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