Skip to content

Commit 65d0b84

Browse files
committed
Rebase onto master
1 parent e77dcf0 commit 65d0b84

File tree

14 files changed

+400
-16
lines changed

14 files changed

+400
-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: 33 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.CountDownLatch
@@ -92,6 +95,7 @@ object CodeGenerationController {
9295
val allTestPackages = getPackageDirectories(baseTestDirectory)
9396
val latch = CountDownLatch(classesWithTests.size)
9497
val testFilesPointers = mutableListOf<SmartPsiElementPointer<PsiFile>>()
98+
val srcClassPathToSarifReport = mutableMapOf<Path, Sarif>()
9599
val utilClassListener = UtilClassListener()
96100
for ((srcClass, generateResult) in classesWithTests) {
97101
val (count, testSetsId) = generateResult
@@ -104,7 +108,7 @@ object CodeGenerationController {
104108
val cut = psi2KClass[srcClass] ?: error("Didn't find KClass instance for class ${srcClass.name}")
105109
runWriteCommandAction(model.project, "Generate tests with UtBot", null, {
106110
try {
107-
generateCodeAndReport(proc, testSetsId, srcClass, cut, testClass, testFilePointer, model, latch, utilClassListener)
111+
generateCodeAndReport(proc, testSetsId, srcClass, cut, testClass, testFilePointer, srcClassPathToSarifReport, model, latch, utilClassListener)
108112
testFilesPointers.add(testFilePointer)
109113
} catch (e: IncorrectOperationException) {
110114
logger.error { e }
@@ -131,6 +135,7 @@ object CodeGenerationController {
131135
if (model.runGeneratedTestsWithCoverage) {
132136
RunConfigurationHelper.runTestsWithCoverage(model, testFilesPointers)
133137
}
138+
runInspectionsIfNeeded(model.project, srcClassPathToSarifReport)
134139
proc.forceTermination()
135140
}
136141
}
@@ -140,6 +145,25 @@ object CodeGenerationController {
140145
}
141146
}
142147

148+
/**
149+
* Runs the UTBot inspection if there are detected errors.
150+
*/
151+
private fun runInspectionsIfNeeded(
152+
project: Project,
153+
srcClassPathToSarifReport: MutableMap<Path, Sarif>
154+
) {
155+
val sarifHasResults = srcClassPathToSarifReport.any { (_, sarif) ->
156+
sarif.getAllResults().isNotEmpty()
157+
}
158+
if (!sarifHasResults) {
159+
return
160+
}
161+
UTBotInspectionManager
162+
.getInstance(project, srcClassPathToSarifReport)
163+
.createNewGlobalContext()
164+
.doInspections(AnalysisScope(project))
165+
}
166+
143167
private fun proceedTestReport(proc: EngineProcess, model: GenerateTestsModel) {
144168
try {
145169
// Parametrized tests are not supported in tests report yet
@@ -557,6 +581,7 @@ object CodeGenerationController {
557581
classUnderTest: ClassId,
558582
testClass: PsiClass,
559583
filePointer: SmartPsiElementPointer<PsiFile>,
584+
srcClassPathToSarifReport: MutableMap<Path, Sarif>,
560585
model: GenerateTestsModel,
561586
reportsCountDown: CountDownLatch,
562587
utilClassListener: UtilClassListener
@@ -614,14 +639,17 @@ object CodeGenerationController {
614639
val file = filePointer.containingFile
615640

616641
run(THREAD_POOL) {
617-
saveSarifReport(
642+
val sarifReport = saveSarifReport(
618643
proc,
619644
testSetsId,
620645
testClassUpdated,
621646
classUnderTest,
622647
model,
623648
file?.text ?: generatedTestsCode
624649
)
650+
val srcClassPath = srcClass.containingFile.virtualFile.toNioPath()
651+
srcClassPathToSarifReport[srcClassPath] = sarifReport
652+
625653
reportsCountDown.countDown()
626654
}
627655
}
@@ -657,10 +685,10 @@ object CodeGenerationController {
657685
testClassId: ClassId,
658686
model: GenerateTestsModel,
659687
generatedTestsCode: String,
660-
) {
688+
): Sarif {
661689
val project = model.project
662690

663-
try {
691+
return try {
664692
// saving sarif report
665693
SarifReportIdea.createAndSave(proc, testSetsId, testClassId, model, generatedTestsCode, testClass)
666694
} catch (e: Exception) {
@@ -670,6 +698,7 @@ object CodeGenerationController {
670698
message = "Cannot save Sarif report via generated tests: error occurred '${e.message}'",
671699
title = "Failed to save Sarif report"
672700
)
701+
Sarif.empty()
673702
}
674703
}
675704

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)