From a1b20535b29bcab59cdeea7cf32341d6f00f8e29 Mon Sep 17 00:00:00 2001 From: Nikolay Krasko Date: Mon, 15 Jan 2018 15:55:15 +0300 Subject: [PATCH] Search same place for `it` usages in rainbow highlighter (KT-22242) Reuse KotlinTargetElementEvaluator for getting same declaration context for implicit 'it' parameter. #KT-22242 Fixed --- .../idea/highlighter/KotlinRainbowVisitor.kt | 56 ++++++++++--------- .../KotlinTargetElementEvaluator.kt | 8 +-- .../KotlinRainbowHighlighterTest.kt | 26 +++++++++ 3 files changed, 60 insertions(+), 30 deletions(-) diff --git a/idea/src/org/jetbrains/kotlin/idea/highlighter/KotlinRainbowVisitor.kt b/idea/src/org/jetbrains/kotlin/idea/highlighter/KotlinRainbowVisitor.kt index 2cb34d7df62..660229b073d 100644 --- a/idea/src/org/jetbrains/kotlin/idea/highlighter/KotlinRainbowVisitor.kt +++ b/idea/src/org/jetbrains/kotlin/idea/highlighter/KotlinRainbowVisitor.kt @@ -16,25 +16,26 @@ package org.jetbrains.kotlin.idea.highlighter +import com.intellij.codeInsight.TargetElementUtil import com.intellij.codeInsight.daemon.RainbowVisitor import com.intellij.openapi.editor.colors.TextAttributesKey import com.intellij.psi.PsiElement import com.intellij.psi.PsiFile import com.intellij.psi.util.PsiTreeUtil -import org.jetbrains.kotlin.descriptors.VariableDescriptor -import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.idea.highlighter.KotlinHighlightingColors.* +import org.jetbrains.kotlin.idea.references.mainReference +import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinTargetElementEvaluator import org.jetbrains.kotlin.kdoc.psi.impl.KDocName import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType import org.jetbrains.kotlin.psi.psiUtil.isAncestor import org.jetbrains.kotlin.psi.psiUtil.parents -import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils -import org.jetbrains.kotlin.resolve.bindingContextUtil.getReferenceTargets -import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode -import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull class KotlinRainbowVisitor : RainbowVisitor() { + companion object { + val KOTLIN_TARGET_ELEMENT_EVALUATOR = KotlinTargetElementEvaluator() + } + override fun suitableForFile(file: PsiFile) = file is KtFile override fun clone() = KotlinRainbowVisitor() @@ -46,20 +47,24 @@ class KotlinRainbowVisitor : RainbowVisitor() { addRainbowHighlight(element, rainbowElement) } element is KtSimpleNameExpression -> { - val qualifiedExpression = PsiTreeUtil.getParentOfType(element, KtQualifiedExpression::class.java, true, - KtLambdaExpression::class.java, KtValueArgumentList::class.java) + val qualifiedExpression = PsiTreeUtil.getParentOfType( + element, KtQualifiedExpression::class.java, true, + KtLambdaExpression::class.java, KtValueArgumentList::class.java + ) if (qualifiedExpression?.selectorExpression?.isAncestor(element) == true) return - val bindingContext = element.analyze(BodyResolveMode.PARTIAL_WITH_DIAGNOSTICS) - val targets = element.getReferenceTargets(bindingContext) - val targetVariable = targets.firstIsInstanceOrNull() - if (targetVariable != null) { - val targetElement = DescriptorToSourceUtils.getSourceFromDescriptor(targetVariable) + val reference = element.mainReference + val targetElement = reference.resolve() + if (targetElement != null) { if (targetElement.isRainbowDeclaration()) { - addRainbowHighlight(targetElement!!, element) + addRainbowHighlight(targetElement, element) } - else if (targetElement == null && element.getReferencedName() == "it") { - addRainbowHighlight(element, element) + } else if (element.getReferencedName() == "it") { + val itTargetElement = + KOTLIN_TARGET_ELEMENT_EVALUATOR.getElementByReference(reference, TargetElementUtil.REFERENCED_ELEMENT_ACCEPTED) + + if (itTargetElement != null) { + addRainbowHighlight(itTargetElement, element) } } } @@ -72,14 +77,13 @@ class KotlinRainbowVisitor : RainbowVisitor() { } } - private fun addRainbowHighlight(target: PsiElement, rainbowElement: PsiElement, - attributesKey: TextAttributesKey? = null) { + private fun addRainbowHighlight(target: PsiElement, rainbowElement: PsiElement, attributesKey: TextAttributesKey? = null) { val lambdaSequenceIterator = target.parents - .takeWhile { it !is KtDeclaration || it.isAnonymousFunction() || it is KtFunctionLiteral } - .filter { it is KtLambdaExpression || it.isAnonymousFunction() } - .iterator() + .takeWhile { it !is KtDeclaration || it.isAnonymousFunction() || it is KtFunctionLiteral } + .filter { it is KtLambdaExpression || it.isAnonymousFunction() } + .iterator() - val attributesKeyToUse = attributesKey ?: (if (target is KtParameter) PARAMETER else LOCAL_VARIABLE) + val attributesKeyToUse = attributesKey ?: (if (target is KtParameter) PARAMETER else LOCAL_VARIABLE) if (lambdaSequenceIterator.hasNext()) { var lambda = lambdaSequenceIterator.next() var lambdaNestingLevel = 0 @@ -97,10 +101,10 @@ class KotlinRainbowVisitor : RainbowVisitor() { addInfo(getInfo(context, rainbowElement, rainbowElement.text, attributesKeyToUse)) } - private fun PsiElement?.isRainbowDeclaration(): Boolean = - (this is KtProperty && isLocal) || - (this is KtParameter && getStrictParentOfType() == null) || - this is KtDestructuringDeclarationEntry + private fun PsiElement.isRainbowDeclaration(): Boolean = + (this is KtProperty && isLocal) || + (this is KtParameter && getStrictParentOfType() == null) || + this is KtDestructuringDeclarationEntry } private fun PsiElement.isAnonymousFunction(): Boolean = this is KtNamedFunction && nameIdentifier == null diff --git a/idea/src/org/jetbrains/kotlin/idea/search/ideaExtensions/KotlinTargetElementEvaluator.kt b/idea/src/org/jetbrains/kotlin/idea/search/ideaExtensions/KotlinTargetElementEvaluator.kt index 3c32a84ed5c..21391929097 100644 --- a/idea/src/org/jetbrains/kotlin/idea/search/ideaExtensions/KotlinTargetElementEvaluator.kt +++ b/idea/src/org/jetbrains/kotlin/idea/search/ideaExtensions/KotlinTargetElementEvaluator.kt @@ -39,8 +39,8 @@ import org.jetbrains.kotlin.resolve.source.getPsi class KotlinTargetElementEvaluator : TargetElementEvaluatorEx, TargetElementUtilExtender { companion object { - val DO_NOT_UNWRAP_LABELED_EXPRESSION = 0x100 - val BYPASS_IMPORT_ALIAS = 0x200 + const val DO_NOT_UNWRAP_LABELED_EXPRESSION = 0x100 + const val BYPASS_IMPORT_ALIAS = 0x200 // Place caret after the open curly brace in lambda for generated 'it' fun findLambdaOpenLBraceForGeneratedIt(ref: PsiReference): PsiElement? { @@ -105,8 +105,8 @@ class KotlinTargetElementEvaluator : TargetElementEvaluatorEx, TargetElementUtil } if (BitUtil.isSet(flags, TargetElementUtil.REFERENCED_ELEMENT_ACCEPTED)) { - return findLambdaOpenLBraceForGeneratedIt(ref) ?: - findReceiverForThisInExtensionFunction(ref) + return findLambdaOpenLBraceForGeneratedIt(ref) + ?: findReceiverForThisInExtensionFunction(ref) } return null diff --git a/idea/tests/org/jetbrains/kotlin/idea/highlighter/KotlinRainbowHighlighterTest.kt b/idea/tests/org/jetbrains/kotlin/idea/highlighter/KotlinRainbowHighlighterTest.kt index 57cf613f83c..8b2f5c62700 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/highlighter/KotlinRainbowHighlighterTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/highlighter/KotlinRainbowHighlighterTest.kt @@ -39,6 +39,32 @@ class KotlinRainbowHighlighterTest : KotlinLightCodeInsightFixtureTestCase() { """) } + fun testRainbowNestedVal() { + checkRainbow( + """ + fun some() { + run { + val name = 1 + name + run { + val name = 2 + name + } + } + } + """ + ) + } + + fun testAssignmentIt() { + checkRainbow(""" + val f : (Int) -> Unit = { + val t = it + it + } + """) + } + fun testRainbowNestedAnonymousFunction() { checkRainbow(""" fun main() {