diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/AfterAnalysisHighlightingVisitor.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/AfterAnalysisHighlightingVisitor.kt index fc034e1d2b1..eaca4f6ca6b 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/AfterAnalysisHighlightingVisitor.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/AfterAnalysisHighlightingVisitor.kt @@ -19,6 +19,6 @@ package org.jetbrains.kotlin.idea.highlighter import com.intellij.lang.annotation.AnnotationHolder import org.jetbrains.kotlin.resolve.BindingContext -internal abstract class AfterAnalysisHighlightingVisitor protected constructor( +abstract class AfterAnalysisHighlightingVisitor protected constructor( holder: AnnotationHolder, protected var bindingContext: BindingContext ) : HighlightingVisitor(holder) diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/HighlightingVisitor.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/HighlightingVisitor.kt index 99fb8d26d2e..bc82b3ae3db 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/HighlightingVisitor.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/HighlightingVisitor.kt @@ -48,16 +48,8 @@ abstract class HighlightingVisitor protected constructor( } } - protected fun applyHighlighterExtensions(element: PsiElement, descriptor: DeclarationDescriptor): Boolean { - if (!NameHighlighter.namesHighlightingEnabled) return false - + protected fun attributeKeyForDeclarationFromExtensions(element: PsiElement, descriptor: DeclarationDescriptor) = Extensions.getExtensions(HighlighterExtension.EP_NAME).firstNotNullResult { extension -> extension.highlightDeclaration(element, descriptor) - }?.let { key -> - highlightName(element, key) - return true } - - return false - } } diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/KotlinPsiChecker.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/KotlinPsiChecker.kt index 02dcfa714b5..f4428971e47 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/KotlinPsiChecker.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/KotlinPsiChecker.kt @@ -97,7 +97,7 @@ open class KotlinPsiChecker : Annotator, HighlightRangeExtension { } companion object { - private fun getAfterAnalysisVisitor(holder: AnnotationHolder, bindingContext: BindingContext) = arrayOf( + fun getAfterAnalysisVisitor(holder: AnnotationHolder, bindingContext: BindingContext) = arrayOf( PropertiesHighlightingVisitor(holder, bindingContext), FunctionsHighlightingVisitor(holder, bindingContext), VariablesHighlightingVisitor(holder, bindingContext), diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/PropertiesHighlightingVisitor.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/PropertiesHighlightingVisitor.kt index 6a5a40b1011..3af3cff3e68 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/PropertiesHighlightingVisitor.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/PropertiesHighlightingVisitor.kt @@ -6,6 +6,8 @@ package org.jetbrains.kotlin.idea.highlighter import com.intellij.lang.annotation.AnnotationHolder +import com.intellij.openapi.editor.colors.TextAttributesKey +import com.intellij.openapi.extensions.Extensions import com.intellij.psi.PsiElement import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.descriptors.impl.SyntheticFieldDescriptor @@ -16,8 +18,10 @@ import org.jetbrains.kotlin.psi.KtSimpleNameExpression import org.jetbrains.kotlin.psi.KtThisExpression import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.DescriptorUtils +import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall import org.jetbrains.kotlin.resolve.calls.tasks.isDynamic import org.jetbrains.kotlin.resolve.calls.tower.isSynthesized +import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult internal class PropertiesHighlightingVisitor(holder: AnnotationHolder, bindingContext: BindingContext) : AfterAnalysisHighlightingVisitor(holder, bindingContext) { @@ -35,14 +39,23 @@ internal class PropertiesHighlightingVisitor(holder: AnnotationHolder, bindingCo return } - highlightProperty(expression, target) + val resolvedCall = expression.getResolvedCall(bindingContext) + + val attributesKey = resolvedCall?.let { call -> + Extensions.getExtensions(HighlighterExtension.EP_NAME).firstNotNullResult { extension -> + extension.highlightCall(expression, call) + } + } ?: attributeKeyByPropertyType(target) + + highlightName(expression, attributesKey) + } override fun visitProperty(property: KtProperty) { val nameIdentifier = property.nameIdentifier ?: return val propertyDescriptor = bindingContext.get(BindingContext.VARIABLE, property) if (propertyDescriptor is PropertyDescriptor) { - highlightProperty(nameIdentifier, propertyDescriptor) + highlightPropertyDeclaration(nameIdentifier, propertyDescriptor) } super.visitProperty(property) @@ -55,19 +68,24 @@ internal class PropertiesHighlightingVisitor(holder: AnnotationHolder, bindingCo if (propertyDescriptor.isVar) { highlightName(nameIdentifier, MUTABLE_VARIABLE) } - highlightProperty(nameIdentifier, propertyDescriptor) + highlightPropertyDeclaration(nameIdentifier, propertyDescriptor) } super.visitParameter(parameter) } - private fun highlightProperty( - elementToHighlight: PsiElement, - descriptor: PropertyDescriptor) { + private fun highlightPropertyDeclaration( + elementToHighlight: PsiElement, + descriptor: PropertyDescriptor + ) { + highlightName( + elementToHighlight, + attributeKeyForDeclarationFromExtensions(elementToHighlight, descriptor) ?: attributeKeyByPropertyType(descriptor) + ) + } - if (applyHighlighterExtensions(elementToHighlight, descriptor)) return - - val attributesKey = when { + private fun attributeKeyByPropertyType(descriptor: PropertyDescriptor): TextAttributesKey { + return when { descriptor.isDynamic() -> DYNAMIC_PROPERTY_CALL @@ -80,6 +98,5 @@ internal class PropertiesHighlightingVisitor(holder: AnnotationHolder, bindingCo else -> INSTANCE_PROPERTY } - highlightName(elementToHighlight, attributesKey) } } diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/TypeKindHighlightingVisitor.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/TypeKindHighlightingVisitor.kt index e88de83289f..6c0b1dcae48 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/TypeKindHighlightingVisitor.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/TypeKindHighlightingVisitor.kt @@ -89,8 +89,11 @@ internal class TypeKindHighlightingVisitor(holder: AnnotationHolder, bindingCont val identifier = classOrObject.nameIdentifier val classDescriptor = bindingContext.get(BindingContext.CLASS, classOrObject) if (identifier != null && classDescriptor != null) { - if (applyHighlighterExtensions(identifier, classDescriptor)) return - highlightName(identifier, textAttributesKeyForClass(classDescriptor)) + highlightName( + identifier, + attributeKeyForDeclarationFromExtensions(classOrObject, classDescriptor) + ?: textAttributesKeyForClass(classDescriptor) + ) } super.visitClassOrObject(classOrObject) } @@ -99,8 +102,10 @@ internal class TypeKindHighlightingVisitor(holder: AnnotationHolder, bindingCont val identifier = typeAlias.nameIdentifier val descriptor = bindingContext.get(BindingContext.TYPE_ALIAS, typeAlias) if (identifier != null && descriptor != null) { - if (applyHighlighterExtensions(identifier, descriptor)) return - highlightName(identifier, TYPE_ALIAS) + highlightName( + identifier, + attributeKeyForDeclarationFromExtensions(identifier, descriptor) ?: TYPE_ALIAS + ) } super.visitTypeAlias(typeAlias) } diff --git a/idea/testData/dslHighlighter/propertyAccess.kt b/idea/testData/dslHighlighter/propertyAccess.kt new file mode 100644 index 00000000000..9b53fc86acc --- /dev/null +++ b/idea/testData/dslHighlighter/propertyAccess.kt @@ -0,0 +1,44 @@ +package p + +@DslMarker +annotation class A + +@DslMarker +annotation class B + +@A +val AC.p1: Int + get() = 3 + +@A +var p2: Int = 5 + +@B +val BC.p3 + get() = 6 + + +@B +var BC.p7 + get() = 3 + set(i) {} + +@A +class AC + +@B +class BC + +fun test() { + p2 // 4 + p2 = 6 // 4 + + with(AC()) { + p1 // 4 + } + with(BC()) { + p3 // 1 + p7 // 1 + p7 = 3 // 1 + } +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/highlighter/AbstractDslHighlighterTest.kt b/idea/tests/org/jetbrains/kotlin/idea/highlighter/AbstractDslHighlighterTest.kt index 0b7e07aa7e7..1830933be47 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/highlighter/AbstractDslHighlighterTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/highlighter/AbstractDslHighlighterTest.kt @@ -5,6 +5,8 @@ package org.jetbrains.kotlin.idea.highlighter +import com.intellij.codeInsight.daemon.impl.AnnotationHolderImpl +import com.intellij.lang.annotation.AnnotationSession import com.intellij.psi.PsiComment import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase import org.jetbrains.kotlin.idea.caches.resolve.analyzeWithAllCompilerChecks @@ -30,15 +32,26 @@ abstract class AbstractDslHighlighterTest : LightCodeInsightFixtureTestCase() { val commentText = (file.findElementAt(endOffset - 1) as? PsiComment)?.text val styleIdByComment = commentText?.replace("//", "")?.trim()?.toInt()?.let { DslHighlighterExtension.externalKeyName(it) } val styleIdByCall = extension.highlightCall(element, call)?.externalName - if (styleIdByCall == styleIdByComment) return + if (styleIdByCall != null && styleIdByCall == styleIdByComment) { + val annotationHolder = AnnotationHolderImpl(AnnotationSession(psiFile)) + val checkers = KotlinPsiChecker.getAfterAnalysisVisitor(annotationHolder, bindingContext) + checkers.forEach { call.call.callElement.accept(it) } + assertTrue( + "KotlinPsiChecker did not contribute an Annotation containing the correct text attribute key at line ${lineNumber + 1}", + annotationHolder.any { + it.textAttributes.externalName == styleIdByComment + } + ) + } else if (styleIdByCall != styleIdByComment) { + val what = element.text + val location = "at line ${editor.document.getLineNumber(element.textOffset) + 1}" - val what = element.text - val location = "at line ${editor.document.getLineNumber(element.textOffset) + 1}" + if (styleIdByCall == null) fail("Expected `$what` to be highlighted $location") + if (styleIdByComment == null) fail("Unexpected highlighting of `$what` $location") - if (styleIdByCall == null) fail("Expected `$what` to be highlighted $location") - if (styleIdByComment == null) fail("Unexpected highlighting of `$what` $location") + fail("Expected: $styleIdByComment, got: $styleIdByCall for $what $location") + } - fail("Expected: $styleIdByComment, got: $styleIdByCall for $what $location") } val visitor = object : KtTreeVisitor() { diff --git a/idea/tests/org/jetbrains/kotlin/idea/highlighter/DslHighlighterTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/highlighter/DslHighlighterTestGenerated.java index da97fc7860a..7cc11c33e6d 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/highlighter/DslHighlighterTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/highlighter/DslHighlighterTestGenerated.java @@ -33,4 +33,9 @@ public class DslHighlighterTestGenerated extends AbstractDslHighlighterTest { public void testFunctionCalls() throws Exception { runTest("idea/testData/dslHighlighter/functionCalls.kt"); } + + @TestMetadata("propertyAccess.kt") + public void testPropertyAccess() throws Exception { + runTest("idea/testData/dslHighlighter/propertyAccess.kt"); + } }