@@ -10,9 +10,13 @@ import com.google.gson.Gson
10
10
import com.intellij.ide.BrowserUtil
11
11
import com.intellij.ide.util.RunOnceUtil
12
12
import com.intellij.openapi.application.runInEdt
13
+ import com.intellij.openapi.application.runReadAction
14
+ import com.intellij.openapi.fileEditor.FileDocumentManager
13
15
import com.intellij.openapi.fileEditor.FileEditorManager
14
16
import com.intellij.openapi.options.ShowSettingsUtil
15
17
import com.intellij.openapi.project.Project
18
+ import com.intellij.openapi.vfs.LocalFileSystem
19
+ import com.intellij.openapi.vfs.VirtualFile
16
20
import com.intellij.ui.jcef.JBCefJSQuery.Response
17
21
import kotlinx.coroutines.CancellationException
18
22
import kotlinx.coroutines.CompletableDeferred
@@ -71,6 +75,8 @@ import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_
71
75
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_TAB_BAR_ACTIONS
72
76
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_TAB_CHANGE
73
77
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_TAB_REMOVE
78
+ import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CODE_REVIEW_FINDINGS_SUFFIX
79
+ import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.DISPLAY_FINDINGS_SUFFIX
74
80
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.EncryptedChatParams
75
81
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.EncryptedQuickActionChatParams
76
82
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.GET_SERIALIZED_CHAT_REQUEST_METHOD
@@ -107,13 +113,23 @@ import software.aws.toolkits.jetbrains.services.amazonqCodeTest.auth.isCodeTestA
107
113
import software.aws.toolkits.jetbrains.services.amazonqDoc.auth.isDocAvailable
108
114
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.auth.isFeatureDevAvailable
109
115
import software.aws.toolkits.jetbrains.services.codemodernizer.utils.isCodeTransformAvailable
116
+ import software.aws.toolkits.jetbrains.services.codewhisperer.codescan.CodeLine
117
+ import software.aws.toolkits.jetbrains.services.codewhisperer.codescan.CodeWhispererCodeScanIssue
118
+ import software.aws.toolkits.jetbrains.services.codewhisperer.codescan.CodeWhispererCodeScanManager
119
+ import software.aws.toolkits.jetbrains.services.codewhisperer.codescan.CodeWhispererCodeScanSession
120
+ import software.aws.toolkits.jetbrains.services.codewhisperer.codescan.Description
121
+ import software.aws.toolkits.jetbrains.services.codewhisperer.codescan.Recommendation
122
+ import software.aws.toolkits.jetbrains.services.codewhisperer.codescan.SuggestedFix
110
123
import software.aws.toolkits.jetbrains.services.codewhisperer.settings.CodeWhispererConfigurable
124
+ import software.aws.toolkits.jetbrains.services.codewhisperer.util.CodeWhispererConstants
111
125
import software.aws.toolkits.jetbrains.settings.MeetQSettings
112
126
import software.aws.toolkits.telemetry.MetricResult
113
127
import software.aws.toolkits.telemetry.Telemetry
128
+ import java.nio.file.Path
114
129
import java.util.concurrent.CompletableFuture
115
130
import java.util.concurrent.CompletionException
116
131
import java.util.function.Function
132
+ import kotlin.collections.get
117
133
118
134
class BrowserConnector (
119
135
private val serializer : MessageSerializer = MessageSerializer .getInstance(),
@@ -122,6 +138,7 @@ class BrowserConnector(
122
138
) {
123
139
val uiReady = CompletableDeferred <Boolean >()
124
140
private val chatCommunicationManager = ChatCommunicationManager .getInstance(project)
141
+ private val codeScanManager = CodeWhispererCodeScanManager .getInstance(project)
125
142
126
143
suspend fun connect (
127
144
browser : Browser ,
@@ -568,6 +585,33 @@ class BrowserConnector(
568
585
}
569
586
}
570
587
588
+ data class flareCodeScanIssue (
589
+ val startLine : Int ,
590
+ val endLine : Int ,
591
+ val comment : String? ,
592
+ val title : String ,
593
+ val description : Description ,
594
+ val detectorId : String ,
595
+ val detectorName : String ,
596
+ val findingId : String ,
597
+ val ruleId : String? ,
598
+ val relatedVulnerabilities : List <String >,
599
+ val severity : String ,
600
+ val recommendation : Recommendation ,
601
+ val suggestedFixes : List <SuggestedFix >,
602
+ val scanJobId : String ,
603
+ val language : String ,
604
+ val autoDetected : Boolean ,
605
+ val filePath : String ,
606
+ val findingContext : String
607
+
608
+ )
609
+
610
+ data class AggregatedCodeScanIssue (
611
+ val filePath : String ,
612
+ val issues : List <flareCodeScanIssue>
613
+ )
614
+
571
615
private fun showResult (
572
616
result : CompletableFuture <String >,
573
617
partialResultToken : String ,
@@ -581,10 +625,74 @@ class BrowserConnector(
581
625
throw error
582
626
}
583
627
chatCommunicationManager.removePartialChatMessage(partialResultToken)
628
+ val params = value?.let { encryptionManager?.decrypt(it) }.orEmpty()
629
+ val jsonObject = Gson ().fromJson(params, Map ::class .java)
630
+ val additionalMessages = jsonObject[" additionalMessages" ] as ? MutableList <Map <String , Any >>
631
+ val findingsMessage = additionalMessages?.find {message ->
632
+ (message[" messageId" ] as String ).endsWith(CODE_REVIEW_FINDINGS_SUFFIX )
633
+ || (message[" messageId" ] as String ).endsWith(DISPLAY_FINDINGS_SUFFIX )}
634
+ val scannedFiles = mutableListOf<VirtualFile >();
635
+ if (findingsMessage != null ) {
636
+ additionalMessages.remove(findingsMessage)
637
+ val gson = Gson ()
638
+ val jsonFindings = gson.fromJson(findingsMessage[" body" ] as String , List ::class .java)
639
+ val mappedFindings = mutableListOf<CodeWhispererCodeScanIssue >()
640
+ for (aggregatedIssueUnformatted in jsonFindings) {
641
+ val aggregatedIssue = gson.fromJson(gson.toJson(aggregatedIssueUnformatted), AggregatedCodeScanIssue ::class .java)
642
+ val file = try {
643
+ LocalFileSystem .getInstance().findFileByIoFile(
644
+ Path .of(aggregatedIssue.filePath).toFile()
645
+ )
646
+ } catch (e: Exception ) {
647
+ null
648
+ }
649
+ if (file?.isDirectory == false ) {
650
+ scannedFiles.add(file)
651
+ runReadAction {
652
+ FileDocumentManager .getInstance().getDocument(file)
653
+ }?.let { document ->
654
+ for (issue in aggregatedIssue.issues) {
655
+ val endLineInDocument = minOf(maxOf(0 , issue.endLine - 1 ), document.lineCount - 1 )
656
+ val endCol = document.getLineEndOffset(endLineInDocument) - document.getLineStartOffset(endLineInDocument) + 1
657
+ val isIssueIgnored = codeScanManager.isIgnoredIssue(issue.title, document, file, issue.startLine - 1 )
658
+ if (isIssueIgnored) {
659
+ continue
660
+ }
661
+ mappedFindings.add(CodeWhispererCodeScanIssue (
662
+ startLine = issue.startLine,
663
+ startCol = 1 ,
664
+ endLine = issue.endLine,
665
+ endCol = endCol,
666
+ file = file,
667
+ project = project,
668
+ title = issue.title,
669
+ description = issue.description,
670
+ detectorId = issue.detectorId,
671
+ detectorName = issue.detectorName,
672
+ findingId = issue.findingId,
673
+ ruleId = issue.ruleId,
674
+ relatedVulnerabilities = issue.relatedVulnerabilities,
675
+ severity = issue.severity,
676
+ recommendation = issue.recommendation,
677
+ suggestedFixes = issue.suggestedFixes,
678
+ codeSnippet = emptyList(),
679
+ isVisible = true ,
680
+ autoDetected = issue.autoDetected,
681
+ scanJobId = issue.scanJobId
682
+ ))
683
+ }
684
+ }
685
+ }
686
+ }
687
+
688
+ codeScanManager.addOnDemandIssues(mappedFindings, scannedFiles, CodeWhispererConstants .CodeAnalysisScope .AGENTIC )
689
+ codeScanManager.showCodeScanUI()
690
+ }
691
+
584
692
val messageToChat = ChatCommunicationManager .convertToJsonToSendToChat(
585
693
SEND_CHAT_COMMAND_PROMPT ,
586
694
tabId,
587
- value?. let { encryptionManager?.decrypt(it) }.orEmpty( ),
695
+ Gson ().toJson(jsonObject ),
588
696
isPartialResult = false
589
697
)
590
698
browser.postChat(messageToChat)
0 commit comments