3
3
4
4
package software.aws.toolkits.jetbrains.services.codewhisperer.util
5
5
6
+ import com.intellij.codeInsight.daemon.impl.HighlightInfo
6
7
import com.intellij.codeInsight.lookup.LookupManager
7
8
import com.intellij.ide.BrowserUtil
9
+ import com.intellij.lang.annotation.HighlightSeverity
8
10
import com.intellij.notification.NotificationAction
9
11
import com.intellij.openapi.application.ApplicationManager
10
12
import com.intellij.openapi.application.runInEdt
13
+ import com.intellij.openapi.editor.Document
11
14
import com.intellij.openapi.editor.Editor
15
+ import com.intellij.openapi.editor.impl.DocumentMarkupModel
12
16
import com.intellij.openapi.editor.impl.EditorImpl
13
17
import com.intellij.openapi.project.Project
14
18
import com.intellij.openapi.vfs.VfsUtil
@@ -21,7 +25,10 @@ import kotlinx.coroutines.Job
21
25
import kotlinx.coroutines.delay
22
26
import kotlinx.coroutines.launch
23
27
import kotlinx.coroutines.yield
28
+ import software.amazon.awssdk.services.codewhispererruntime.model.IdeDiagnostic
24
29
import 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
25
32
import software.aws.toolkits.core.utils.getLogger
26
33
import software.aws.toolkits.core.utils.warn
27
34
import software.aws.toolkits.jetbrains.core.credentials.AwsBearerTokenConnection
@@ -347,3 +354,88 @@ object CodeWhispererUtil {
347
354
enum class CaretMovement {
348
355
NO_CHANGE , MOVE_FORWARD , MOVE_BACKWARD
349
356
}
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