From 54d06140342d538367d1883f449fa10023abda5b Mon Sep 17 00:00:00 2001 From: Vladimir Dolzhenko Date: Fri, 4 Oct 2024 21:36:14 +0200 Subject: [PATCH] [kotlin] Rework before resolve highlighting visitor for better injected files support #KTIJ-28361 #KTIJ-17011 GitOrigin-RevId: f95bbc66f6870894b604a1a9ddb89e1279d02053 --- .../K2HighlightingMetaInfoTestGenerated.java | 5 +++ ... => BeforeResolveHighlightingExtension.kt} | 43 +++++++------------ .../KotlinBeforeResolveHighlightingVisitor.kt | 42 ++++++++++++++++++ .../BeforeResolveHighlightingVisitor.kt | 9 +++- .../resources/kotlin.highlighting.shared.xml | 3 +- .../AnnotationEntryHighlightingVisitor.kt | 3 +- .../DeclarationHighlightingVisitor.kt | 3 +- .../K1HighlightingMetaInfoTestGenerated.java | 5 +++ ...tlinInfixFunctionInjection.kt.highlighting | 6 +-- .../jvm/KotlinInjection.kt | 27 +++++++++++- .../jvm/KotlinInjection.kt.highlighting | 27 +++++++++++- .../jvm/KotlinInjection.kt.highlighting.k2 | 32 ++++++++++++++ .../jvm/KotlinSimpleInjection.kt | 9 ++++ .../jvm/KotlinSimpleInjection.kt.highlighting | 9 ++++ 14 files changed, 184 insertions(+), 39 deletions(-) rename plugins/kotlin/highlighting/highlighting-minimal/src/org/jetbrains/kotlin/idea/base/highlighting/{KotlinBeforeResolveHighlightingPass.kt => BeforeResolveHighlightingExtension.kt} (63%) create mode 100644 plugins/kotlin/highlighting/highlighting-minimal/src/org/jetbrains/kotlin/idea/base/highlighting/KotlinBeforeResolveHighlightingVisitor.kt create mode 100644 plugins/kotlin/idea/tests/testData/highlighterMetaInfo/jvm/KotlinInjection.kt.highlighting.k2 create mode 100644 plugins/kotlin/idea/tests/testData/highlighterMetaInfo/jvm/KotlinSimpleInjection.kt create mode 100644 plugins/kotlin/idea/tests/testData/highlighterMetaInfo/jvm/KotlinSimpleInjection.kt.highlighting diff --git a/plugins/kotlin/highlighting/highlighting-k2/test/org/jetbrains/kotlin/idea/k2/highlighting/K2HighlightingMetaInfoTestGenerated.java b/plugins/kotlin/highlighting/highlighting-k2/test/org/jetbrains/kotlin/idea/k2/highlighting/K2HighlightingMetaInfoTestGenerated.java index 5bc03f7589bd..e483be1ab51f 100644 --- a/plugins/kotlin/highlighting/highlighting-k2/test/org/jetbrains/kotlin/idea/k2/highlighting/K2HighlightingMetaInfoTestGenerated.java +++ b/plugins/kotlin/highlighting/highlighting-k2/test/org/jetbrains/kotlin/idea/k2/highlighting/K2HighlightingMetaInfoTestGenerated.java @@ -175,6 +175,11 @@ public abstract class K2HighlightingMetaInfoTestGenerated extends AbstractK2High runTest("../../idea/tests/testData/highlighterMetaInfo/jvm/KotlinInjection.kt"); } + @TestMetadata("KotlinSimpleInjection.kt") + public void testKotlinSimpleInjection() throws Exception { + runTest("../../idea/tests/testData/highlighterMetaInfo/jvm/KotlinSimpleInjection.kt"); + } + @TestMetadata("NonExistingKotlinMethodFromJava.kt") public void testNonExistingKotlinMethodFromJava() throws Exception { runTest("../../idea/tests/testData/highlighterMetaInfo/jvm/NonExistingKotlinMethodFromJava.kt"); diff --git a/plugins/kotlin/highlighting/highlighting-minimal/src/org/jetbrains/kotlin/idea/base/highlighting/KotlinBeforeResolveHighlightingPass.kt b/plugins/kotlin/highlighting/highlighting-minimal/src/org/jetbrains/kotlin/idea/base/highlighting/BeforeResolveHighlightingExtension.kt similarity index 63% rename from plugins/kotlin/highlighting/highlighting-minimal/src/org/jetbrains/kotlin/idea/base/highlighting/KotlinBeforeResolveHighlightingPass.kt rename to plugins/kotlin/highlighting/highlighting-minimal/src/org/jetbrains/kotlin/idea/base/highlighting/BeforeResolveHighlightingExtension.kt index 28b821bda322..f072a939ec2f 100644 --- a/plugins/kotlin/highlighting/highlighting-minimal/src/org/jetbrains/kotlin/idea/base/highlighting/KotlinBeforeResolveHighlightingPass.kt +++ b/plugins/kotlin/highlighting/highlighting-minimal/src/org/jetbrains/kotlin/idea/base/highlighting/BeforeResolveHighlightingExtension.kt @@ -2,30 +2,38 @@ package org.jetbrains.kotlin.idea.base.highlighting -import com.intellij.codeHighlighting.* +import com.intellij.codeHighlighting.TextEditorHighlightingPass +import com.intellij.codeHighlighting.TextEditorHighlightingPassFactory import com.intellij.codeInsight.daemon.impl.analysis.HighlightInfoHolder import com.intellij.openapi.editor.Document import com.intellij.openapi.editor.Editor import com.intellij.openapi.extensions.ExtensionPointName import com.intellij.openapi.project.DumbAware -import com.intellij.openapi.project.Project import com.intellij.psi.PsiElement import com.intellij.psi.PsiFile import com.intellij.psi.PsiRecursiveElementVisitor import org.jetbrains.annotations.ApiStatus import org.jetbrains.kotlin.idea.KotlinFileType -import org.jetbrains.kotlin.idea.highlighter.visitor.AbstractHighlightingVisitor import org.jetbrains.kotlin.idea.highlighter.AbstractHighlightingPassBase -import org.jetbrains.kotlin.idea.highlighter.BeforeResolveHighlightingVisitor +import org.jetbrains.kotlin.idea.highlighter.visitor.AbstractHighlightingVisitor + +@ApiStatus.Internal +interface BeforeResolveHighlightingExtension { + fun createVisitor(holder: HighlightInfoHolder): AbstractHighlightingVisitor + + companion object { + val EP_NAME: ExtensionPointName = + ExtensionPointName.create("org.jetbrains.kotlin.beforeResolveHighlightingVisitor") + } +} + class KotlinBeforeResolveHighlightingPass(file: PsiFile, document: Document) : AbstractHighlightingPassBase(file, document) { override fun runAnnotatorWithContext(element: PsiElement, holder: HighlightInfoHolder) { - val visitor = BeforeResolveHighlightingVisitor(holder) - val extensions = EP_NAME.extensionList.map { it.createVisitor(holder) } + val extensions = BeforeResolveHighlightingExtension.EP_NAME.extensionList.map { it.createVisitor(holder) } element.accept(object : PsiRecursiveElementVisitor() { override fun visitElement(element: PsiElement) { - element.accept(visitor) extensions.forEach(element::accept) super.visitElement(element) } @@ -38,25 +46,4 @@ class KotlinBeforeResolveHighlightingPass(file: PsiFile, document: Document) : A return KotlinBeforeResolveHighlightingPass(file, editor.document) } } - - class Registrar : TextEditorHighlightingPassFactoryRegistrar { - override fun registerHighlightingPassFactory(registrar: TextEditorHighlightingPassRegistrar, project: Project) { - registrar.registerTextEditorHighlightingPass( - Factory(), - /* anchor = */ TextEditorHighlightingPassRegistrar.Anchor.BEFORE, - /* anchorPassId = */ Pass.UPDATE_FOLDING, - /* needAdditionalIntentionsPass = */ false, - /* inPostHighlightingPass = */ false - ) - } - } - - companion object { - val EP_NAME = ExtensionPointName.create("org.jetbrains.kotlin.beforeResolveHighlightingVisitor") - } -} - -@ApiStatus.Internal -interface BeforeResolveHighlightingExtension { - fun createVisitor(holder: HighlightInfoHolder): AbstractHighlightingVisitor } \ No newline at end of file diff --git a/plugins/kotlin/highlighting/highlighting-minimal/src/org/jetbrains/kotlin/idea/base/highlighting/KotlinBeforeResolveHighlightingVisitor.kt b/plugins/kotlin/highlighting/highlighting-minimal/src/org/jetbrains/kotlin/idea/base/highlighting/KotlinBeforeResolveHighlightingVisitor.kt new file mode 100644 index 000000000000..ffc50d44401d --- /dev/null +++ b/plugins/kotlin/highlighting/highlighting-minimal/src/org/jetbrains/kotlin/idea/base/highlighting/KotlinBeforeResolveHighlightingVisitor.kt @@ -0,0 +1,42 @@ +// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package org.jetbrains.kotlin.idea.base.highlighting + +import com.intellij.codeInsight.daemon.impl.HighlightVisitor +import com.intellij.codeInsight.daemon.impl.analysis.HighlightInfoHolder +import com.intellij.openapi.project.DumbAware +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiElementVisitor +import com.intellij.psi.PsiFile +import org.jetbrains.annotations.ApiStatus +import org.jetbrains.kotlin.idea.base.highlighting.BeforeResolveHighlightingExtension.Companion.EP_NAME +import org.jetbrains.kotlin.psi.KtCommonFile + +@ApiStatus.Internal +class KotlinBeforeResolveHighlightingVisitor: HighlightVisitor, DumbAware { + private var visitors: List? = null + + override fun suitableForFile(file: PsiFile): Boolean = + @Suppress("DEPRECATION") + file is KtCommonFile + + override fun visit(element: PsiElement) { + visitors?.forEach(element::accept) + } + + override fun analyze( + file: PsiFile, + updateWholeFile: Boolean, + holder: HighlightInfoHolder, + action: Runnable + ): Boolean { + try { + visitors = EP_NAME.extensionList.map { it.createVisitor(holder) } + action.run() + } finally { + visitors = null + } + return true + } + + override fun clone(): HighlightVisitor = KotlinBeforeResolveHighlightingVisitor() +} \ No newline at end of file diff --git a/plugins/kotlin/highlighting/highlighting-minimal/src/org/jetbrains/kotlin/idea/highlighter/BeforeResolveHighlightingVisitor.kt b/plugins/kotlin/highlighting/highlighting-minimal/src/org/jetbrains/kotlin/idea/highlighter/BeforeResolveHighlightingVisitor.kt index e77a821480d5..17c34fef99f2 100644 --- a/plugins/kotlin/highlighting/highlighting-minimal/src/org/jetbrains/kotlin/idea/highlighter/BeforeResolveHighlightingVisitor.kt +++ b/plugins/kotlin/highlighting/highlighting-minimal/src/org/jetbrains/kotlin/idea/highlighter/BeforeResolveHighlightingVisitor.kt @@ -6,9 +6,11 @@ import com.intellij.codeHighlighting.RainbowHighlighter import com.intellij.codeInsight.daemon.impl.analysis.HighlightInfoHolder import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.editor.colors.EditorColorsManager +import com.intellij.openapi.project.DumbAware import com.intellij.openapi.util.TextRange import com.intellij.psi.PsiElement import org.jetbrains.kotlin.idea.KotlinLanguage +import org.jetbrains.kotlin.idea.base.highlighting.BeforeResolveHighlightingExtension import org.jetbrains.kotlin.idea.highlighter.visitor.AbstractHighlightingVisitor import org.jetbrains.kotlin.kdoc.parser.KDocKnownTag import org.jetbrains.kotlin.kdoc.psi.impl.KDocLink @@ -18,7 +20,7 @@ import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.endOffset import org.jetbrains.kotlin.psi.psiUtil.startOffset -class BeforeResolveHighlightingVisitor(holder: HighlightInfoHolder) : AbstractHighlightingVisitor(holder) { +class BeforeResolveHighlightingVisitor(holder: HighlightInfoHolder) : AbstractHighlightingVisitor(holder), DumbAware { override fun visitElement(element: PsiElement) { val elementType = element.node.elementType val attributes = when { @@ -103,3 +105,8 @@ class BeforeResolveHighlightingVisitor(holder: HighlightInfoHolder) : AbstractHi super.visitNamedFunction(function) } } + +class BeforeResolveHighlightingExtension : BeforeResolveHighlightingExtension { + override fun createVisitor(holder: HighlightInfoHolder): AbstractHighlightingVisitor = + BeforeResolveHighlightingVisitor(holder) +} \ No newline at end of file diff --git a/plugins/kotlin/highlighting/highlighting-shared/resources/kotlin.highlighting.shared.xml b/plugins/kotlin/highlighting/highlighting-shared/resources/kotlin.highlighting.shared.xml index 94ae4a97acca..2a62fba57683 100644 --- a/plugins/kotlin/highlighting/highlighting-shared/resources/kotlin.highlighting.shared.xml +++ b/plugins/kotlin/highlighting/highlighting-shared/resources/kotlin.highlighting.shared.xml @@ -12,7 +12,6 @@ - @@ -22,9 +21,11 @@ + + diff --git a/plugins/kotlin/highlighting/highlighting-shared/src/org/jetbrains/kotlin/idea/base/highlighting/beforeResolve/AnnotationEntryHighlightingVisitor.kt b/plugins/kotlin/highlighting/highlighting-shared/src/org/jetbrains/kotlin/idea/base/highlighting/beforeResolve/AnnotationEntryHighlightingVisitor.kt index 724c06ed94dc..e360e4745ebb 100644 --- a/plugins/kotlin/highlighting/highlighting-shared/src/org/jetbrains/kotlin/idea/base/highlighting/beforeResolve/AnnotationEntryHighlightingVisitor.kt +++ b/plugins/kotlin/highlighting/highlighting-shared/src/org/jetbrains/kotlin/idea/base/highlighting/beforeResolve/AnnotationEntryHighlightingVisitor.kt @@ -3,6 +3,7 @@ package org.jetbrains.kotlin.idea.base.highlighting.beforeResolve import com.intellij.codeInsight.daemon.impl.analysis.HighlightInfoHolder +import com.intellij.openapi.project.DumbAware import com.intellij.openapi.util.TextRange import org.jetbrains.kotlin.idea.base.highlighting.BeforeResolveHighlightingExtension import org.jetbrains.kotlin.idea.highlighter.visitor.AbstractHighlightingVisitor @@ -13,7 +14,7 @@ import org.jetbrains.kotlin.psi.psiUtil.startOffset internal class AnnotationEntryHighlightingVisitor( holder: HighlightInfoHolder -) : AbstractHighlightingVisitor(holder) { +) : AbstractHighlightingVisitor(holder), DumbAware { override fun visitAnnotationEntry(annotationEntry: KtAnnotationEntry) { val range = annotationEntry.getTextRangeToHighlight() ?: return highlightName(annotationEntry.project, range, KotlinHighlightInfoTypeSemanticNames.ANNOTATION) diff --git a/plugins/kotlin/highlighting/highlighting-shared/src/org/jetbrains/kotlin/idea/base/highlighting/beforeResolve/DeclarationHighlightingVisitor.kt b/plugins/kotlin/highlighting/highlighting-shared/src/org/jetbrains/kotlin/idea/base/highlighting/beforeResolve/DeclarationHighlightingVisitor.kt index 8e0be939e7b9..947b5338cedf 100644 --- a/plugins/kotlin/highlighting/highlighting-shared/src/org/jetbrains/kotlin/idea/base/highlighting/beforeResolve/DeclarationHighlightingVisitor.kt +++ b/plugins/kotlin/highlighting/highlighting-shared/src/org/jetbrains/kotlin/idea/base/highlighting/beforeResolve/DeclarationHighlightingVisitor.kt @@ -3,6 +3,7 @@ package org.jetbrains.kotlin.idea.base.highlighting.beforeResolve import com.intellij.codeInsight.daemon.impl.analysis.HighlightInfoHolder +import com.intellij.openapi.project.DumbAware import com.intellij.psi.util.PsiUtilCore import org.jetbrains.kotlin.idea.base.highlighting.BeforeResolveHighlightingExtension import org.jetbrains.kotlin.idea.base.highlighting.textAttributesForClass @@ -13,7 +14,7 @@ import org.jetbrains.kotlin.idea.highlighter.visitor.AbstractHighlightingVisitor import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.psi.* -internal class DeclarationHighlightingVisitor(holder: HighlightInfoHolder) : AbstractHighlightingVisitor(holder) { +internal class DeclarationHighlightingVisitor(holder: HighlightInfoHolder) : AbstractHighlightingVisitor(holder), DumbAware { override fun visitTypeAlias(typeAlias: KtTypeAlias) { highlightNamedDeclaration(typeAlias, KotlinHighlightInfoTypeSemanticNames.TYPE_ALIAS) super.visitTypeAlias(typeAlias) diff --git a/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/highlighter/K1HighlightingMetaInfoTestGenerated.java b/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/highlighter/K1HighlightingMetaInfoTestGenerated.java index 26335e6f8f8d..fb58c084e107 100644 --- a/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/highlighter/K1HighlightingMetaInfoTestGenerated.java +++ b/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/highlighter/K1HighlightingMetaInfoTestGenerated.java @@ -175,6 +175,11 @@ public abstract class K1HighlightingMetaInfoTestGenerated extends AbstractK1High runTest("testData/highlighterMetaInfo/jvm/KotlinInjection.kt"); } + @TestMetadata("KotlinSimpleInjection.kt") + public void testKotlinSimpleInjection() throws Exception { + runTest("testData/highlighterMetaInfo/jvm/KotlinSimpleInjection.kt"); + } + @TestMetadata("NonExistingKotlinMethodFromJava.kt") public void testNonExistingKotlinMethodFromJava() throws Exception { runTest("testData/highlighterMetaInfo/jvm/NonExistingKotlinMethodFromJava.kt"); diff --git a/plugins/kotlin/idea/tests/testData/highlighterMetaInfo/jvm/KotlinInfixFunctionInjection.kt.highlighting b/plugins/kotlin/idea/tests/testData/highlighterMetaInfo/jvm/KotlinInfixFunctionInjection.kt.highlighting index da1f61216601..4519fd157861 100644 --- a/plugins/kotlin/idea/tests/testData/highlighterMetaInfo/jvm/KotlinInfixFunctionInjection.kt.highlighting +++ b/plugins/kotlin/idea/tests/testData/highlighterMetaInfo/jvm/KotlinInfixFunctionInjection.kt.highlighting @@ -8,7 +8,7 @@ infix @Language("kotlin") fun String.xml2(@Language("kotlin") content: String){} fun main() { - "foo" xml "fun foo() {}" - "foo".xml("fun foo() {}") - "fun bar() {}" xml2 "fun foo() {}" + "foo" xml "fun foo() {}" + "foo".xml("fun foo() {}") + "fun bar() {}" xml2 "fun foo() {}" } diff --git a/plugins/kotlin/idea/tests/testData/highlighterMetaInfo/jvm/KotlinInjection.kt b/plugins/kotlin/idea/tests/testData/highlighterMetaInfo/jvm/KotlinInjection.kt index fd678e74b030..43f9c75c8c87 100644 --- a/plugins/kotlin/idea/tests/testData/highlighterMetaInfo/jvm/KotlinInjection.kt +++ b/plugins/kotlin/idea/tests/testData/highlighterMetaInfo/jvm/KotlinInjection.kt @@ -1,4 +1,3 @@ -// FIR_IDENTICAL // CHECK_SYMBOL_NAMES // HIGHLIGHTER_ATTRIBUTES_KEY package language_injection @@ -6,4 +5,28 @@ package language_injection import org.intellij.lang.annotations.Language @Language("kotlin") -val test = "fun test2() {}" +val test = """ +internal class Foo: Bar() { + private val name: String = "Kodee" + lateinit var way: Path + + fun doFun() { + var count = 0 + for21@ for (t in pc) { + while (count < 21) { + print(message = "Hello, ") + println(name) + + count++ + // I meant to type `continue@for21`. + continue@for21 + } + } + } + + companion object { + @JvmStatic + val globalProperty = 42 + } +} +""" diff --git a/plugins/kotlin/idea/tests/testData/highlighterMetaInfo/jvm/KotlinInjection.kt.highlighting b/plugins/kotlin/idea/tests/testData/highlighterMetaInfo/jvm/KotlinInjection.kt.highlighting index 560adda91fbd..31c032df1b42 100644 --- a/plugins/kotlin/idea/tests/testData/highlighterMetaInfo/jvm/KotlinInjection.kt.highlighting +++ b/plugins/kotlin/idea/tests/testData/highlighterMetaInfo/jvm/KotlinInjection.kt.highlighting @@ -1,4 +1,3 @@ -// FIR_IDENTICAL // CHECK_SYMBOL_NAMES // HIGHLIGHTER_ATTRIBUTES_KEY package language_injection @@ -6,4 +5,28 @@ package language_injection import org.intellij.lang.annotations.Language @Language("kotlin") -val test = "fun test2() {}" +val test = """ +internal class Foo: Bar() { + private val name: String = "Kodee" + lateinit var way: Path + + fun doFun() { + var count = 0 + for21@ for (t in pc) { + while (count < 21) { + print(message = "Hello, ") + println(name) + + count++ + // I meant to type `continue@for21`. + continue@for21 + } + } + } + + companion object { + @JvmStatic + val globalProperty = 42 + } +} +""" diff --git a/plugins/kotlin/idea/tests/testData/highlighterMetaInfo/jvm/KotlinInjection.kt.highlighting.k2 b/plugins/kotlin/idea/tests/testData/highlighterMetaInfo/jvm/KotlinInjection.kt.highlighting.k2 new file mode 100644 index 000000000000..b1fbf3df4c45 --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/highlighterMetaInfo/jvm/KotlinInjection.kt.highlighting.k2 @@ -0,0 +1,32 @@ +// CHECK_SYMBOL_NAMES +// HIGHLIGHTER_ATTRIBUTES_KEY +package language_injection + +import org.intellij.lang.annotations.Language + +@Language("kotlin") +val test = """ +internal class Foo: Bar() { + private val name: String = "Kodee" + lateinit var way: Path + + fun doFun() { + var count = 0 + for21@ for (t in pc) { + while (count < 21) { + print(message = "Hello, ") + println(name) + + count++ + // I meant to type `continue@for21`. + continue@for21 + } + } + } + + companion object { + @JvmStatic + val globalProperty = 42 + } +} +""" diff --git a/plugins/kotlin/idea/tests/testData/highlighterMetaInfo/jvm/KotlinSimpleInjection.kt b/plugins/kotlin/idea/tests/testData/highlighterMetaInfo/jvm/KotlinSimpleInjection.kt new file mode 100644 index 000000000000..fd678e74b030 --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/highlighterMetaInfo/jvm/KotlinSimpleInjection.kt @@ -0,0 +1,9 @@ +// FIR_IDENTICAL +// CHECK_SYMBOL_NAMES +// HIGHLIGHTER_ATTRIBUTES_KEY +package language_injection + +import org.intellij.lang.annotations.Language + +@Language("kotlin") +val test = "fun test2() {}" diff --git a/plugins/kotlin/idea/tests/testData/highlighterMetaInfo/jvm/KotlinSimpleInjection.kt.highlighting b/plugins/kotlin/idea/tests/testData/highlighterMetaInfo/jvm/KotlinSimpleInjection.kt.highlighting new file mode 100644 index 000000000000..ee8803ce5fde --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/highlighterMetaInfo/jvm/KotlinSimpleInjection.kt.highlighting @@ -0,0 +1,9 @@ +// FIR_IDENTICAL +// CHECK_SYMBOL_NAMES +// HIGHLIGHTER_ATTRIBUTES_KEY +package language_injection + +import org.intellij.lang.annotations.Language + +@Language("kotlin") +val test = "fun test2() {}"