Add analysis:kt-reference module and move KtReferences there.

This commit is contained in:
Mads Ager
2022-01-19 17:11:40 +01:00
committed by Ilya Kirillov
parent 5320a32d67
commit 6f0bb0eda5
20 changed files with 35 additions and 16 deletions
+2 -1
View File
@@ -9,6 +9,7 @@ dependencies {
implementation(project(":compiler:frontend.java"))
implementation(project(":analysis:analysis-api-impl-base"))
implementation(project(":analysis:analysis-internal-utils"))
implementation(project(":analysis:kt-reference"))
implementation(project(":compiler:backend"))
implementation(project(":compiler:backend.jvm"))
@@ -42,4 +43,4 @@ projectTest(jUnitMode = JUnitMode.JUnit5) {
useJUnitPlatform()
}
testsJar()
testsJar()
+1 -2
View File
@@ -21,6 +21,7 @@ dependencies {
api(intellijCore())
implementation(project(":analysis:analysis-api-providers"))
implementation(project(":analysis:analysis-internal-utils"))
implementation(project(":analysis:kt-reference"))
testApi(projectTests(":analysis:low-level-api-fir"))
testApi(projectTests(":compiler:tests-common"))
@@ -84,5 +85,3 @@ val generateCode by tasks.registering(NoDebugJavaExec::class) {
val compileKotlin by tasks
compileKotlin.dependsOn(generateCode)
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.analysis.api.fir.symbols.KtFirPackageSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtSymbol
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFir
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFirSafe
import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.builder.buildImport
import org.jetbrains.kotlin.fir.declarations.synthetic.FirSyntheticProperty
@@ -7,6 +7,7 @@ dependencies {
api(project(":compiler:psi"))
api(project(":analysis:analysis-api"))
api(project(":analysis:analysis-api-impl-barebone"))
api(project(":analysis:kt-reference"))
api(intellijCore())
implementation(project(":analysis:analysis-internal-utils"))
@@ -27,4 +28,4 @@ sourceSets {
"test" { projectDefault() }
}
testsJar()
testsJar()
+1
View File
@@ -17,6 +17,7 @@ dependencies {
compileOnly(project(":analysis:low-level-api-fir"))
implementation(project(":analysis:analysis-internal-utils"))
implementation(project(":analysis:analysis-api-providers"))
implementation(project(":analysis:kt-reference"))
api(intellijCore())
api(commonDependency("com.google.guava:guava"))
+16
View File
@@ -0,0 +1,16 @@
plugins {
kotlin("jvm")
id("jps-compatible")
}
dependencies {
implementation(project(":compiler:psi"))
implementation(intellijCore())
compileOnly(commonDependency("com.google.guava:guava"))
}
sourceSets {
"main" { projectDefault() }
"test" { none() }
}
@@ -0,0 +1,25 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.references
import com.intellij.openapi.util.TextRange
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.kdoc.psi.impl.KDocName
import org.jetbrains.kotlin.name.Name
abstract class KDocReference(element: KDocName) : KtMultiReference<KDocName>(element) {
override fun getRangeInElement(): TextRange = element.getNameTextRange()
override fun canRename(): Boolean = true
override fun resolve(): PsiElement? = multiResolve(false).firstOrNull()?.element
abstract override fun handleElementRename(newElementName: String): PsiElement?
override fun getCanonicalText(): String = element.getNameText()
override val resolvesByNames: Collection<Name> get() = listOf(Name.identifier(element.getNameText()))
}
@@ -0,0 +1,36 @@
/*
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.references
import com.intellij.psi.MultiRangeReference
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.lexer.KtToken
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtArrayAccessExpression
import org.jetbrains.kotlin.util.OperatorNameConventions
abstract class KtArrayAccessReference(
expression: KtArrayAccessExpression
) : KtSimpleReference<KtArrayAccessExpression>(expression), MultiRangeReference {
override val resolvesByNames: Collection<Name>
get() = NAMES
override fun getRangeInElement() = element.textRange.shiftRight(-element.textOffset)
private fun getBracketRange(bracketToken: KtToken) =
expression.indicesNode.node.findChildByType(bracketToken)?.textRange?.shiftRight(-expression.textOffset)
override fun getRanges() = listOfNotNull(getBracketRange(KtTokens.LBRACKET), getBracketRange(KtTokens.RBRACKET))
override fun canRename() = true
abstract override fun handleElementRename(newElementName: String): PsiElement?
companion object {
private val NAMES = listOf(OperatorNameConventions.GET, OperatorNameConventions.SET)
}
}
@@ -0,0 +1,31 @@
/*
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.references
import com.intellij.openapi.util.TextRange
import com.intellij.psi.MultiRangeReference
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.ArrayFqNames
abstract class KtCollectionLiteralReference(expression: KtCollectionLiteralExpression) :
KtSimpleReference<KtCollectionLiteralExpression>(expression), MultiRangeReference {
companion object {
private val COLLECTION_LITERAL_CALL_NAMES = ArrayFqNames.PRIMITIVE_TYPE_TO_ARRAY.values + ArrayFqNames.ARRAY_OF_FUNCTION
}
override fun getRangeInElement(): TextRange = element.normalizeRange()
override fun getRanges(): List<TextRange> {
return listOfNotNull(element.leftBracket?.normalizeRange(), element.rightBracket?.normalizeRange())
}
override val resolvesByNames: Collection<Name>
get() = COLLECTION_LITERAL_CALL_NAMES
private fun PsiElement.normalizeRange(): TextRange = this.textRange.shiftRight(-expression.textOffset)
}
@@ -0,0 +1,27 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.references
import com.intellij.openapi.util.TextRange
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.*
abstract class KtConstructorDelegationReference(
expression: KtConstructorDelegationReferenceExpression
) : KtSimpleReference<KtConstructorDelegationReferenceExpression>(expression) {
override fun getRangeInElement(): TextRange {
return TextRange(0, element.textLength)
}
override val resolvesByNames: Collection<Name>
get() = emptyList()
override fun handleElementRename(newElementName: String): PsiElement? {
// Class rename never affects this reference, so there is no need to fail with exception
return expression
}
}
@@ -0,0 +1,39 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.references
import com.intellij.openapi.util.TextRange
import com.intellij.psi.PsiElement
import com.intellij.util.IncorrectOperationException
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtDestructuringDeclaration
import org.jetbrains.kotlin.psi.KtDestructuringDeclarationEntry
import org.jetbrains.kotlin.idea.references.KtMultiReference
abstract class KtDestructuringDeclarationReference(
element: KtDestructuringDeclarationEntry
) : KtMultiReference<KtDestructuringDeclarationEntry>(element) {
override fun getRangeInElement() = TextRange(0, element.textLength)
abstract override fun canRename(): Boolean
override fun resolve() = multiResolve(false).asSequence()
.map { it.element }
.first { it is KtDestructuringDeclarationEntry }
override fun handleElementRename(newElementName: String): PsiElement? {
if (canRename()) return expression
throw IncorrectOperationException()
}
override val resolvesByNames: Collection<Name>
get() {
val destructuringParent = element.parent as? KtDestructuringDeclaration ?: return emptyList()
val componentIndex = destructuringParent.entries.indexOf(element) + 1
return listOf(Name.identifier("component$componentIndex"))
}
}
@@ -0,0 +1,31 @@
/*
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.references
import com.intellij.openapi.util.TextRange
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.util.OperatorNameConventions
abstract class KtForLoopInReference(element: KtForExpression) : KtMultiReference<KtForExpression>(element) {
override fun getRangeInElement(): TextRange {
val inKeyword = expression.inKeyword ?: return TextRange.EMPTY_RANGE
val offset = inKeyword.startOffsetInParent
return TextRange(offset, offset + inKeyword.textLength)
}
override val resolvesByNames: Collection<Name>
get() = NAMES
companion object {
private val NAMES = listOf(
OperatorNameConventions.ITERATOR,
OperatorNameConventions.NEXT,
OperatorNameConventions.HAS_NEXT
)
}
}
@@ -0,0 +1,91 @@
/*
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.references
import com.intellij.lang.ASTNode
import com.intellij.openapi.util.TextRange
import com.intellij.psi.MultiRangeReference
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedExpressionForSelectorOrThis
import org.jetbrains.kotlin.util.OperatorNameConventions
import java.util.*
abstract class KtInvokeFunctionReference(expression: KtCallExpression) : KtSimpleReference<KtCallExpression>(expression), MultiRangeReference {
override val resolvesByNames: Collection<Name> get() = NAMES
override fun getRangeInElement(): TextRange {
return element.textRange.shiftRight(-element.textOffset)
}
override fun getRanges(): List<TextRange> {
val list = ArrayList<TextRange>()
val valueArgumentList = expression.valueArgumentList
if (valueArgumentList != null) {
if (valueArgumentList.arguments.isNotEmpty()) {
val valueArgumentListNode = valueArgumentList.node
val lPar = valueArgumentListNode.findChildByType(KtTokens.LPAR)
if (lPar != null) {
list.add(getRange(lPar))
}
val rPar = valueArgumentListNode.findChildByType(KtTokens.RPAR)
if (rPar != null) {
list.add(getRange(rPar))
}
} else {
list.add(getRange(valueArgumentList.node))
}
}
val functionLiteralArguments = expression.lambdaArguments
for (functionLiteralArgument in functionLiteralArguments) {
val functionLiteralExpression = functionLiteralArgument.getLambdaExpression() ?: continue
list.add(getRange(functionLiteralExpression.leftCurlyBrace))
val rightCurlyBrace = functionLiteralExpression.rightCurlyBrace
if (rightCurlyBrace != null) {
list.add(getRange(rightCurlyBrace))
}
}
return list
}
private fun getRange(node: ASTNode): TextRange {
val textRange = node.textRange
return textRange.shiftRight(-expression.textOffset)
}
override fun canRename(): Boolean = true
override fun handleElementRename(newElementName: String): PsiElement? {
val callExpression = expression
val fullCallExpression = callExpression.getQualifiedExpressionForSelectorOrThis()
if (newElementName == OperatorNameConventions.GET.asString() && callExpression.typeArguments.isEmpty()) {
val arrayAccessExpression = KtPsiFactory(callExpression).buildExpression {
if (fullCallExpression is KtQualifiedExpression) {
appendExpression(fullCallExpression.receiverExpression)
appendFixedText(fullCallExpression.operationSign.value)
}
appendExpression(callExpression.calleeExpression)
appendFixedText("[")
appendExpressions(callExpression.valueArguments.map { it.getArgumentExpression() })
appendFixedText("]")
}
return fullCallExpression.replace(arrayAccessExpression)
}
return doRenameImplicitConventionalCall(newElementName)
}
protected abstract fun doRenameImplicitConventionalCall(newName: String?): KtExpression
companion object {
private val NAMES = listOf(OperatorNameConventions.INVOKE)
}
}
@@ -0,0 +1,29 @@
/*
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.references
import com.intellij.openapi.util.TextRange
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtPropertyDelegate
import org.jetbrains.kotlin.util.OperatorNameConventions
abstract class KtPropertyDelegationMethodsReference(element: KtPropertyDelegate) : KtMultiReference<KtPropertyDelegate>(element) {
override fun getRangeInElement(): TextRange {
val byKeywordNode = expression.byKeywordNode
val offset = byKeywordNode.psi!!.startOffsetInParent
return TextRange(offset, offset + byKeywordNode.textLength)
}
override val resolvesByNames: Collection<Name> get() = NAMES
companion object {
private val NAMES = listOf(
OperatorNameConventions.GET_VALUE,
OperatorNameConventions.SET_VALUE,
OperatorNameConventions.PROVIDE_DELEGATE
)
}
}
@@ -0,0 +1,47 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.references
import com.intellij.psi.*
import com.intellij.psi.impl.source.resolve.ResolveCache
import com.intellij.util.IncorrectOperationException
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtReferenceExpression
interface KtReference : PsiPolyVariantReference {
val resolver: ResolveCache.PolyVariantResolver<KtReference>
override fun getElement(): KtElement
val resolvesByNames: Collection<Name>
}
abstract class AbstractKtReference<T : KtElement>(element: T) : PsiPolyVariantReferenceBase<T>(element), KtReference {
val expression: T
get() = element
override fun multiResolve(incompleteCode: Boolean): Array<ResolveResult> =
ResolveCache.getInstance(expression.project).resolveWithCaching(this, resolver, false, incompleteCode)
override fun getCanonicalText(): String = "<TBD>"
open fun canRename(): Boolean = false
override fun handleElementRename(newElementName: String): PsiElement? = throw IncorrectOperationException()
override fun bindToElement(element: PsiElement): PsiElement = throw IncorrectOperationException()
@Suppress("UNCHECKED_CAST")
override fun getVariants(): Array<Any> = PsiReference.EMPTY_ARRAY as Array<Any>
override fun isSoft(): Boolean = false
override fun toString() = this::class.java.simpleName + ": " + expression.text
}
abstract class KtSimpleReference<T : KtReferenceExpression>(expression: T) : AbstractKtReference<T>(expression)
abstract class KtMultiReference<T : KtElement>(expression: T) : AbstractKtReference<T>(expression)
@@ -0,0 +1,82 @@
/*
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.references
import com.intellij.openapi.util.TextRange
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getParentOfTypeAndBranch
import org.jetbrains.kotlin.psi.psiUtil.startOffset
import org.jetbrains.kotlin.types.expressions.OperatorConventions
abstract class KtSimpleNameReference(expression: KtSimpleNameExpression) : KtSimpleReference<KtSimpleNameExpression>(expression) {
protected abstract fun doCanBeReferenceTo(candidateTarget: PsiElement): Boolean
override fun getRangeInElement(): TextRange {
val element = element.getReferencedNameElement()
val startOffset = getElement().startOffset
return element.textRange.shiftRight(-startOffset)
}
override fun canRename(): Boolean {
if (expression.getParentOfTypeAndBranch<KtWhenConditionInRange>(strict = true) { operationReference } != null) return false
val elementType = expression.getReferencedNameElementType()
if (elementType == KtTokens.PLUSPLUS || elementType == KtTokens.MINUSMINUS) return false
return true
}
abstract override fun handleElementRename(newElementName: String): PsiElement?
enum class ShorteningMode {
NO_SHORTENING,
DELAYED_SHORTENING,
FORCED_SHORTENING
}
// By default reference binding is delayed
override fun bindToElement(element: PsiElement): PsiElement =
bindToElement(element, ShorteningMode.DELAYED_SHORTENING)
abstract fun bindToElement(element: PsiElement, shorteningMode: ShorteningMode): PsiElement
abstract fun bindToFqName(
fqName: FqName,
shorteningMode: ShorteningMode = ShorteningMode.DELAYED_SHORTENING,
targetElement: PsiElement? = null
): PsiElement
override fun getCanonicalText(): String = expression.text
override val resolvesByNames: Collection<Name>
get() {
val element = element
if (element is KtOperationReferenceExpression) {
val tokenType = element.operationSignTokenType
if (tokenType != null) {
val name = OperatorConventions.getNameForOperationSymbol(
tokenType, element.parent is KtUnaryExpression, element.parent is KtBinaryExpression
) ?: return emptyList()
val counterpart = OperatorConventions.ASSIGNMENT_OPERATION_COUNTERPARTS[tokenType]
return if (counterpart != null) {
val counterpartName = OperatorConventions.getNameForOperationSymbol(counterpart, false, true)!!
listOf(name, counterpartName)
} else {
listOf(name)
}
}
}
return listOf(element.getReferencedNameAsName())
}
abstract fun getImportAlias(): KtImportAlias?
}
@@ -0,0 +1,34 @@
/*
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.references
import com.intellij.openapi.util.TextRange
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtNameReferenceExpression
abstract class SyntheticPropertyAccessorReference(
expression: KtNameReferenceExpression,
val getter: Boolean
) : KtSimpleReference<KtNameReferenceExpression>(expression) {
protected abstract fun additionalIsReferenceToChecker(element: PsiElement): Boolean
protected fun isAccessorName(name: String): Boolean {
if (getter) {
return name.startsWith("get") || name.startsWith("is")
}
return name.startsWith("set")
}
override fun getRangeInElement() = TextRange(0, expression.textLength)
override fun canRename() = true
abstract override fun handleElementRename(newElementName: String): PsiElement?
override val resolvesByNames: Collection<Name>
get() = listOf(element.getReferencedNameAsName())
}
@@ -0,0 +1,29 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.references
import org.jetbrains.kotlin.kdoc.psi.impl.KDocName
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtReferenceExpression
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
val KtSimpleNameExpression.mainReference: KtSimpleNameReference
get() = references.firstIsInstance()
val KtReferenceExpression.mainReference: KtReference
get() = if (this is KtSimpleNameExpression) mainReference else references.firstIsInstance()
val KDocName.mainReference: KDocReference
get() = references.firstIsInstance()
val KtElement.mainReference: KtReference?
get() = when (this) {
is KtReferenceExpression -> mainReference
is KDocName -> mainReference
else -> references.firstIsInstanceOrNull()
}