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