Skip to content

Commit 703c523

Browse files
committed
Rebase onto master
1 parent 40cedc6 commit 703c523

File tree

14 files changed

+402
-16
lines changed

14 files changed

+402
-16
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,4 @@ target/
77
.idea/
88
.gradle/
99
*.log
10-
*.rdgen
10+
*.rdgen

utbot-framework/src/main/kotlin/org/utbot/framework/process/EngineMain.kt

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -176,13 +176,13 @@ private fun EngineProcessModel.setup(
176176
synchronizer.measureExecutionForTermination(writeSarifReport) { params ->
177177
val reportFilePath = Paths.get(params.reportFilePath)
178178
reportFilePath.parent.toFile().mkdirs()
179-
reportFilePath.toFile().writeText(
180-
SarifReport(
181-
testSets[params.testSetsId]!!,
182-
params.generatedTestsCode,
183-
RdSourceFindingStrategyFacade(realProtocol.rdSourceFindingStrategy)
184-
).createReport().toJson()
185-
)
179+
val sarifReport = SarifReport(
180+
testSets[params.testSetsId]!!,
181+
params.generatedTestsCode,
182+
RdSourceFindingStrategyFacade(realProtocol.rdSourceFindingStrategy)
183+
).createReport().toJson()
184+
reportFilePath.toFile().writeText(sarifReport)
185+
sarifReport
186186
}
187187
synchronizer.measureExecutionForTermination(generateTestReport) { params ->
188188
val eventLogMessage = params.eventLogMessage

utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/generator/CodeGenerationController.kt

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package org.utbot.intellij.plugin.generator
22

3+
import com.intellij.analysis.AnalysisScope
34
import com.intellij.codeInsight.CodeInsightUtil
45
import com.intellij.codeInsight.FileModificationService
56
import com.intellij.ide.fileTemplates.FileTemplateManager
@@ -51,6 +52,7 @@ import org.utbot.framework.codegen.model.UtilClassKind
5152
import org.utbot.framework.codegen.model.UtilClassKind.Companion.UT_UTILS_CLASS_NAME
5253
import org.utbot.framework.plugin.api.ClassId
5354
import org.utbot.framework.plugin.api.CodegenLanguage
55+
import org.utbot.intellij.plugin.inspection.UTBotInspectionManager
5456
import org.utbot.intellij.plugin.models.GenerateTestsModel
5557
import org.utbot.intellij.plugin.models.packageName
5658
import org.utbot.intellij.plugin.process.EngineProcess
@@ -65,6 +67,7 @@ import org.utbot.intellij.plugin.util.IntelliJApiHelper.Target.*
6567
import org.utbot.intellij.plugin.util.IntelliJApiHelper.run
6668
import org.utbot.intellij.plugin.util.RunConfigurationHelper
6769
import org.utbot.intellij.plugin.util.extractClassMethodsIncludingNested
70+
import org.utbot.sarif.Sarif
6871
import org.utbot.sarif.SarifReport
6972
import java.nio.file.Path
7073
import java.util.concurrent.CancellationException
@@ -94,6 +97,7 @@ object CodeGenerationController {
9497
val allTestPackages = getPackageDirectories(baseTestDirectory)
9598
val latch = CountDownLatch(classesWithTests.size)
9699
val testFilesPointers = mutableListOf<SmartPsiElementPointer<PsiFile>>()
100+
val srcClassPathToSarifReport = mutableMapOf<Path, Sarif>()
97101
val utilClassListener = UtilClassListener()
98102
var index = 0
99103
for ((srcClass, generateResult) in classesWithTests) {
@@ -119,6 +123,7 @@ object CodeGenerationController {
119123
cut,
120124
testClass,
121125
testFilePointer,
126+
srcClassPathToSarifReport,
122127
model,
123128
latch,
124129
utilClassListener,
@@ -151,6 +156,7 @@ object CodeGenerationController {
151156
UtTestsDialogProcessor.updateIndicator(indicator, UtTestsDialogProcessor.ProgressRange.SARIF, "Start tests with coverage", 0.95)
152157
RunConfigurationHelper.runTestsWithCoverage(model, testFilesPointers)
153158
}
159+
runInspectionsIfNeeded(model.project, srcClassPathToSarifReport) // TODO
154160
proc.forceTermination()
155161
UtTestsDialogProcessor.updateIndicator(indicator, UtTestsDialogProcessor.ProgressRange.SARIF, "Start tests with coverage", 1.0)
156162
}
@@ -161,6 +167,25 @@ object CodeGenerationController {
161167
}
162168
}
163169

170+
/**
171+
* Runs the UTBot inspection if there are detected errors.
172+
*/
173+
private fun runInspectionsIfNeeded(
174+
project: Project,
175+
srcClassPathToSarifReport: MutableMap<Path, Sarif>
176+
) {
177+
val sarifHasResults = srcClassPathToSarifReport.any { (_, sarif) ->
178+
sarif.getAllResults().isNotEmpty()
179+
}
180+
if (!sarifHasResults) {
181+
return
182+
}
183+
UTBotInspectionManager
184+
.getInstance(project, srcClassPathToSarifReport)
185+
.createNewGlobalContext()
186+
.doInspections(AnalysisScope(project))
187+
}
188+
164189
private fun proceedTestReport(proc: EngineProcess, model: GenerateTestsModel) {
165190
try {
166191
// Parametrized tests are not supported in tests report yet
@@ -583,6 +608,7 @@ object CodeGenerationController {
583608
classUnderTest: ClassId,
584609
testClass: PsiClass,
585610
filePointer: SmartPsiElementPointer<PsiFile>,
611+
srcClassPathToSarifReport: MutableMap<Path, Sarif>,
586612
model: GenerateTestsModel,
587613
reportsCountDown: CountDownLatch,
588614
utilClassListener: UtilClassListener,
@@ -661,7 +687,7 @@ object CodeGenerationController {
661687
// uploading formatted code
662688
val file = filePointer.containingFile
663689

664-
saveSarifReport(
690+
val sarifReport = saveSarifReport(
665691
proc,
666692
testSetsId,
667693
testClassUpdated,
@@ -671,6 +697,9 @@ object CodeGenerationController {
671697
file?.text ?: generatedTestsCode,
672698
indicator
673699
)
700+
val srcClassPath = srcClass.containingFile.virtualFile.toNioPath()
701+
srcClassPathToSarifReport[srcClassPath] = sarifReport
702+
674703
unblockDocument(testClassUpdated.project, editor.document)
675704
}
676705
}
@@ -707,19 +736,20 @@ object CodeGenerationController {
707736
reportsCountDown: CountDownLatch,
708737
generatedTestsCode: String,
709738
indicator: ProgressIndicator
710-
) {
739+
): Sarif {
711740
val project = model.project
712741

713-
try {
742+
return try {
714743
// saving sarif report
715-
SarifReportIdea.createAndSave(proc, testSetsId, testClassId, model, generatedTestsCode, testClass, reportsCountDown, indicator)
744+
SarifReportIdea.createAndSave(proc, testSetsId, testClassId, model, generatedTestsCode, testClass, reportsCountDown, indicator)
716745
} catch (e: Exception) {
717746
logger.error(e) { "error in saving sarif report"}
718747
showErrorDialogLater(
719748
project,
720749
message = "Cannot save Sarif report via generated tests: error occurred '${e.message}'",
721750
title = "Failed to save Sarif report"
722751
)
752+
Sarif.empty()
723753
}
724754
}
725755

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package org.utbot.intellij.plugin.inspection
2+
3+
import com.intellij.codeInspection.LocalQuickFix
4+
import com.intellij.codeInspection.ProblemDescriptor
5+
import com.intellij.icons.AllIcons
6+
import com.intellij.openapi.application.ApplicationManager
7+
import com.intellij.openapi.project.Project
8+
import com.intellij.unscramble.AnalyzeStacktraceUtil
9+
10+
/**
11+
* Button that launches the built-in "Analyze Stack Trace" action. Displayed as a quick fix.
12+
*
13+
* @param exceptionMessage short description of the detected exception.
14+
* @param stackTraceLines list of strings of the form "className.methodName(fileName:lineNumber)".
15+
*/
16+
class AnalyzeStackTraceFix(
17+
private val exceptionMessage: String,
18+
private val stackTraceLines: List<String>
19+
) : LocalQuickFix {
20+
21+
/**
22+
* Without `invokeLater` the [com.intellij.execution.impl.ConsoleViewImpl.myPredefinedFilters] will not be filled.
23+
*
24+
* See [com.intellij.execution.impl.ConsoleViewImpl.createCompositeFilter] for more details.
25+
*/
26+
override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
27+
val stackTraceContent = stackTraceLines.joinToString("\n") { "at $it" }
28+
ApplicationManager.getApplication().invokeLater {
29+
AnalyzeStacktraceUtil.addConsole(
30+
/* project = */ project,
31+
/* consoleFactory = */ null,
32+
/* tabTitle = */ "StackTrace",
33+
/* text = */ "$exceptionMessage\n\n$stackTraceContent",
34+
/* icon = */ AllIcons.Actions.Lightning
35+
)
36+
}
37+
}
38+
39+
/**
40+
* This text is displayed on the quick fix button.
41+
*/
42+
override fun getName() = "Analyze stack trace"
43+
44+
override fun getFamilyName() = name
45+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package org.utbot.intellij.plugin.inspection
2+
3+
import com.intellij.codeInspection.ex.*
4+
import com.intellij.codeInspection.ui.InspectionToolPresentation
5+
import com.intellij.openapi.project.Project
6+
import com.intellij.openapi.util.NotNullLazyValue
7+
import com.intellij.ui.content.ContentManager
8+
import org.utbot.sarif.Sarif
9+
import java.nio.file.Path
10+
import java.util.concurrent.ConcurrentHashMap
11+
import java.util.concurrent.ConcurrentMap
12+
13+
/**
14+
* Overrides some methods of [GlobalInspectionContextImpl] to satisfy the logic of [UTBotInspectionTool].
15+
*/
16+
class UTBotInspectionContext(
17+
project: Project,
18+
contentManager: NotNullLazyValue<out ContentManager>,
19+
val srcClassPathToSarifReport: MutableMap<Path, Sarif>
20+
) : GlobalInspectionContextImpl(project, contentManager) {
21+
22+
/**
23+
* See [GlobalInspectionContextImpl.myPresentationMap] for more details.
24+
*/
25+
private val myPresentationMap: ConcurrentMap<InspectionToolWrapper<*, *>, InspectionToolPresentation> =
26+
ConcurrentHashMap()
27+
28+
private val globalInspectionToolWrapper by lazy {
29+
val utbotInspectionTool = UTBotInspectionTool.getInstance(srcClassPathToSarifReport)
30+
GlobalInspectionToolWrapper(utbotInspectionTool).also {
31+
it.initialize(/* context = */ this)
32+
}
33+
}
34+
35+
/**
36+
* Returns [InspectionProfileImpl] with only one inspection tool - [UTBotInspectionTool].
37+
*/
38+
override fun getCurrentProfile(): InspectionProfileImpl {
39+
val supplier = InspectionToolsSupplier.Simple(listOf(globalInspectionToolWrapper))
40+
return InspectionProfileImpl("UTBotInspectionToolProfile", supplier, BASE_PROFILE)
41+
}
42+
43+
override fun close(noSuspiciousCodeFound: Boolean) {
44+
myPresentationMap.clear()
45+
super.close(noSuspiciousCodeFound)
46+
}
47+
48+
override fun cleanup() {
49+
myPresentationMap.clear()
50+
super.cleanup()
51+
}
52+
53+
/**
54+
* Overriding is needed to provide [UTBotInspectionToolPresentation]
55+
* instead of the standard implementation of the [InspectionToolPresentation].
56+
*/
57+
override fun getPresentation(toolWrapper: InspectionToolWrapper<*, *>): InspectionToolPresentation {
58+
return myPresentationMap.computeIfAbsent(toolWrapper) {
59+
UTBotInspectionToolPresentation(globalInspectionToolWrapper, context = this)
60+
}
61+
}
62+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package org.utbot.intellij.plugin.inspection
2+
3+
import com.intellij.codeInspection.ex.GlobalInspectionContextImpl
4+
import com.intellij.codeInspection.ex.InspectionManagerEx
5+
import com.intellij.openapi.project.Project
6+
import com.intellij.openapi.util.NotNullLazyValue
7+
import com.intellij.ui.content.ContentManager
8+
import org.utbot.sarif.Sarif
9+
import java.nio.file.Path
10+
11+
/**
12+
* Overrides some methods of [InspectionManagerEx] to satisfy the logic of [UTBotInspectionTool].
13+
*/
14+
class UTBotInspectionManager(project: Project) : InspectionManagerEx(project) {
15+
16+
private var srcClassPathToSarifReport: MutableMap<Path, Sarif> = mutableMapOf()
17+
18+
companion object {
19+
fun getInstance(project: Project, srcClassPathToSarifReport: MutableMap<Path, Sarif>) =
20+
UTBotInspectionManager(project).also {
21+
it.srcClassPathToSarifReport = srcClassPathToSarifReport
22+
}
23+
}
24+
25+
/**
26+
* See [InspectionManagerEx.myContentManager] for more details.
27+
*/
28+
private val myContentManager: NotNullLazyValue<ContentManager> by lazy {
29+
NotNullLazyValue.createValue {
30+
getProblemsViewContentManager(project)
31+
}
32+
}
33+
34+
/**
35+
* Overriding is needed to provide [UTBotInspectionContext] instead of [GlobalInspectionContextImpl].
36+
*/
37+
override fun createNewGlobalContext(): GlobalInspectionContextImpl =
38+
UTBotInspectionContext(project, myContentManager, srcClassPathToSarifReport)
39+
}

0 commit comments

Comments
 (0)