@@ -8,38 +8,23 @@ import com.intellij.codeInsight.hints.presentation.InlayPresentation
8
8
import com.intellij.codeInsight.hints.presentation.MouseButton
9
9
import com.intellij.codeInsight.hints.presentation.PresentationFactory
10
10
import com.intellij.ide.util.DefaultPsiElementCellRenderer
11
+ import com.intellij.openapi.editor.BlockInlayPriority
11
12
import com.intellij.openapi.editor.Editor
12
13
import com.intellij.openapi.editor.ex.util.EditorUtil
13
14
import com.intellij.openapi.editor.impl.EditorImpl
14
15
import com.intellij.psi.*
15
- import com.intellij.psi.impl.source.PsiExtensibleClass
16
16
import me.him188.kotlin.jvm.blocking.bridge.JvmBlockingBridge
17
17
import me.him188.kotlin.jvm.blocking.bridge.compiler.backend.ir.RuntimeIntrinsics
18
18
import me.him188.kotlin.jvm.blocking.bridge.ide.line.marker.document
19
19
import me.him188.kotlin.jvm.blocking.bridge.ide.line.marker.getLineNumber
20
- import org.jetbrains.kotlin.asJava.classes.KtLightClass
21
- import org.jetbrains.kotlin.asJava.classes.KtUltraLightClass
22
- import org.jetbrains.kotlin.asJava.classes.KtUltraLightClassForFacade
23
- import org.jetbrains.kotlin.asJava.elements.FakeFileForLightClass
24
- import org.jetbrains.kotlin.asJava.elements.KtLightDeclaration
25
- import org.jetbrains.kotlin.asJava.elements.KtLightMethod
26
- import org.jetbrains.kotlin.psi.KtAnnotationEntry
27
- import org.jetbrains.kotlin.psi.KtClassOrObject
28
- import org.jetbrains.kotlin.psi.KtFile
29
- import org.jetbrains.kotlin.psi.KtObjectDeclaration
20
+ import org.jetbrains.kotlin.psi.*
21
+ import org.jetbrains.kotlin.psi.psiUtil.containingClass
22
+ import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
30
23
import org.jetbrains.kotlin.psi.psiUtil.startOffset
31
- import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKind
32
24
import java.awt.event.MouseEvent
33
25
import javax.swing.JComponent
34
26
import javax.swing.JPanel
35
27
36
- internal val PsiElement .containingKtFile: KtFile ?
37
- get() = (containingFile as ? FakeFileForLightClass )?.ktFile
38
- ? : (this as ? KtLightDeclaration <* , * >)?.kotlinOrigin?.containingKtFile
39
-
40
- internal val PsiMember .containingKtClass: KtClassOrObject ?
41
- get() = (containingClass as ? KtLightClass )?.kotlinOrigin
42
-
43
28
class BridgeInlayHintsCollector :
44
29
InlayHintsProvider <NoSettings >,
45
30
// KotlinAbstractHintsProvider<NoSettings>(),
@@ -48,122 +33,89 @@ class BridgeInlayHintsCollector :
48
33
override fun collect (element : PsiElement , editor : Editor , sink : InlayHintsSink ): Boolean = kotlin.runCatching {
49
34
// wrapped with runCatching in case binary changes. it's better not to provide feature than throwing exceptions
50
35
51
- if (element is KtFile ) {
52
- var anyChanged = false
36
+ if (element !is KtFile ) return false
37
+ if (editor !is EditorImpl ) return false
38
+ if (! element.isBridgeCompilerEnabled) return false
53
39
54
- fun collectClass (clazz : PsiClass ): Boolean {
55
- anyChanged = collect(clazz, editor, sink) || anyChanged
56
- for (inner in clazz.innerClasses) {
57
- anyChanged = collectClass(inner) || anyChanged
58
- }
59
- return anyChanged
60
- }
40
+ var anyChanged = false
41
+ for (clazz in element.ktClassOrObjects()) {
42
+ anyChanged = collectInlayHintsForClass(clazz, editor, sink) || anyChanged
43
+ }
61
44
62
- for (clazz in element.classes) {
63
- collectClass(clazz)
45
+ for (declaration in element.declarations) {
46
+ if (declaration is KtNamedFunction ) {
47
+ anyChanged = collectInlayHintsForFunction(declaration, editor, sink) || anyChanged
64
48
}
65
- return anyChanged
66
49
}
50
+ return anyChanged
51
+ }.getOrElse { false }
67
52
68
- if (element !is KtUltraLightClass && element !is KtUltraLightClassForFacade ) return false
69
- if (element !is PsiExtensibleClass ) return false
70
-
71
- if (editor !is EditorImpl ) return false
72
-
53
+ private fun collectInlayHintsForClass (element : KtClassOrObject , editor : EditorImpl , sink : InlayHintsSink ): Boolean {
73
54
var anyChanged = false
74
- val factory = PresentationFactory (editor)
75
-
76
- if ( ! element.isBridgeCompilerEnabled) return false
55
+ element.ktClassOrObjects().forEach {
56
+ anyChanged = collectInlayHintsForClass(it, editor, sink) || anyChanged
57
+ }
77
58
78
- val generated = mutableSetOf<PsiElement >()
79
-
80
- for (method in element.methods) {
81
- if (method is BlockingBridgeStubMethod ) continue
82
- if (method.containingClass != = element) continue
83
- if (! generated.add(method.navigationElement)) continue
84
-
85
- if (method.canHaveBridgeFunctions().inlayHints) {
86
- anyChanged = true
87
- sink.addBlockElement(
88
- offset = method.identifyingElement?.startOffset ? : method.startOffset,
89
- relatesToPrecedingText = false ,
90
- showAbove = true ,
91
- priority = 1 ,
92
- presentation = createPresentation(factory, method, editor) ? : continue ,
93
- )
94
- }
59
+ for (function in element.declarations.asSequence().filterIsInstance<KtFunction >()) {
60
+ if (function.containingClass() != = element) return false
61
+ anyChanged = collectInlayHintsForFunction(function, editor, sink) || anyChanged
95
62
}
96
63
97
64
return anyChanged
98
- }.getOrElse { false }
65
+ }
66
+
67
+ private fun collectInlayHintsForFunction (
68
+ method : KtFunction ,
69
+ editor : EditorImpl ,
70
+ sink : InlayHintsSink ,
71
+ ): Boolean {
72
+ if (method.canHaveBridgeFunctions().inlayHints) {
73
+ val factory = PresentationFactory (editor)
74
+ val presentation = createPresentation(factory, method, editor) ? : return false
75
+ sink.addBlockElement(
76
+ offset = method.identifyingElement?.startOffset ? : method.startOffset,
77
+ relatesToPrecedingText = false ,
78
+ showAbove = true ,
79
+ priority = BlockInlayPriority .ANNOTATIONS ,
80
+ presentation = presentation,
81
+ )
82
+ return true
83
+ }
84
+ return false
85
+ }
99
86
100
87
101
88
private fun createPresentation (
102
89
factory : PresentationFactory ,
103
- method : PsiMethod ,
90
+ method : KtFunction ,
104
91
editor : Editor ,
105
92
): InlayPresentation ? {
106
93
var hint =
107
94
factory.text(" @${JvmBlockingBridge ::class .simpleName} " )
108
95
109
- fun createNavigation (mouseEvent : MouseEvent , target : NavigatablePsiElement ) {
110
- PsiElementListNavigator .openTargets(
111
- mouseEvent, arrayOf(target),
112
- " Navigate To Annotation Source" ,
113
- " Find Navigation Target" ,
114
- DefaultPsiElementCellRenderer ()
115
- )
116
- }
117
-
118
- var annotation: KtAnnotationEntry ?
119
- if (method !is KtLightMethod ) return null
120
- if (method.lightMemberOrigin?.originKind != JvmDeclarationOriginKind .OTHER ) return null
121
- if (method.isJvmStatic() && method.containingKtClass !is KtObjectDeclaration ) return null
122
-
123
- when {
124
- method.containingKtClass?.findAnnotation(RuntimeIntrinsics .JvmBlockingBridgeFqName )
125
- .also { annotation = it } != null -> {
126
-
127
- val containingClass = method.containingClass
128
- hint = factory.withTooltip(
129
- " From ${annotation!! .text} on class ${containingClass.name} " ,
130
- hint
131
- )
132
- hint = factory.onClick(hint, MouseButton .Middle ) { mouseEvent, _ ->
133
- createNavigation(
134
- mouseEvent,
135
- annotation!!
136
- )
137
- }
138
- }
96
+ if (method.isJvmStatic() && method.containingClassOrObject !is KtObjectDeclaration ) return null
139
97
140
- method.containingKtFile?.findAnnotation(RuntimeIntrinsics .JvmBlockingBridgeFqName )
141
- .also { annotation = it } != null -> {
142
-
143
- val containingKtFile = method.containingKtFile!!
144
- hint = factory.withTooltip(
145
- " From ${annotation!! .text} on file ${containingKtFile.name} " ,
146
- hint
147
- )
148
- hint = factory.onClick(hint, MouseButton .Middle ) { mouseEvent, _ ->
149
- createNavigation(
150
- mouseEvent,
151
- annotation!!
152
- )
153
- }
154
- }
155
-
156
- else -> {
157
- hint = factory.withTooltip(
158
- " From enableForModule" ,
159
- hint
160
- )
161
- }
98
+ method.containingClassOrObject?.findAnnotation(RuntimeIntrinsics .JvmBlockingBridgeFqName )?.let { annotation ->
99
+ val containingClass = method.containingClassOrObject
100
+ hint = factory.withTooltip(
101
+ " From ${annotation.text} on class ${containingClass?.name} " ,
102
+ hint
103
+ )
104
+ hint = factory.withNavigation(hint, annotation)
105
+ } ? : method.containingKtFile.findAnnotation(RuntimeIntrinsics .JvmBlockingBridgeFqName )?.let { annotation ->
106
+ val containingKtFile = method.containingKtFile
107
+ hint = factory.withTooltip(
108
+ " From ${annotation.text} on file ${containingKtFile.name} " ,
109
+ hint
110
+ )
111
+ hint = factory.withNavigation(hint, annotation)
112
+ } ? : kotlin.run {
113
+ hint = factory.withTooltip(" From enableForModule" , hint)
162
114
}
163
115
164
- val alignmentElement = method.modifierList
116
+ val alignmentElement = method.modifierList ? : return null
165
117
val lineStart =
166
- method.document?.getLineStartOffset(( alignmentElement) .getLineNumber()) ? : return null
118
+ method.document?.getLineStartOffset(alignmentElement.getLineNumber()) ? : return null
167
119
168
120
hint = factory.inset(
169
121
hint,
@@ -178,6 +130,31 @@ class BridgeInlayHintsCollector :
178
130
return hint
179
131
}
180
132
133
+ private fun PresentationFactory.withNavigation (
134
+ base : InlayPresentation ,
135
+ target : NavigatablePsiElement ,
136
+ ): InlayPresentation {
137
+ fun createNavigation (mouseEvent : MouseEvent ) {
138
+ PsiElementListNavigator .openTargets(
139
+ mouseEvent, arrayOf(target),
140
+ " Navigate To Annotation Source" ,
141
+ " Find Navigation Target" ,
142
+ DefaultPsiElementCellRenderer ()
143
+ )
144
+ }
145
+
146
+ var hint = base
147
+
148
+ hint = onClick(hint, MouseButton .Middle ) { mouseEvent, _ ->
149
+ createNavigation(mouseEvent)
150
+ }
151
+ hint = onClick(hint, MouseButton .Left ) { mouseEvent, _ ->
152
+ if (! mouseEvent.isControlDown) return @onClick
153
+ createNavigation(mouseEvent)
154
+ }
155
+ return hint
156
+ }
157
+
181
158
override val name: String get() = " JvmBlockingBridge hints"
182
159
override val previewText: String get() = " "
183
160
@@ -202,4 +179,7 @@ class BridgeInlayHintsCollector :
202
179
}
203
180
204
181
override val key: SettingsKey <NoSettings > get() = SettingsKey (" blocking.bridge.hints" )
205
- }
182
+ }
183
+
184
+ private fun KtDeclarationContainer.ktClassOrObjects () =
185
+ declarations.asSequence().filterIsInstance<KtClassOrObject >()
0 commit comments