33
44package software.aws.toolkits.jetbrains.services.codewhisperer.util
55
6+ import com.intellij.codeInsight.daemon.impl.HighlightInfo
67import com.intellij.codeInsight.lookup.LookupManager
78import com.intellij.ide.BrowserUtil
9+ import com.intellij.lang.annotation.HighlightSeverity
810import com.intellij.notification.NotificationAction
911import com.intellij.openapi.application.ApplicationManager
1012import com.intellij.openapi.application.runInEdt
13+ import com.intellij.openapi.editor.Document
1114import com.intellij.openapi.editor.Editor
15+ import com.intellij.openapi.editor.impl.DocumentMarkupModel
1216import com.intellij.openapi.editor.impl.EditorImpl
1317import com.intellij.openapi.project.Project
1418import com.intellij.openapi.vfs.VfsUtil
@@ -21,7 +25,10 @@ import kotlinx.coroutines.Job
2125import kotlinx.coroutines.delay
2226import kotlinx.coroutines.launch
2327import kotlinx.coroutines.yield
28+ import software.amazon.awssdk.services.codewhispererruntime.model.IdeDiagnostic
2429import software.amazon.awssdk.services.codewhispererruntime.model.OptOutPreference
30+ import software.amazon.awssdk.services.codewhispererruntime.model.Position
31+ import software.amazon.awssdk.services.codewhispererruntime.model.Range
2532import software.aws.toolkits.core.utils.getLogger
2633import software.aws.toolkits.core.utils.warn
2734import software.aws.toolkits.jetbrains.core.credentials.AwsBearerTokenConnection
@@ -347,3 +354,88 @@ object CodeWhispererUtil {
347354enum class CaretMovement {
348355 NO_CHANGE , MOVE_FORWARD , MOVE_BACKWARD
349356}
357+
358+ fun getDiagnosticsType (message : String ): String {
359+ val lowercaseMessage = message.lowercase()
360+
361+ val diagnosticPatterns = mapOf (
362+ " TYPE_ERROR" to listOf (" type" , " cast" ),
363+ " SYNTAX_ERROR" to listOf (" expected" , " indent" , " syntax" ),
364+ " REFERENCE_ERROR" to listOf (" undefined" , " not defined" , " undeclared" , " reference" , " symbol" ),
365+ " BEST_PRACTICE" to listOf (" deprecated" , " unused" , " uninitialized" , " not initialized" ),
366+ " SECURITY" to listOf (" security" , " vulnerability" )
367+ )
368+
369+ return diagnosticPatterns
370+ .entries
371+ .firstOrNull { (_, keywords) ->
372+ keywords.any { lowercaseMessage.contains(it) }
373+ }
374+ ?.key ? : " OTHER"
375+ }
376+
377+ fun convertSeverity (severity : HighlightSeverity ): String = when {
378+ severity == HighlightSeverity .ERROR -> " ERROR"
379+ severity == HighlightSeverity .WARNING ||
380+ severity == HighlightSeverity .WEAK_WARNING -> " WARNING"
381+ severity == HighlightSeverity .INFORMATION -> " INFORMATION"
382+ severity.toString().contains(" TEXT" , ignoreCase = true ) -> " HINT"
383+ severity == HighlightSeverity .INFO -> " INFORMATION"
384+ // For severities that might indicate performance issues
385+ severity.toString().contains(" PERFORMANCE" , ignoreCase = true ) -> " WARNING"
386+ // For deprecation warnings
387+ severity.toString().contains(" DEPRECATED" , ignoreCase = true ) -> " WARNING"
388+ // Default case
389+ else -> " INFORMATION"
390+ }
391+
392+ fun getDocumentDiagnostics (document : Document , project : Project ): List <IdeDiagnostic > = runCatching {
393+ DocumentMarkupModel .forDocument(document, project, true )
394+ .allHighlighters
395+ .mapNotNull { it.errorStripeTooltip as ? HighlightInfo }
396+ .filter { ! it.description.isNullOrEmpty() }
397+ .map { info ->
398+ val startLine = document.getLineNumber(info.startOffset)
399+ val endLine = document.getLineNumber(info.endOffset)
400+
401+ IdeDiagnostic .builder()
402+ .ideDiagnosticType(getDiagnosticsType(info.description))
403+ .severity(convertSeverity(info.severity))
404+ .source(info.inspectionToolId)
405+ .range(
406+ Range .builder()
407+ .start(
408+ Position .builder()
409+ .line(startLine)
410+ .character(document.getLineStartOffset(startLine))
411+ .build()
412+ )
413+ .end(
414+ Position .builder()
415+ .line(endLine)
416+ .character(document.getLineStartOffset(endLine))
417+ .build()
418+ )
419+ .build()
420+ )
421+ .build()
422+ }
423+ }.getOrElse { e ->
424+ getLogger<CodeWhispererUtil >().warn { " Failed to get document diagnostics ${e.message} " }
425+ emptyList()
426+ }
427+
428+ data class DiagnosticDifferences (
429+ val added : List <IdeDiagnostic >,
430+ val removed : List <IdeDiagnostic >,
431+ )
432+
433+ fun serializeDiagnostics (diagnostic : IdeDiagnostic ): String = " ${diagnostic.source()} -${diagnostic.severity()} -${diagnostic.ideDiagnosticType()} "
434+
435+ fun getDiagnosticDifferences (oldDiagnostic : List <IdeDiagnostic >, newDiagnostic : List <IdeDiagnostic >): DiagnosticDifferences {
436+ val oldSet = oldDiagnostic.map { i -> serializeDiagnostics(i) }.toSet()
437+ val newSet = newDiagnostic.map { i -> serializeDiagnostics(i) }.toSet()
438+ val added = newDiagnostic.filter { i -> ! oldSet.contains(serializeDiagnostics(i)) }.distinctBy { serializeDiagnostics(it) }
439+ val removed = oldDiagnostic.filter { i -> ! newSet.contains(serializeDiagnostics(i)) }.distinctBy { serializeDiagnostics(it) }
440+ return DiagnosticDifferences (added, removed)
441+ }
0 commit comments