Skip to content

Commit 02c2101

Browse files
Vassiliy-Kudryashovdenis-fokin
authored andcommitted
IDEA intention actions could help us with readability of generated code #158 (#615)
1 parent f249d28 commit 02c2101

File tree

2 files changed

+114
-20
lines changed

2 files changed

+114
-20
lines changed

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

+25-20
Original file line numberDiff line numberDiff line change
@@ -301,28 +301,33 @@ object CodeGenerationController {
301301

302302
// reformatting before creating reports due to
303303
// SarifReport requires the final version of the generated tests code
304-
runWriteCommandAction(testClassUpdated.project, "UtBot tests reformatting", null, {
305-
reformat(model, file, testClassUpdated)
306-
})
307-
unblockDocument(testClassUpdated.project, editor.document)
308-
309-
// uploading formatted code
310-
val testsCodeWithTestReportFormatted =
311-
testsCodeWithTestReport.copy(generatedCode = file.text)
312-
313-
// creating and saving reports
314-
reports += testsCodeWithTestReportFormatted.testsGenerationReport
315-
316-
saveSarifReport(
317-
testClassUpdated,
318-
testSets,
319-
model,
320-
testsCodeWithTestReportFormatted,
321-
)
304+
run(THREAD_POOL) {
305+
IntentionHelper(model.project, editor, file).applyIntentions()
306+
run(EDT_LATER) {
307+
runWriteCommandAction(testClassUpdated.project, "UtBot tests reformatting", null, {
308+
reformat(model, file, testClassUpdated)
309+
})
310+
unblockDocument(testClassUpdated.project, editor.document)
311+
312+
// uploading formatted code
313+
val testsCodeWithTestReportFormatted =
314+
testsCodeWithTestReport.copy(generatedCode = file.text)
315+
316+
// creating and saving reports
317+
reports += testsCodeWithTestReportFormatted.testsGenerationReport
318+
319+
saveSarifReport(
320+
testClassUpdated,
321+
testSets,
322+
model,
323+
testsCodeWithTestReportFormatted,
324+
)
322325

323-
reportsCountDown.countDown()
326+
reportsCountDown.countDown()
324327

325-
unblockDocument(testClassUpdated.project, editor.document)
328+
unblockDocument(testClassUpdated.project, editor.document)
329+
}
330+
}
326331
}
327332
}
328333
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
package org.utbot.intellij.plugin.generator
2+
3+
import com.intellij.codeInsight.daemon.impl.DaemonCodeAnalyzerEx
4+
import com.intellij.codeInsight.daemon.impl.DaemonProgressIndicator
5+
import com.intellij.codeInsight.daemon.impl.HighlightInfo
6+
import com.intellij.codeInsight.intention.IntentionAction
7+
import com.intellij.openapi.command.WriteCommandAction
8+
import com.intellij.openapi.editor.Editor
9+
import com.intellij.openapi.progress.ProgressManager
10+
import com.intellij.openapi.project.DumbService
11+
import com.intellij.openapi.project.Project
12+
import com.intellij.openapi.util.Computable
13+
import com.intellij.openapi.util.Disposer
14+
import com.intellij.openapi.util.TextRange
15+
import com.intellij.psi.PsiFile
16+
17+
class IntentionHelper(val project: Project, private val editor: Editor, private val testFile: PsiFile) {
18+
fun applyIntentions() {
19+
while (true) {
20+
val actions =
21+
DumbService.getInstance(project).runReadActionInSmartMode(Computable<Map<IntentionAction, String>> {
22+
val daemonProgressIndicator = DaemonProgressIndicator()
23+
Disposer.register(project, daemonProgressIndicator)//check it
24+
val list = ProgressManager.getInstance().runProcess(Computable<List<HighlightInfo>> {
25+
try {
26+
DaemonCodeAnalyzerEx.getInstanceEx(project).runMainPasses(
27+
testFile,
28+
editor.document,
29+
daemonProgressIndicator
30+
)
31+
} catch (e: Exception) {
32+
emptyList()// 'Cannot obtain read-action' rare case
33+
}
34+
}, daemonProgressIndicator)
35+
val actions = mutableMapOf<IntentionAction, String>()
36+
list.forEach { info ->
37+
val quickFixActionRanges = info.quickFixActionRanges
38+
if (!quickFixActionRanges.isNullOrEmpty()) {
39+
val toList =
40+
quickFixActionRanges.map { pair: com.intellij.openapi.util.Pair<HighlightInfo.IntentionActionDescriptor, TextRange> -> pair.first.action }
41+
.toList()
42+
toList.forEach { intentionAction -> actions[intentionAction] = intentionAction.familyName }
43+
}
44+
}
45+
actions
46+
})
47+
if (actions.isEmpty()) break
48+
49+
var someWereApplied = false
50+
actions.forEach {
51+
if (it.value.isApplicable()) {
52+
someWereApplied = true
53+
if (it.key.startInWriteAction()) {
54+
WriteCommandAction.runWriteCommandAction(project) {
55+
editor.document.isInBulkUpdate = true
56+
it.key.invoke(project, editor, testFile)
57+
editor.document.isInBulkUpdate = false
58+
}
59+
} else {
60+
editor.document.isInBulkUpdate = true
61+
it.key.invoke(project, editor, testFile)
62+
editor.document.isInBulkUpdate = false
63+
}
64+
}
65+
}
66+
if (!someWereApplied) break
67+
}
68+
}
69+
70+
private fun String.isApplicable(): Boolean {
71+
if (this.startsWith("Change type of actual to ")) return true
72+
if (this == "Replace 'switch' with 'if'") return true // SetsTest
73+
if (this == "Replace with allMatch()") return true
74+
if (this == "Remove redundant cast(s)") return true // SetsTest
75+
if (this == "Collapse 'catch' blocks") return true // MapsTest
76+
if (this == "Replace lambda with method reference") return true // MockRandomExamplesTest
77+
if (this == "Inline variable") return true // ServiceWithFieldTest
78+
if (this == "Optimize imports") return true
79+
if (this.startsWith("Replace 'if else' with '&&'")) return true
80+
if (this.startsWith("Merge with 'case")) return true // CodegenExampleTest
81+
// if (this.equals("Simplify assertion")) return true // RecursiveTypeTest
82+
// if (this.familyName.startsWith("Try to generify ")) return true
83+
return false
84+
// "Generify File" shows TypeCookDialog to update JavaRefactoringSettings.getInstance() and then call invokeRefactoring
85+
// We may do the same without dialog interaction
86+
// "Collapse into loop" for duplicate lines like collection.add(...) comes from background later
87+
// We may implement it in codegen by ourselves
88+
}
89+
}

0 commit comments

Comments
 (0)