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