Dsl highlighting: support highlighting properties
Fix properties not being highlighted Fix test infrastructure to verify actual output of highlighting visitors
This commit is contained in:
+1
-1
@@ -19,6 +19,6 @@ package org.jetbrains.kotlin.idea.highlighter
|
|||||||
import com.intellij.lang.annotation.AnnotationHolder
|
import com.intellij.lang.annotation.AnnotationHolder
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
|
|
||||||
internal abstract class AfterAnalysisHighlightingVisitor protected constructor(
|
abstract class AfterAnalysisHighlightingVisitor protected constructor(
|
||||||
holder: AnnotationHolder, protected var bindingContext: BindingContext
|
holder: AnnotationHolder, protected var bindingContext: BindingContext
|
||||||
) : HighlightingVisitor(holder)
|
) : HighlightingVisitor(holder)
|
||||||
|
|||||||
@@ -48,16 +48,8 @@ abstract class HighlightingVisitor protected constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected fun applyHighlighterExtensions(element: PsiElement, descriptor: DeclarationDescriptor): Boolean {
|
protected fun attributeKeyForDeclarationFromExtensions(element: PsiElement, descriptor: DeclarationDescriptor) =
|
||||||
if (!NameHighlighter.namesHighlightingEnabled) return false
|
|
||||||
|
|
||||||
Extensions.getExtensions(HighlighterExtension.EP_NAME).firstNotNullResult { extension ->
|
Extensions.getExtensions(HighlighterExtension.EP_NAME).firstNotNullResult { extension ->
|
||||||
extension.highlightDeclaration(element, descriptor)
|
extension.highlightDeclaration(element, descriptor)
|
||||||
}?.let { key ->
|
|
||||||
highlightName(element, key)
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ open class KotlinPsiChecker : Annotator, HighlightRangeExtension {
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private fun getAfterAnalysisVisitor(holder: AnnotationHolder, bindingContext: BindingContext) = arrayOf(
|
fun getAfterAnalysisVisitor(holder: AnnotationHolder, bindingContext: BindingContext) = arrayOf(
|
||||||
PropertiesHighlightingVisitor(holder, bindingContext),
|
PropertiesHighlightingVisitor(holder, bindingContext),
|
||||||
FunctionsHighlightingVisitor(holder, bindingContext),
|
FunctionsHighlightingVisitor(holder, bindingContext),
|
||||||
VariablesHighlightingVisitor(holder, bindingContext),
|
VariablesHighlightingVisitor(holder, bindingContext),
|
||||||
|
|||||||
+27
-10
@@ -6,6 +6,8 @@
|
|||||||
package org.jetbrains.kotlin.idea.highlighter
|
package org.jetbrains.kotlin.idea.highlighter
|
||||||
|
|
||||||
import com.intellij.lang.annotation.AnnotationHolder
|
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 com.intellij.psi.PsiElement
|
||||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.impl.SyntheticFieldDescriptor
|
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.psi.KtThisExpression
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
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.tasks.isDynamic
|
||||||
import org.jetbrains.kotlin.resolve.calls.tower.isSynthesized
|
import org.jetbrains.kotlin.resolve.calls.tower.isSynthesized
|
||||||
|
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
|
||||||
|
|
||||||
internal class PropertiesHighlightingVisitor(holder: AnnotationHolder, bindingContext: BindingContext)
|
internal class PropertiesHighlightingVisitor(holder: AnnotationHolder, bindingContext: BindingContext)
|
||||||
: AfterAnalysisHighlightingVisitor(holder, bindingContext) {
|
: AfterAnalysisHighlightingVisitor(holder, bindingContext) {
|
||||||
@@ -35,14 +39,23 @@ internal class PropertiesHighlightingVisitor(holder: AnnotationHolder, bindingCo
|
|||||||
return
|
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) {
|
override fun visitProperty(property: KtProperty) {
|
||||||
val nameIdentifier = property.nameIdentifier ?: return
|
val nameIdentifier = property.nameIdentifier ?: return
|
||||||
val propertyDescriptor = bindingContext.get(BindingContext.VARIABLE, property)
|
val propertyDescriptor = bindingContext.get(BindingContext.VARIABLE, property)
|
||||||
if (propertyDescriptor is PropertyDescriptor) {
|
if (propertyDescriptor is PropertyDescriptor) {
|
||||||
highlightProperty(nameIdentifier, propertyDescriptor)
|
highlightPropertyDeclaration(nameIdentifier, propertyDescriptor)
|
||||||
}
|
}
|
||||||
|
|
||||||
super.visitProperty(property)
|
super.visitProperty(property)
|
||||||
@@ -55,19 +68,24 @@ internal class PropertiesHighlightingVisitor(holder: AnnotationHolder, bindingCo
|
|||||||
if (propertyDescriptor.isVar) {
|
if (propertyDescriptor.isVar) {
|
||||||
highlightName(nameIdentifier, MUTABLE_VARIABLE)
|
highlightName(nameIdentifier, MUTABLE_VARIABLE)
|
||||||
}
|
}
|
||||||
highlightProperty(nameIdentifier, propertyDescriptor)
|
highlightPropertyDeclaration(nameIdentifier, propertyDescriptor)
|
||||||
}
|
}
|
||||||
|
|
||||||
super.visitParameter(parameter)
|
super.visitParameter(parameter)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun highlightProperty(
|
private fun highlightPropertyDeclaration(
|
||||||
elementToHighlight: PsiElement,
|
elementToHighlight: PsiElement,
|
||||||
descriptor: PropertyDescriptor) {
|
descriptor: PropertyDescriptor
|
||||||
|
) {
|
||||||
|
highlightName(
|
||||||
|
elementToHighlight,
|
||||||
|
attributeKeyForDeclarationFromExtensions(elementToHighlight, descriptor) ?: attributeKeyByPropertyType(descriptor)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
if (applyHighlighterExtensions(elementToHighlight, descriptor)) return
|
private fun attributeKeyByPropertyType(descriptor: PropertyDescriptor): TextAttributesKey {
|
||||||
|
return when {
|
||||||
val attributesKey = when {
|
|
||||||
descriptor.isDynamic() ->
|
descriptor.isDynamic() ->
|
||||||
DYNAMIC_PROPERTY_CALL
|
DYNAMIC_PROPERTY_CALL
|
||||||
|
|
||||||
@@ -80,6 +98,5 @@ internal class PropertiesHighlightingVisitor(holder: AnnotationHolder, bindingCo
|
|||||||
else ->
|
else ->
|
||||||
INSTANCE_PROPERTY
|
INSTANCE_PROPERTY
|
||||||
}
|
}
|
||||||
highlightName(elementToHighlight, attributesKey)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-4
@@ -89,8 +89,11 @@ internal class TypeKindHighlightingVisitor(holder: AnnotationHolder, bindingCont
|
|||||||
val identifier = classOrObject.nameIdentifier
|
val identifier = classOrObject.nameIdentifier
|
||||||
val classDescriptor = bindingContext.get(BindingContext.CLASS, classOrObject)
|
val classDescriptor = bindingContext.get(BindingContext.CLASS, classOrObject)
|
||||||
if (identifier != null && classDescriptor != null) {
|
if (identifier != null && classDescriptor != null) {
|
||||||
if (applyHighlighterExtensions(identifier, classDescriptor)) return
|
highlightName(
|
||||||
highlightName(identifier, textAttributesKeyForClass(classDescriptor))
|
identifier,
|
||||||
|
attributeKeyForDeclarationFromExtensions(classOrObject, classDescriptor)
|
||||||
|
?: textAttributesKeyForClass(classDescriptor)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
super.visitClassOrObject(classOrObject)
|
super.visitClassOrObject(classOrObject)
|
||||||
}
|
}
|
||||||
@@ -99,8 +102,10 @@ internal class TypeKindHighlightingVisitor(holder: AnnotationHolder, bindingCont
|
|||||||
val identifier = typeAlias.nameIdentifier
|
val identifier = typeAlias.nameIdentifier
|
||||||
val descriptor = bindingContext.get(BindingContext.TYPE_ALIAS, typeAlias)
|
val descriptor = bindingContext.get(BindingContext.TYPE_ALIAS, typeAlias)
|
||||||
if (identifier != null && descriptor != null) {
|
if (identifier != null && descriptor != null) {
|
||||||
if (applyHighlighterExtensions(identifier, descriptor)) return
|
highlightName(
|
||||||
highlightName(identifier, TYPE_ALIAS)
|
identifier,
|
||||||
|
attributeKeyForDeclarationFromExtensions(identifier, descriptor) ?: TYPE_ALIAS
|
||||||
|
)
|
||||||
}
|
}
|
||||||
super.visitTypeAlias(typeAlias)
|
super.visitTypeAlias(typeAlias)
|
||||||
}
|
}
|
||||||
|
|||||||
+44
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,6 +5,8 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.idea.highlighter
|
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.psi.PsiComment
|
||||||
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase
|
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.analyzeWithAllCompilerChecks
|
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 commentText = (file.findElementAt(endOffset - 1) as? PsiComment)?.text
|
||||||
val styleIdByComment = commentText?.replace("//", "")?.trim()?.toInt()?.let { DslHighlighterExtension.externalKeyName(it) }
|
val styleIdByComment = commentText?.replace("//", "")?.trim()?.toInt()?.let { DslHighlighterExtension.externalKeyName(it) }
|
||||||
val styleIdByCall = extension.highlightCall(element, call)?.externalName
|
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
|
if (styleIdByCall == null) fail("Expected `$what` to be highlighted $location")
|
||||||
val location = "at line ${editor.document.getLineNumber(element.textOffset) + 1}"
|
if (styleIdByComment == null) fail("Unexpected highlighting of `$what` $location")
|
||||||
|
|
||||||
if (styleIdByCall == null) fail("Expected `$what` to be highlighted $location")
|
fail("Expected: $styleIdByComment, got: $styleIdByCall for $what $location")
|
||||||
if (styleIdByComment == null) fail("Unexpected highlighting of `$what` $location")
|
}
|
||||||
|
|
||||||
fail("Expected: $styleIdByComment, got: $styleIdByCall for $what $location")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val visitor = object : KtTreeVisitor<Unit?>() {
|
val visitor = object : KtTreeVisitor<Unit?>() {
|
||||||
|
|||||||
+5
@@ -33,4 +33,9 @@ public class DslHighlighterTestGenerated extends AbstractDslHighlighterTest {
|
|||||||
public void testFunctionCalls() throws Exception {
|
public void testFunctionCalls() throws Exception {
|
||||||
runTest("idea/testData/dslHighlighter/functionCalls.kt");
|
runTest("idea/testData/dslHighlighter/functionCalls.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("propertyAccess.kt")
|
||||||
|
public void testPropertyAccess() throws Exception {
|
||||||
|
runTest("idea/testData/dslHighlighter/propertyAccess.kt");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user