Move frontend independent parts of KtReference.isReferenceTo up to share it.
This commit is contained in:
+3
-7
@@ -36,12 +36,8 @@ abstract class KtFe10SimpleNameReference(expression: KtSimpleNameExpression) : K
|
|||||||
internal class CliKtFe10SimpleNameReference(
|
internal class CliKtFe10SimpleNameReference(
|
||||||
expression: KtSimpleNameExpression
|
expression: KtSimpleNameExpression
|
||||||
) : KtFe10SimpleNameReference(expression), CliKtFe10Reference {
|
) : KtFe10SimpleNameReference(expression), CliKtFe10Reference {
|
||||||
override fun doCanBeReferenceTo(candidateTarget: PsiElement): Boolean {
|
override fun isReferenceToViaExtension(element: PsiElement): Boolean {
|
||||||
return true
|
return false
|
||||||
}
|
|
||||||
|
|
||||||
override fun isReferenceTo(element: PsiElement): Boolean {
|
|
||||||
return resolve() == element
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun handleElementRename(newElementName: String): PsiElement? {
|
override fun handleElementRename(newElementName: String): PsiElement? {
|
||||||
@@ -59,4 +55,4 @@ internal class CliKtFe10SimpleNameReference(
|
|||||||
override fun getImportAlias(): KtImportAlias? {
|
override fun getImportAlias(): KtImportAlias? {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-4
@@ -43,13 +43,13 @@ internal class KtFirSimpleNameReference(
|
|||||||
return fixUpAnnotationCallResolveToCtor(results)
|
return fixUpAnnotationCallResolveToCtor(results)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun doCanBeReferenceTo(candidateTarget: PsiElement): Boolean {
|
override fun canBeReferenceTo(candidateTarget: PsiElement): Boolean {
|
||||||
return true // TODO
|
return true // TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Extension point used for deprecated Android Extensions. Not going to implement for FIR.
|
||||||
override fun isReferenceTo(element: PsiElement): Boolean {
|
override fun isReferenceToViaExtension(element: PsiElement): Boolean {
|
||||||
return resolve() == element //todo
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun handleElementRename(newElementName: String): PsiElement? {
|
override fun handleElementRename(newElementName: String): PsiElement? {
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ plugins {
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation(project(":compiler:psi"))
|
implementation(project(":compiler:psi"))
|
||||||
|
implementation(project(":compiler:light-classes"))
|
||||||
implementation(intellijCore())
|
implementation(intellijCore())
|
||||||
|
|
||||||
compileOnly(commonDependency("com.google.guava:guava"))
|
compileOnly(commonDependency("com.google.guava:guava"))
|
||||||
|
|||||||
@@ -8,9 +8,13 @@ package org.jetbrains.kotlin.idea.references
|
|||||||
import com.intellij.psi.*
|
import com.intellij.psi.*
|
||||||
import com.intellij.psi.impl.source.resolve.ResolveCache
|
import com.intellij.psi.impl.source.resolve.ResolveCache
|
||||||
import com.intellij.util.IncorrectOperationException
|
import com.intellij.util.IncorrectOperationException
|
||||||
|
import org.jetbrains.kotlin.asJava.unwrapped
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.psi.KtElement
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.KtReferenceExpression
|
import org.jetbrains.kotlin.psi.psiUtil.getLabeledParent
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.getParentOfTypeAndBranch
|
||||||
|
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||||
|
|
||||||
interface KtReference : PsiPolyVariantReference {
|
interface KtReference : PsiPolyVariantReference {
|
||||||
val resolver: ResolveCache.PolyVariantResolver<KtReference>
|
val resolver: ResolveCache.PolyVariantResolver<KtReference>
|
||||||
@@ -40,8 +44,105 @@ abstract class AbstractKtReference<T : KtElement>(element: T) : PsiPolyVariantRe
|
|||||||
override fun isSoft(): Boolean = false
|
override fun isSoft(): Boolean = false
|
||||||
|
|
||||||
override fun toString() = this::class.java.simpleName + ": " + expression.text
|
override fun toString() = this::class.java.simpleName + ": " + expression.text
|
||||||
|
|
||||||
|
@Suppress("UNUSED_PARAMETER")
|
||||||
|
protected open fun canBeReferenceTo(candidateTarget: PsiElement): Boolean = true
|
||||||
|
|
||||||
|
@Suppress("UNUSED_PARAMETER")
|
||||||
|
protected open fun isReferenceToImportAlias(alias: KtImportAlias): Boolean = false
|
||||||
|
|
||||||
|
override fun isReferenceTo(candidateTarget: PsiElement): Boolean {
|
||||||
|
if (!canBeReferenceTo(candidateTarget)) return false
|
||||||
|
|
||||||
|
val unwrappedCandidate = candidateTarget.unwrapped?.originalElement ?: return false
|
||||||
|
|
||||||
|
// Optimizations to return early for cases where this reference cannot
|
||||||
|
// refer to the candidate target.
|
||||||
|
when (this) {
|
||||||
|
is KtInvokeFunctionReference -> {
|
||||||
|
if (candidateTarget !is KtNamedFunction && candidateTarget !is PsiMethod) return false
|
||||||
|
if ((candidateTarget as PsiNamedElement).name != OperatorNameConventions.INVOKE.asString()) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is KtDestructuringDeclarationReference -> {
|
||||||
|
if (candidateTarget !is KtNamedFunction && candidateTarget !is KtParameter && candidateTarget !is PsiMethod) return false
|
||||||
|
}
|
||||||
|
is KtSimpleNameReference -> {
|
||||||
|
if (unwrappedCandidate is PsiMethod && !canBePsiMethodReference()) return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val element = element
|
||||||
|
|
||||||
|
if (candidateTarget is KtImportAlias &&
|
||||||
|
(element is KtSimpleNameExpression && element.getReferencedName() == candidateTarget.name ||
|
||||||
|
this is KDocReference && this.canonicalText == candidateTarget.name)
|
||||||
|
) {
|
||||||
|
return isReferenceToImportAlias(candidateTarget)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (element is KtLabelReferenceExpression) {
|
||||||
|
when ((element.parent as? KtContainerNode)?.parent) {
|
||||||
|
is KtReturnExpression -> unwrappedTargets.forEach {
|
||||||
|
if (it !is KtFunctionLiteral && !(it is KtNamedFunction && it.name.isNullOrEmpty())) return@forEach
|
||||||
|
it as KtFunction
|
||||||
|
|
||||||
|
val labeledExpression = it.getLabeledParent(element.getReferencedName())
|
||||||
|
if (labeledExpression != null) {
|
||||||
|
if (candidateTarget == labeledExpression) return true else return@forEach
|
||||||
|
}
|
||||||
|
val calleeReference = it.getCalleeByLambdaArgument()?.mainReference ?: return@forEach
|
||||||
|
if (calleeReference.isReferenceTo(candidateTarget)) return true
|
||||||
|
}
|
||||||
|
is KtBreakExpression, is KtContinueExpression -> unwrappedTargets.forEach {
|
||||||
|
val labeledExpression = (it as? KtExpression)?.getLabeledParent(element.getReferencedName()) ?: return@forEach
|
||||||
|
if (candidateTarget == labeledExpression) return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val targets = unwrappedTargets
|
||||||
|
val manager = candidateTarget.manager
|
||||||
|
|
||||||
|
if (targets.any { manager.areElementsEquivalent(unwrappedCandidate, it) }) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return targets.any {
|
||||||
|
it.isConstructorOf(unwrappedCandidate) ||
|
||||||
|
it is KtObjectDeclaration && it.isCompanion() && it.getNonStrictParentOfType<KtClass>() == unwrappedCandidate
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun KtSimpleNameReference.canBePsiMethodReference(): Boolean {
|
||||||
|
// NOTE: Accessor references are handled separately, see SyntheticPropertyAccessorReference
|
||||||
|
if (element == (element.parent as? KtCallExpression)?.calleeExpression) return true
|
||||||
|
|
||||||
|
val callableReference = element.getParentOfTypeAndBranch<KtCallableReferenceExpression> { callableReference }
|
||||||
|
if (callableReference != null) return true
|
||||||
|
|
||||||
|
val binaryOperator = element.getParentOfTypeAndBranch<KtBinaryExpression> { operationReference }
|
||||||
|
if (binaryOperator != null) return true
|
||||||
|
|
||||||
|
val unaryOperator = element.getParentOfTypeAndBranch<KtUnaryExpression> { operationReference }
|
||||||
|
if (unaryOperator != null) return true
|
||||||
|
|
||||||
|
if (element.getNonStrictParentOfType<KtImportDirective>() != null) return true
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun PsiElement.isConstructorOf(unwrappedCandidate: PsiElement) =
|
||||||
|
when {
|
||||||
|
// call to Java constructor
|
||||||
|
this is PsiMethod && isConstructor && containingClass == unwrappedCandidate -> true
|
||||||
|
// call to Kotlin constructor
|
||||||
|
this is KtConstructor<*> && getContainingClassOrObject().isEquivalentTo(unwrappedCandidate) -> true
|
||||||
|
else -> false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class KtSimpleReference<T : KtReferenceExpression>(expression: T) : AbstractKtReference<T>(expression)
|
abstract class KtSimpleReference<T : KtReferenceExpression>(expression: T) : AbstractKtReference<T>(expression)
|
||||||
|
|
||||||
abstract class KtMultiReference<T : KtElement>(expression: T) : AbstractKtReference<T>(expression)
|
abstract class KtMultiReference<T : KtElement>(expression: T) : AbstractKtReference<T>(expression)
|
||||||
|
|||||||
+8
-1
@@ -16,7 +16,14 @@ import org.jetbrains.kotlin.psi.psiUtil.startOffset
|
|||||||
import org.jetbrains.kotlin.types.expressions.OperatorConventions
|
import org.jetbrains.kotlin.types.expressions.OperatorConventions
|
||||||
|
|
||||||
abstract class KtSimpleNameReference(expression: KtSimpleNameExpression) : KtSimpleReference<KtSimpleNameExpression>(expression) {
|
abstract class KtSimpleNameReference(expression: KtSimpleNameExpression) : KtSimpleReference<KtSimpleNameExpression>(expression) {
|
||||||
protected abstract fun doCanBeReferenceTo(candidateTarget: PsiElement): Boolean
|
// Extension point used by deprecated android extensions.
|
||||||
|
abstract fun isReferenceToViaExtension(element: PsiElement): Boolean
|
||||||
|
|
||||||
|
override fun isReferenceTo(candidateTarget: PsiElement): Boolean {
|
||||||
|
if (!canBeReferenceTo(candidateTarget)) return false
|
||||||
|
if (isReferenceToViaExtension(candidateTarget)) return true
|
||||||
|
return super.isReferenceTo(candidateTarget)
|
||||||
|
}
|
||||||
|
|
||||||
override fun getRangeInElement(): TextRange {
|
override fun getRangeInElement(): TextRange {
|
||||||
val element = element.getReferencedNameElement()
|
val element = element.getReferencedNameElement()
|
||||||
|
|||||||
-2
@@ -14,8 +14,6 @@ abstract class SyntheticPropertyAccessorReference(
|
|||||||
expression: KtNameReferenceExpression,
|
expression: KtNameReferenceExpression,
|
||||||
val getter: Boolean
|
val getter: Boolean
|
||||||
) : KtSimpleReference<KtNameReferenceExpression>(expression) {
|
) : KtSimpleReference<KtNameReferenceExpression>(expression) {
|
||||||
protected abstract fun additionalIsReferenceToChecker(element: PsiElement): Boolean
|
|
||||||
|
|
||||||
protected fun isAccessorName(name: String): Boolean {
|
protected fun isAccessorName(name: String): Boolean {
|
||||||
if (getter) {
|
if (getter) {
|
||||||
return name.startsWith("get") || name.startsWith("is")
|
return name.startsWith("get") || name.startsWith("is")
|
||||||
|
|||||||
@@ -5,10 +5,15 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.idea.references
|
package org.jetbrains.kotlin.idea.references
|
||||||
|
|
||||||
|
import com.intellij.psi.PsiElement
|
||||||
|
import com.intellij.psi.PsiMethod
|
||||||
|
import com.intellij.psi.PsiPolyVariantReference
|
||||||
|
import com.intellij.psi.PsiReference
|
||||||
|
import org.jetbrains.kotlin.asJava.unwrapped
|
||||||
import org.jetbrains.kotlin.kdoc.psi.impl.KDocName
|
import org.jetbrains.kotlin.kdoc.psi.impl.KDocName
|
||||||
import org.jetbrains.kotlin.psi.KtElement
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.KtReferenceExpression
|
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
|
||||||
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
|
import org.jetbrains.kotlin.psi.psiUtil.getParentOfTypeAndBranch
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance
|
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
|
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
|
||||||
|
|
||||||
@@ -27,3 +32,27 @@ val KtElement.mainReference: KtReference?
|
|||||||
is KDocName -> mainReference
|
is KDocName -> mainReference
|
||||||
else -> references.firstIsInstanceOrNull()
|
else -> references.firstIsInstanceOrNull()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Navigation element of the resolved reference
|
||||||
|
// For property accessor return enclosing property
|
||||||
|
val PsiReference.unwrappedTargets: Set<PsiElement>
|
||||||
|
get() {
|
||||||
|
fun PsiElement.adjust(): PsiElement? = when (val target = unwrapped?.originalElement) {
|
||||||
|
is KtPropertyAccessor -> target.getNonStrictParentOfType<KtProperty>()
|
||||||
|
else -> target
|
||||||
|
}
|
||||||
|
|
||||||
|
return when (this) {
|
||||||
|
is PsiPolyVariantReference -> multiResolve(false).mapNotNullTo(HashSet()) { it.element?.adjust() }
|
||||||
|
else -> listOfNotNull(resolve()?.adjust()).toSet()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun KtFunction.getCalleeByLambdaArgument(): KtSimpleNameExpression? {
|
||||||
|
val argument = getParentOfTypeAndBranch<KtValueArgument> { getArgumentExpression() } ?: return null
|
||||||
|
val callExpression = when (argument) {
|
||||||
|
is KtLambdaArgument -> argument.parent as? KtCallExpression
|
||||||
|
else -> (argument.parent as? KtValueArgumentList)?.parent as? KtCallExpression
|
||||||
|
} ?: return null
|
||||||
|
return callExpression.calleeExpression as? KtSimpleNameExpression
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user