FIR IDE: Make KtReference class descriptors frontend independent
* The new idea-frontend-independent module created * Moved KtReference and it inheritors to that module & implement them in idea-analysis module by using descriptors frontend
This commit is contained in:
@@ -1,17 +1,6 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* Copyright 2010-2020 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.kdoc
|
||||
@@ -20,6 +9,7 @@ import com.intellij.openapi.util.TextRange
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
||||
import org.jetbrains.kotlin.idea.references.KtDescriptorsBasedReference
|
||||
import org.jetbrains.kotlin.idea.references.KtMultiReference
|
||||
import org.jetbrains.kotlin.kdoc.psi.impl.KDocLink
|
||||
import org.jetbrains.kotlin.kdoc.psi.impl.KDocName
|
||||
@@ -28,7 +18,11 @@ import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||
|
||||
class KDocReference(element: KDocName) : KtMultiReference<KDocName>(element) {
|
||||
//TODO move to frontend-independent module
|
||||
class KDocReference(element: KDocName) : KtMultiReference<KDocName>(element), KtDescriptorsBasedReference {
|
||||
override fun isReferenceTo(element: PsiElement): Boolean =
|
||||
super<KtDescriptorsBasedReference>.isReferenceTo(element)
|
||||
|
||||
override fun getTargetDescriptors(context: BindingContext): Collection<DeclarationDescriptor> {
|
||||
val declaration = element.getContainingDoc().getOwner() ?: return arrayListOf()
|
||||
val resolutionFacade = element.getResolutionFacade()
|
||||
|
||||
+164
@@ -0,0 +1,164 @@
|
||||
/*
|
||||
* Copyright 2010-2020 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.PsiElement
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.expressions.*
|
||||
import org.jetbrains.kotlin.fir.psi
|
||||
import org.jetbrains.kotlin.fir.references.*
|
||||
import org.jetbrains.kotlin.fir.resolve.firSymbolProvider
|
||||
import org.jetbrains.kotlin.fir.resolve.toSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.ConeClassLikeLookupTagImpl
|
||||
import org.jetbrains.kotlin.fir.types.ConeLookupTagBasedType
|
||||
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
|
||||
import org.jetbrains.kotlin.idea.fir.firResolveState
|
||||
import org.jetbrains.kotlin.idea.fir.getOrBuildFir
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.psi.KtDotQualifiedExpression
|
||||
import org.jetbrains.kotlin.psi.KtElement
|
||||
import org.jetbrains.kotlin.psi.KtPackageDirective
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
|
||||
|
||||
object FirReferenceResolveHelper {
|
||||
fun FirResolvedTypeRef.toTargetPsi(session: FirSession): PsiElement? {
|
||||
val type = type as? ConeLookupTagBasedType ?: return null
|
||||
return (type.lookupTag.toSymbol(session) as? AbstractFirBasedSymbol<*>)?.fir?.psi
|
||||
}
|
||||
|
||||
fun ClassId.toTargetPsi(session: FirSession, calleeReference: FirReference? = null): PsiElement? {
|
||||
val classLikeDeclaration = ConeClassLikeLookupTagImpl(this).toSymbol(session)?.fir
|
||||
if (classLikeDeclaration is FirRegularClass) {
|
||||
if (calleeReference is FirResolvedNamedReference) {
|
||||
val callee = calleeReference.resolvedSymbol.fir as? FirCallableMemberDeclaration
|
||||
// TODO: check callee owner directly?
|
||||
if (callee !is FirConstructor && callee?.isStatic != true) {
|
||||
classLikeDeclaration.companionObject?.let { return it.psi }
|
||||
}
|
||||
}
|
||||
}
|
||||
return classLikeDeclaration?.psi
|
||||
}
|
||||
|
||||
fun FirReference.toTargetPsi(session: FirSession): PsiElement? {
|
||||
return when (this) {
|
||||
is FirResolvedNamedReference -> {
|
||||
resolvedSymbol.fir.psi
|
||||
}
|
||||
is FirResolvedCallableReference -> {
|
||||
resolvedSymbol.fir.psi
|
||||
}
|
||||
is FirThisReference -> {
|
||||
boundSymbol?.fir?.psi
|
||||
}
|
||||
is FirSuperReference -> {
|
||||
(superTypeRef as? FirResolvedTypeRef)?.toTargetPsi(session)
|
||||
}
|
||||
else -> {
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun resolveToPsiElements(ref: AbstractKtReference<KtElement>): Collection<PsiElement> {
|
||||
val expression = ref.expression
|
||||
val state = expression.firResolveState()
|
||||
val session = state.getSession(expression)
|
||||
when (val fir = expression.getOrBuildFir(state)) {
|
||||
is FirResolvable -> {
|
||||
return listOfNotNull(fir.calleeReference.toTargetPsi(session))
|
||||
}
|
||||
is FirResolvedTypeRef -> {
|
||||
return listOfNotNull(fir.toTargetPsi(session))
|
||||
}
|
||||
is FirResolvedQualifier -> {
|
||||
val classId = fir.classId ?: return emptyList()
|
||||
// Distinguish A.foo() from A(.Companion).foo()
|
||||
// Make expression.parent as? KtDotQualifiedExpression local function
|
||||
var parent = expression.parent as? KtDotQualifiedExpression
|
||||
while (parent != null) {
|
||||
val selectorExpression = parent.selectorExpression ?: break
|
||||
if (selectorExpression === expression) {
|
||||
parent = parent.parent as? KtDotQualifiedExpression
|
||||
continue
|
||||
}
|
||||
val parentFir = selectorExpression.getOrBuildFir(state)
|
||||
if (parentFir is FirQualifiedAccess) {
|
||||
return listOfNotNull(classId.toTargetPsi(session, parentFir.calleeReference))
|
||||
}
|
||||
parent = parent.parent as? KtDotQualifiedExpression
|
||||
}
|
||||
return listOfNotNull(classId.toTargetPsi(session))
|
||||
}
|
||||
is FirAnnotationCall -> {
|
||||
val type = fir.typeRef as? FirResolvedTypeRef ?: return emptyList()
|
||||
return listOfNotNull(type.toTargetPsi(session))
|
||||
}
|
||||
is FirResolvedImport -> {
|
||||
var parent = expression.parent
|
||||
while (parent is KtDotQualifiedExpression) {
|
||||
if (parent.selectorExpression !== expression) {
|
||||
// Special: package reference in the middle of import directive
|
||||
// import a.<caret>b.c.SomeClass
|
||||
// TODO: return reference to PsiPackage
|
||||
return listOf(expression)
|
||||
}
|
||||
parent = parent.parent
|
||||
}
|
||||
val classId = fir.resolvedClassId
|
||||
if (classId != null) {
|
||||
return listOfNotNull(classId.toTargetPsi(session))
|
||||
}
|
||||
val name = fir.importedName ?: return emptyList()
|
||||
val symbolProvider = session.firSymbolProvider
|
||||
return symbolProvider.getTopLevelCallableSymbols(fir.packageFqName, name).mapNotNull { it.fir.psi } +
|
||||
listOfNotNull(symbolProvider.getClassLikeSymbolByFqName(ClassId(fir.packageFqName, name))?.fir?.psi)
|
||||
}
|
||||
is FirFile -> {
|
||||
if (expression.getNonStrictParentOfType<KtPackageDirective>() != null) {
|
||||
// Special: package reference in the middle of package directive
|
||||
return listOf(expression)
|
||||
}
|
||||
return listOfNotNull(fir.psi)
|
||||
}
|
||||
is FirArrayOfCall -> {
|
||||
// We can't yet find PsiElement for arrayOf, intArrayOf, etc.
|
||||
return emptyList()
|
||||
}
|
||||
is FirErrorNamedReference -> {
|
||||
return emptyList()
|
||||
}
|
||||
else -> {
|
||||
// Handle situation when we're in the middle/beginning of qualifier
|
||||
// <caret>A.B.C.foo() or A.<caret>B.C.foo()
|
||||
// NB: in this case we get some parent FIR, like FirBlock, FirProperty, FirFunction or the like
|
||||
var parent = expression.parent as? KtDotQualifiedExpression
|
||||
var unresolvedCounter = 1
|
||||
while (parent != null) {
|
||||
val selectorExpression = parent.selectorExpression ?: break
|
||||
if (selectorExpression === expression) {
|
||||
parent = parent.parent as? KtDotQualifiedExpression
|
||||
continue
|
||||
}
|
||||
val parentFir = selectorExpression.getOrBuildFir(state)
|
||||
if (parentFir is FirResolvedQualifier) {
|
||||
var classId = parentFir.classId
|
||||
while (unresolvedCounter > 0) {
|
||||
unresolvedCounter--
|
||||
classId = classId?.outerClassId
|
||||
}
|
||||
return listOfNotNull(classId?.toTargetPsi(session))
|
||||
}
|
||||
parent = parent.parent as? KtDotQualifiedExpression
|
||||
unresolvedCounter++
|
||||
}
|
||||
return emptyList()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+7
-11
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Copyright 2010-2020 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.
|
||||
*/
|
||||
|
||||
@@ -66,14 +66,10 @@ class ReferenceImpl(private val argument: KtValueArgument) : PsiReference {
|
||||
override fun isSoft() = false
|
||||
}
|
||||
|
||||
internal class KotlinDefaultAnnotationMethodImplicitReferenceContributor : KotlinReferenceProviderContributor {
|
||||
override fun registerReferenceProviders(registrar: KotlinPsiReferenceRegistrar) {
|
||||
registrar.registerProvider<KtValueArgument> {
|
||||
if (it.isNamed()) return@registerProvider null
|
||||
val annotationEntry = it.getParentOfTypeAndBranch<KtAnnotationEntry> { valueArgumentList } ?: return@registerProvider null
|
||||
if (annotationEntry.valueArguments.size != 1) return@registerProvider null
|
||||
internal val KotlinDefaultAnnotationMethodImplicitReferenceProvider = provider@{ element: KtValueArgument ->
|
||||
if (element.isNamed()) return@provider null
|
||||
val annotationEntry = element.getParentOfTypeAndBranch<KtAnnotationEntry> { valueArgumentList } ?: return@provider null
|
||||
if (annotationEntry.valueArguments.size != 1) return@provider null
|
||||
|
||||
ReferenceImpl(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
ReferenceImpl(element)
|
||||
}
|
||||
+17
-26
@@ -1,17 +1,6 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* Copyright 2010-2020 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
|
||||
@@ -24,10 +13,10 @@ import org.jetbrains.kotlin.psi.KtPackageDirective
|
||||
import org.jetbrains.kotlin.psi.KtUserType
|
||||
import org.jetbrains.kotlin.psi.psiUtil.parents
|
||||
|
||||
internal class KotlinReferenceContributor : KotlinReferenceProviderContributor {
|
||||
class KotlinReferenceContributor : KotlinReferenceProviderContributor {
|
||||
override fun registerReferenceProviders(registrar: KotlinPsiReferenceRegistrar) {
|
||||
with(registrar) {
|
||||
registerProvider(factory = ::KtSimpleNameReference)
|
||||
registerProvider(factory = ::KtSimpleNameReferenceDescriptorsImpl)
|
||||
|
||||
registerMultiProvider<KtNameReferenceExpression> { nameReferenceExpression ->
|
||||
if (nameReferenceExpression.getReferencedNameElementType() != KtTokens.IDENTIFIER) return@registerMultiProvider emptyArray()
|
||||
@@ -37,32 +26,34 @@ internal class KotlinReferenceContributor : KotlinReferenceProviderContributor {
|
||||
|
||||
when (nameReferenceExpression.readWriteAccess(useResolveForReadWrite = false)) {
|
||||
ReferenceAccess.READ ->
|
||||
arrayOf(SyntheticPropertyAccessorReference.Getter(nameReferenceExpression))
|
||||
arrayOf(SyntheticPropertyAccessorReferenceDescriptorImpl(nameReferenceExpression, getter = true))
|
||||
ReferenceAccess.WRITE ->
|
||||
arrayOf(SyntheticPropertyAccessorReference.Setter(nameReferenceExpression))
|
||||
arrayOf(SyntheticPropertyAccessorReferenceDescriptorImpl(nameReferenceExpression, getter = false))
|
||||
ReferenceAccess.READ_WRITE ->
|
||||
arrayOf(
|
||||
SyntheticPropertyAccessorReference.Getter(nameReferenceExpression),
|
||||
SyntheticPropertyAccessorReference.Setter(nameReferenceExpression)
|
||||
SyntheticPropertyAccessorReferenceDescriptorImpl(nameReferenceExpression, getter = true),
|
||||
SyntheticPropertyAccessorReferenceDescriptorImpl(nameReferenceExpression, getter = false)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
registerProvider(factory = ::KtConstructorDelegationReference)
|
||||
registerProvider(factory = ::KtConstructorDelegationReferenceDescriptorsImpl)
|
||||
|
||||
registerProvider(factory = ::KtInvokeFunctionReference)
|
||||
registerProvider(factory = ::KtInvokeFunctionReferenceDescriptorsImpl)
|
||||
|
||||
registerProvider(factory = ::KtArrayAccessReference)
|
||||
registerProvider(factory = ::KtArrayAccessReferenceDescriptorsImpl)
|
||||
|
||||
registerProvider(factory = ::KtCollectionLiteralReference)
|
||||
registerProvider(factory = ::KtCollectionLiteralReferenceDescriptorsImpl)
|
||||
|
||||
registerProvider(factory = ::KtForLoopInReference)
|
||||
registerProvider(factory = ::KtForLoopInReferenceDescriptorsImpl)
|
||||
|
||||
registerProvider(factory = ::KtPropertyDelegationMethodsReference)
|
||||
registerProvider(factory = ::KtPropertyDelegationMethodsReferenceDescriptorsImpl)
|
||||
|
||||
registerProvider(factory = ::KtDestructuringDeclarationReference)
|
||||
registerProvider(factory = ::KtDestructuringDeclarationReferenceDescriptorsImpl)
|
||||
|
||||
registerProvider(factory = ::KDocReference)
|
||||
|
||||
registerProvider(KotlinDefaultAnnotationMethodImplicitReferenceProvider)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,80 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2019 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.google.common.collect.Lists
|
||||
import com.intellij.psi.MultiRangeReference
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.idea.core.canMoveLambdaOutsideParentheses
|
||||
import org.jetbrains.kotlin.idea.core.moveFunctionLiteralOutsideParentheses
|
||||
import org.jetbrains.kotlin.idea.core.replaced
|
||||
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.psi.KtPsiFactory
|
||||
import org.jetbrains.kotlin.psi.KtQualifiedExpression
|
||||
import org.jetbrains.kotlin.psi.buildExpression
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getPossiblyQualifiedCallExpression
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.BindingContext.INDEXED_LVALUE_GET
|
||||
import org.jetbrains.kotlin.resolve.BindingContext.INDEXED_LVALUE_SET
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
|
||||
class KtArrayAccessReference(
|
||||
expression: KtArrayAccessExpression
|
||||
) : KtSimpleReference<KtArrayAccessExpression>(expression), MultiRangeReference {
|
||||
override val resolvesByNames: Collection<Name>
|
||||
get() = NAMES
|
||||
|
||||
override fun getRangeInElement() = element.textRange.shiftRight(-element.textOffset)
|
||||
|
||||
override fun getTargetDescriptors(context: BindingContext): Collection<DeclarationDescriptor> {
|
||||
val getFunctionDescriptor = context[INDEXED_LVALUE_GET, expression]?.candidateDescriptor
|
||||
val setFunctionDescriptor = context[INDEXED_LVALUE_SET, expression]?.candidateDescriptor
|
||||
return listOfNotNull(getFunctionDescriptor, setFunctionDescriptor)
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
override fun handleElementRename(newElementName: String): PsiElement? {
|
||||
val arrayAccessExpression = expression
|
||||
if (OperatorNameConventions.INVOKE.asString() == newElementName) {
|
||||
val replacement = KtPsiFactory(arrayAccessExpression.project).buildExpression {
|
||||
val arrayExpression = arrayAccessExpression.arrayExpression
|
||||
if (arrayExpression is KtQualifiedExpression) {
|
||||
appendExpression(arrayExpression.receiverExpression)
|
||||
appendFixedText(arrayExpression.operationSign.value)
|
||||
appendExpression(arrayExpression.selectorExpression)
|
||||
} else {
|
||||
appendExpression(arrayExpression)
|
||||
}
|
||||
|
||||
appendFixedText("(")
|
||||
appendExpressions(arrayAccessExpression.indexExpressions, ",")
|
||||
appendFixedText(")")
|
||||
}
|
||||
val fullCallExpression = arrayAccessExpression.replaced(replacement)
|
||||
val callExpression = fullCallExpression.getPossiblyQualifiedCallExpression()
|
||||
if (callExpression != null && callExpression.canMoveLambdaOutsideParentheses()) {
|
||||
callExpression.moveFunctionLiteralOutsideParentheses()
|
||||
}
|
||||
return fullCallExpression
|
||||
}
|
||||
|
||||
return this.renameImplicitConventionalCall(newElementName)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val NAMES = Lists.newArrayList(OperatorNameConventions.GET, OperatorNameConventions.SET)
|
||||
}
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2010-2020 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.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.idea.core.canMoveLambdaOutsideParentheses
|
||||
import org.jetbrains.kotlin.idea.core.moveFunctionLiteralOutsideParentheses
|
||||
import org.jetbrains.kotlin.psi.KtArrayAccessExpression
|
||||
import org.jetbrains.kotlin.psi.KtCallExpression
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.BindingContext.INDEXED_LVALUE_GET
|
||||
import org.jetbrains.kotlin.resolve.BindingContext.INDEXED_LVALUE_SET
|
||||
|
||||
internal class KtArrayAccessReferenceDescriptorsImpl(
|
||||
expression: KtArrayAccessExpression
|
||||
) : KtArrayAccessReference(expression), KtDescriptorsBasedReference {
|
||||
override fun isReferenceTo(element: PsiElement): Boolean =
|
||||
super<KtDescriptorsBasedReference>.isReferenceTo(element)
|
||||
|
||||
override fun moveFunctionLiteralOutsideParentheses(callExpression: KtCallExpression) {
|
||||
callExpression.moveFunctionLiteralOutsideParentheses()
|
||||
}
|
||||
|
||||
override fun canMoveLambdaOutsideParentheses(callExpression: KtCallExpression): Boolean =
|
||||
callExpression.canMoveLambdaOutsideParentheses()
|
||||
|
||||
override fun doRenameImplicitConventionalCall(newName: String?): KtExpression =
|
||||
renameImplicitConventionalCall(newName)
|
||||
|
||||
override fun getTargetDescriptors(context: BindingContext): Collection<DeclarationDescriptor> {
|
||||
val getFunctionDescriptor = context[INDEXED_LVALUE_GET, expression]?.candidateDescriptor
|
||||
val setFunctionDescriptor = context[INDEXED_LVALUE_SET, expression]?.candidateDescriptor
|
||||
return listOfNotNull(getFunctionDescriptor, setFunctionDescriptor)
|
||||
}
|
||||
}
|
||||
-39
@@ -1,39 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2019 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.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.KtCollectionLiteralExpression
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.CollectionLiteralResolver
|
||||
|
||||
class KtCollectionLiteralReference(expression: KtCollectionLiteralExpression) :
|
||||
KtSimpleReference<KtCollectionLiteralExpression>(expression), MultiRangeReference {
|
||||
companion object {
|
||||
private val COLLECTION_LITERAL_CALL_NAMES =
|
||||
CollectionLiteralResolver.PRIMITIVE_TYPE_TO_ARRAY.values + CollectionLiteralResolver.ARRAY_OF_FUNCTION
|
||||
}
|
||||
|
||||
override fun getRangeInElement(): TextRange = element.normalizeRange()
|
||||
|
||||
override fun getTargetDescriptors(context: BindingContext): Collection<DeclarationDescriptor> {
|
||||
val resolvedCall = context[BindingContext.COLLECTION_LITERAL_CALL, element]
|
||||
return listOfNotNull(resolvedCall?.resultingDescriptor)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright 2010-2020 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.PsiElement
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.psi.KtCollectionLiteralExpression
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
|
||||
class KtCollectionLiteralReferenceDescriptorsImpl(
|
||||
expression: KtCollectionLiteralExpression
|
||||
) : KtCollectionLiteralReference(expression), KtDescriptorsBasedReference {
|
||||
override fun isReferenceTo(element: PsiElement): Boolean =
|
||||
super<KtDescriptorsBasedReference>.isReferenceTo(element)
|
||||
|
||||
override fun getTargetDescriptors(context: BindingContext): Collection<DeclarationDescriptor> {
|
||||
val resolvedCall = context[BindingContext.COLLECTION_LITERAL_CALL, element]
|
||||
return listOfNotNull(resolvedCall?.resultingDescriptor)
|
||||
}
|
||||
}
|
||||
-51
@@ -1,51 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.references;
|
||||
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.name.Name;
|
||||
import org.jetbrains.kotlin.psi.KtConstructorDelegationReferenceExpression;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
public class KtConstructorDelegationReference extends KtSimpleReference<KtConstructorDelegationReferenceExpression> {
|
||||
public KtConstructorDelegationReference(KtConstructorDelegationReferenceExpression expression) {
|
||||
super(expression);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextRange getRangeInElement() {
|
||||
return new TextRange(0, getElement().getTextLength());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Collection<Name> getResolvesByNames() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public PsiElement handleElementRename(@Nullable String newElementName) {
|
||||
// Class rename never affects this reference, so there is no need to fail with exception
|
||||
return getExpression();
|
||||
}
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2010-2020 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.PsiElement
|
||||
import org.jetbrains.kotlin.psi.KtConstructorDelegationReferenceExpression
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.bindingContextUtil.getReferenceTargets
|
||||
|
||||
class KtConstructorDelegationReferenceDescriptorsImpl(
|
||||
expression: KtConstructorDelegationReferenceExpression
|
||||
) : KtConstructorDelegationReference(expression), KtDescriptorsBasedReference {
|
||||
|
||||
override fun isReferenceTo(element: PsiElement): Boolean =
|
||||
super<KtDescriptorsBasedReference>.isReferenceTo(element)
|
||||
|
||||
override fun getTargetDescriptors(context: BindingContext) = expression.getReferenceTargets(context)
|
||||
}
|
||||
+7
-15
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Copyright 2010-2020 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.
|
||||
*/
|
||||
|
||||
@@ -16,8 +16,12 @@ import org.jetbrains.kotlin.psi.KtDestructuringDeclaration
|
||||
import org.jetbrains.kotlin.psi.KtDestructuringDeclarationEntry
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
|
||||
class KtDestructuringDeclarationReference(element: KtDestructuringDeclarationEntry) :
|
||||
AbstractKtReference<KtDestructuringDeclarationEntry>(element) {
|
||||
class KtDestructuringDeclarationReferenceDescriptorsImpl(
|
||||
element: KtDestructuringDeclarationEntry
|
||||
) : KtDestructuringDeclarationReference(element), KtDescriptorsBasedReference {
|
||||
override fun isReferenceTo(element: PsiElement): Boolean =
|
||||
super<KtDescriptorsBasedReference>.isReferenceTo(element)
|
||||
|
||||
override fun getTargetDescriptors(context: BindingContext): Collection<DeclarationDescriptor> {
|
||||
return listOfNotNull(context[BindingContext.COMPONENT_RESOLVED_CALL, element]?.candidateDescriptor)
|
||||
}
|
||||
@@ -30,16 +34,4 @@ class KtDestructuringDeclarationReference(element: KtDestructuringDeclarationEnt
|
||||
it is CallableMemberDescriptor && it.kind == CallableMemberDescriptor.Kind.SYNTHESIZED
|
||||
}
|
||||
}
|
||||
|
||||
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"))
|
||||
}
|
||||
}
|
||||
+7
-18
@@ -1,45 +1,34 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Copyright 2010-2020 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.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.KtForExpression
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
|
||||
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)
|
||||
}
|
||||
class KtForLoopInReferenceDescriptorsImpl(
|
||||
element: KtForExpression
|
||||
) : KtForLoopInReference(element), KtDescriptorsBasedReference {
|
||||
override fun isReferenceTo(element: PsiElement): Boolean =
|
||||
super<KtDescriptorsBasedReference>.isReferenceTo(element)
|
||||
|
||||
override fun getTargetDescriptors(context: BindingContext): Collection<DeclarationDescriptor> {
|
||||
val loopRange = expression.loopRange ?: return emptyList()
|
||||
return LOOP_RANGE_KEYS.mapNotNull { key -> context.get(key, loopRange)?.candidateDescriptor }
|
||||
}
|
||||
|
||||
override val resolvesByNames: Collection<Name>
|
||||
get() = NAMES
|
||||
|
||||
companion object {
|
||||
private val LOOP_RANGE_KEYS = arrayOf(
|
||||
BindingContext.LOOP_RANGE_ITERATOR_RESOLVED_CALL,
|
||||
BindingContext.LOOP_RANGE_NEXT_RESOLVED_CALL,
|
||||
BindingContext.LOOP_RANGE_HAS_NEXT_RESOLVED_CALL
|
||||
)
|
||||
|
||||
private val NAMES = listOf(
|
||||
OperatorNameConventions.ITERATOR,
|
||||
OperatorNameConventions.NEXT,
|
||||
OperatorNameConventions.HAS_NEXT
|
||||
)
|
||||
}
|
||||
}
|
||||
-111
@@ -1,111 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. 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.project.IndexNotReadyException
|
||||
import com.intellij.psi.ContributedReferenceHost
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiReference
|
||||
import com.intellij.psi.PsiReferenceService
|
||||
import com.intellij.psi.impl.source.resolve.reference.ReferenceProvidersRegistry
|
||||
import com.intellij.psi.util.CachedValueProvider
|
||||
import com.intellij.psi.util.CachedValuesManager
|
||||
import com.intellij.psi.util.PsiModificationTracker
|
||||
import com.intellij.util.containers.ConcurrentFactoryMap
|
||||
import com.intellij.util.containers.ContainerUtil
|
||||
import com.intellij.util.containers.MultiMap
|
||||
import org.jetbrains.kotlin.psi.KotlinReferenceProvidersService
|
||||
import org.jetbrains.kotlin.psi.KtElement
|
||||
import org.jetbrains.kotlin.utils.SmartList
|
||||
|
||||
internal interface KotlinPsiReferenceProvider {
|
||||
fun getReferencesByElement(element: PsiElement): Array<PsiReference>
|
||||
}
|
||||
|
||||
internal interface KotlinReferenceProviderContributor {
|
||||
fun registerReferenceProviders(registrar: KotlinPsiReferenceRegistrar)
|
||||
}
|
||||
|
||||
internal class KotlinPsiReferenceRegistrar {
|
||||
val providers: MultiMap<Class<out PsiElement>, KotlinPsiReferenceProvider> = MultiMap.create()
|
||||
|
||||
inline fun <reified E : KtElement> registerProvider(crossinline factory: (E) -> PsiReference?) {
|
||||
registerMultiProvider<E> { element ->
|
||||
factory(element)?.let { reference -> arrayOf(reference) } ?: PsiReference.EMPTY_ARRAY
|
||||
}
|
||||
}
|
||||
|
||||
inline fun <reified E : KtElement> registerMultiProvider(crossinline factory: (E) -> Array<PsiReference>) {
|
||||
val provider: KotlinPsiReferenceProvider = object : KotlinPsiReferenceProvider {
|
||||
override fun getReferencesByElement(element: PsiElement): Array<PsiReference> {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return factory(element as E)
|
||||
}
|
||||
}
|
||||
|
||||
registerMultiProvider(E::class.java, provider)
|
||||
}
|
||||
|
||||
fun registerMultiProvider(klass: Class<out PsiElement>, provider: KotlinPsiReferenceProvider) {
|
||||
providers.putValue(klass, provider)
|
||||
}
|
||||
}
|
||||
|
||||
class KtIdeReferenceProviderService : KotlinReferenceProvidersService() {
|
||||
private val originalProvidersBinding: MultiMap<Class<out PsiElement>, KotlinPsiReferenceProvider>
|
||||
private val providersBindingCache: Map<Class<out PsiElement>, List<KotlinPsiReferenceProvider>>
|
||||
|
||||
private val referenceContributors = listOf(KotlinReferenceContributor(), KotlinDefaultAnnotationMethodImplicitReferenceContributor())
|
||||
|
||||
init {
|
||||
val registrar = KotlinPsiReferenceRegistrar()
|
||||
referenceContributors.forEach { it.registerReferenceProviders(registrar) }
|
||||
originalProvidersBinding = registrar.providers
|
||||
|
||||
providersBindingCache = ConcurrentFactoryMap.createMap<Class<out PsiElement>, List<KotlinPsiReferenceProvider>> { klass ->
|
||||
val result = ContainerUtil.newSmartList<KotlinPsiReferenceProvider>()
|
||||
for (bindingClass in originalProvidersBinding.keySet()) {
|
||||
if (bindingClass.isAssignableFrom(klass)) {
|
||||
result.addAll(originalProvidersBinding.get(bindingClass))
|
||||
}
|
||||
}
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
private fun doGetKotlinReferencesFromProviders(context: PsiElement): Array<PsiReference> {
|
||||
val providers: List<KotlinPsiReferenceProvider>? = providersBindingCache[context.javaClass]
|
||||
if (providers.isNullOrEmpty()) return PsiReference.EMPTY_ARRAY
|
||||
|
||||
val result = SmartList<PsiReference>()
|
||||
for (provider in providers) {
|
||||
try {
|
||||
result.addAll(provider.getReferencesByElement(context))
|
||||
} catch (ignored: IndexNotReadyException) {
|
||||
// Ignore and continue to next provider
|
||||
}
|
||||
}
|
||||
|
||||
if (result.isEmpty()) {
|
||||
return PsiReference.EMPTY_ARRAY
|
||||
}
|
||||
|
||||
return result.toTypedArray()
|
||||
}
|
||||
|
||||
override fun getReferences(psiElement: PsiElement): Array<PsiReference> {
|
||||
if (psiElement is ContributedReferenceHost) {
|
||||
return ReferenceProvidersRegistry.getReferencesFromProviders(psiElement, PsiReferenceService.Hints.NO_HINTS)
|
||||
}
|
||||
|
||||
return CachedValuesManager.getCachedValue(psiElement) {
|
||||
CachedValueProvider.Result.create(
|
||||
doGetKotlinReferencesFromProviders(psiElement),
|
||||
PsiModificationTracker.MODIFICATION_COUNT
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
-121
@@ -1,121 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
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.descriptors.DeclarationDescriptor
|
||||
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.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getCall
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
import java.util.*
|
||||
|
||||
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 getTargetDescriptors(context: BindingContext): Collection<DeclarationDescriptor> {
|
||||
val call = element.getCall(context)
|
||||
val resolvedCall = call.getResolvedCall(context)
|
||||
return when {
|
||||
resolvedCall is VariableAsFunctionResolvedCall ->
|
||||
setOf<DeclarationDescriptor>((resolvedCall as VariableAsFunctionResolvedCall).functionCall.candidateDescriptor)
|
||||
call != null && resolvedCall != null && call.callType == Call.CallType.INVOKE ->
|
||||
setOf<DeclarationDescriptor>(resolvedCall.candidateDescriptor)
|
||||
else ->
|
||||
emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
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 renameImplicitConventionalCall(newElementName)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
private val NAMES = listOf(OperatorNameConventions.INVOKE)
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2010-2020 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.PsiElement
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.psi.Call
|
||||
import org.jetbrains.kotlin.psi.KtCallExpression
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getCall
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall
|
||||
|
||||
class KtInvokeFunctionReferenceDescriptorsImpl(expression: KtCallExpression) : KtInvokeFunctionReference(expression), KtDescriptorsBasedReference {
|
||||
override fun isReferenceTo(element: PsiElement): Boolean =
|
||||
super<KtDescriptorsBasedReference>.isReferenceTo(element)
|
||||
|
||||
|
||||
override fun getTargetDescriptors(context: BindingContext): Collection<DeclarationDescriptor> {
|
||||
val call = element.getCall(context)
|
||||
val resolvedCall = call.getResolvedCall(context)
|
||||
return when {
|
||||
resolvedCall is VariableAsFunctionResolvedCall ->
|
||||
setOf<DeclarationDescriptor>((resolvedCall as VariableAsFunctionResolvedCall).functionCall.candidateDescriptor)
|
||||
call != null && resolvedCall != null && call.callType == Call.CallType.INVOKE ->
|
||||
setOf<DeclarationDescriptor>(resolvedCall.candidateDescriptor)
|
||||
else ->
|
||||
emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
override fun doRenameImplicitConventionalCall(newName: String?): KtExpression =
|
||||
renameImplicitConventionalCall(newName)
|
||||
}
|
||||
-56
@@ -1,56 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.references
|
||||
|
||||
import com.intellij.openapi.util.TextRange
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.VariableDescriptorWithAccessors
|
||||
import org.jetbrains.kotlin.descriptors.accessors
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.KtProperty
|
||||
import org.jetbrains.kotlin.psi.KtPropertyDelegate
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
|
||||
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 fun getTargetDescriptors(context: BindingContext): Collection<DeclarationDescriptor> {
|
||||
val property = expression.getStrictParentOfType<KtProperty>() ?: return emptyList()
|
||||
val descriptor = context[BindingContext.DECLARATION_TO_DESCRIPTOR, property] as? VariableDescriptorWithAccessors
|
||||
?: return emptyList()
|
||||
return (descriptor.accessors.mapNotNull { accessor ->
|
||||
context.get(BindingContext.DELEGATED_PROPERTY_RESOLVED_CALL, accessor)?.candidateDescriptor
|
||||
} + listOfNotNull(context.get(BindingContext.PROVIDE_DELEGATE_RESOLVED_CALL, descriptor)?.candidateDescriptor))
|
||||
}
|
||||
|
||||
override val resolvesByNames: Collection<Name> get() = NAMES
|
||||
|
||||
companion object {
|
||||
private val NAMES = listOf(
|
||||
OperatorNameConventions.GET_VALUE,
|
||||
OperatorNameConventions.SET_VALUE,
|
||||
OperatorNameConventions.PROVIDE_DELEGATE
|
||||
)
|
||||
}
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright 2010-2020 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.PsiElement
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.VariableDescriptorWithAccessors
|
||||
import org.jetbrains.kotlin.descriptors.accessors
|
||||
import org.jetbrains.kotlin.psi.KtProperty
|
||||
import org.jetbrains.kotlin.psi.KtPropertyDelegate
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
|
||||
class KtPropertyDelegationMethodsReferenceDescriptorsImpl(
|
||||
element: KtPropertyDelegate
|
||||
) : KtPropertyDelegationMethodsReference(element), KtDescriptorsBasedReference {
|
||||
override fun isReferenceTo(element: PsiElement): Boolean =
|
||||
super<KtDescriptorsBasedReference>.isReferenceTo(element)
|
||||
|
||||
override fun getTargetDescriptors(context: BindingContext): Collection<DeclarationDescriptor> {
|
||||
val property = expression.getStrictParentOfType<KtProperty>() ?: return emptyList()
|
||||
val descriptor = context[BindingContext.DECLARATION_TO_DESCRIPTOR, property] as? VariableDescriptorWithAccessors
|
||||
?: return emptyList()
|
||||
return descriptor.accessors.mapNotNull { accessor ->
|
||||
context.get(BindingContext.DELEGATED_PROPERTY_RESOLVED_CALL, accessor)?.candidateDescriptor
|
||||
} + listOfNotNull(context.get(BindingContext.PROVIDE_DELEGATE_RESOLVED_CALL, descriptor)?.candidateDescriptor)
|
||||
}
|
||||
}
|
||||
@@ -1,17 +1,6 @@
|
||||
/*
|
||||
* Copyright 2010-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* Copyright 2010-2020 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
|
||||
@@ -51,251 +40,83 @@ import org.jetbrains.kotlin.resolve.bindingContextUtil.getReferenceTargets
|
||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||
import java.util.*
|
||||
|
||||
interface KtReference : PsiPolyVariantReference {
|
||||
fun resolveToDescriptors(bindingContext: BindingContext): Collection<DeclarationDescriptor>
|
||||
interface KtDescriptorsBasedReference : KtReference {
|
||||
override val resolver get() = KotlinDescriptorsBasedReferenceResolver
|
||||
|
||||
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> {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val kotlinResolver = KOTLIN_RESOLVER as ResolveCache.PolyVariantResolver<AbstractKtReference<T>>
|
||||
return ResolveCache.getInstance(expression.project).resolveWithCaching(this, kotlinResolver, false, incompleteCode)
|
||||
fun resolveToDescriptors(bindingContext: BindingContext): Collection<DeclarationDescriptor> {
|
||||
return getTargetDescriptors(bindingContext)
|
||||
}
|
||||
|
||||
fun getTargetDescriptors(context: BindingContext): Collection<DeclarationDescriptor>
|
||||
|
||||
override fun isReferenceTo(element: PsiElement): Boolean {
|
||||
return matchesTarget(element)
|
||||
}
|
||||
|
||||
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 resolveToDescriptors(bindingContext: BindingContext): Collection<DeclarationDescriptor> {
|
||||
return getTargetDescriptors(bindingContext)
|
||||
}
|
||||
|
||||
protected abstract fun getTargetDescriptors(context: BindingContext): Collection<DeclarationDescriptor>
|
||||
|
||||
override fun toString() = this::class.java.simpleName + ": " + expression.text
|
||||
|
||||
companion object {
|
||||
private object FirReferenceResolveHelper {
|
||||
fun FirResolvedTypeRef.toTargetPsi(session: FirSession): PsiElement? {
|
||||
val type = type as? ConeLookupTagBasedType ?: return null
|
||||
return (type.lookupTag.toSymbol(session) as? AbstractFirBasedSymbol<*>)?.fir?.psi
|
||||
}
|
||||
|
||||
fun ClassId.toTargetPsi(session: FirSession, calleeReference: FirReference? = null): PsiElement? {
|
||||
val classLikeDeclaration = ConeClassLikeLookupTagImpl(this).toSymbol(session)?.fir
|
||||
if (classLikeDeclaration is FirRegularClass) {
|
||||
if (calleeReference is FirResolvedNamedReference) {
|
||||
val callee = calleeReference.resolvedSymbol.fir as? FirCallableMemberDeclaration
|
||||
// TODO: check callee owner directly?
|
||||
if (callee !is FirConstructor && callee?.isStatic != true) {
|
||||
classLikeDeclaration.companionObject?.let { return it.psi }
|
||||
}
|
||||
}
|
||||
}
|
||||
return classLikeDeclaration?.psi
|
||||
}
|
||||
|
||||
fun FirReference.toTargetPsi(session: FirSession): PsiElement? {
|
||||
return when (this) {
|
||||
is FirResolvedNamedReference -> {
|
||||
resolvedSymbol.fir.psi
|
||||
}
|
||||
is FirResolvedCallableReference -> {
|
||||
resolvedSymbol.fir.psi
|
||||
}
|
||||
is FirThisReference -> {
|
||||
boundSymbol?.fir?.psi
|
||||
}
|
||||
is FirSuperReference -> {
|
||||
(superTypeRef as? FirResolvedTypeRef)?.toTargetPsi(session)
|
||||
}
|
||||
else -> {
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun resolveToPsiElements(ref: AbstractKtReference<KtElement>): Collection<PsiElement> {
|
||||
val expression = ref.expression
|
||||
val state = expression.firResolveState()
|
||||
val session = state.getSession(expression)
|
||||
when (val fir = expression.getOrBuildFir(state)) {
|
||||
is FirResolvable -> {
|
||||
return listOfNotNull(fir.calleeReference.toTargetPsi(session))
|
||||
}
|
||||
is FirResolvedTypeRef -> {
|
||||
return listOfNotNull(fir.toTargetPsi(session))
|
||||
}
|
||||
is FirResolvedQualifier -> {
|
||||
val classId = fir.classId ?: return emptyList()
|
||||
// Distinguish A.foo() from A(.Companion).foo()
|
||||
// Make expression.parent as? KtDotQualifiedExpression local function
|
||||
var parent = expression.parent as? KtDotQualifiedExpression
|
||||
while (parent != null) {
|
||||
val selectorExpression = parent.selectorExpression ?: break
|
||||
if (selectorExpression === expression) {
|
||||
parent = parent.parent as? KtDotQualifiedExpression
|
||||
continue
|
||||
}
|
||||
val parentFir = selectorExpression.getOrBuildFir(state)
|
||||
if (parentFir is FirQualifiedAccess) {
|
||||
return listOfNotNull(classId.toTargetPsi(session, parentFir.calleeReference))
|
||||
}
|
||||
parent = parent.parent as? KtDotQualifiedExpression
|
||||
}
|
||||
return listOfNotNull(classId.toTargetPsi(session))
|
||||
}
|
||||
is FirAnnotationCall -> {
|
||||
val type = fir.typeRef as? FirResolvedTypeRef ?: return emptyList()
|
||||
return listOfNotNull(type.toTargetPsi(session))
|
||||
}
|
||||
is FirResolvedImport -> {
|
||||
var parent = expression.parent
|
||||
while (parent is KtDotQualifiedExpression) {
|
||||
if (parent.selectorExpression !== expression) {
|
||||
// Special: package reference in the middle of import directive
|
||||
// import a.<caret>b.c.SomeClass
|
||||
// TODO: return reference to PsiPackage
|
||||
return listOf(expression)
|
||||
}
|
||||
parent = parent.parent
|
||||
}
|
||||
val classId = fir.resolvedClassId
|
||||
if (classId != null) {
|
||||
return listOfNotNull(classId.toTargetPsi(session))
|
||||
}
|
||||
val name = fir.importedName ?: return emptyList()
|
||||
val symbolProvider = session.firSymbolProvider
|
||||
return symbolProvider.getTopLevelCallableSymbols(fir.packageFqName, name).mapNotNull { it.fir.psi } +
|
||||
listOfNotNull(symbolProvider.getClassLikeSymbolByFqName(ClassId(fir.packageFqName, name))?.fir?.psi)
|
||||
}
|
||||
is FirFile -> {
|
||||
if (expression.getNonStrictParentOfType<KtPackageDirective>() != null) {
|
||||
// Special: package reference in the middle of package directive
|
||||
return listOf(expression)
|
||||
}
|
||||
return listOfNotNull(fir.psi)
|
||||
}
|
||||
is FirArrayOfCall -> {
|
||||
// We can't yet find PsiElement for arrayOf, intArrayOf, etc.
|
||||
return emptyList()
|
||||
}
|
||||
is FirErrorNamedReference -> {
|
||||
return emptyList()
|
||||
}
|
||||
else -> {
|
||||
// Handle situation when we're in the middle/beginning of qualifier
|
||||
// <caret>A.B.C.foo() or A.<caret>B.C.foo()
|
||||
// NB: in this case we get some parent FIR, like FirBlock, FirProperty, FirFunction or the like
|
||||
var parent = expression.parent as? KtDotQualifiedExpression
|
||||
var unresolvedCounter = 1
|
||||
while (parent != null) {
|
||||
val selectorExpression = parent.selectorExpression ?: break
|
||||
if (selectorExpression === expression) {
|
||||
parent = parent.parent as? KtDotQualifiedExpression
|
||||
continue
|
||||
}
|
||||
val parentFir = selectorExpression.getOrBuildFir(state)
|
||||
if (parentFir is FirResolvedQualifier) {
|
||||
var classId = parentFir.classId
|
||||
while (unresolvedCounter > 0) {
|
||||
unresolvedCounter--
|
||||
classId = classId?.outerClassId
|
||||
}
|
||||
return listOfNotNull(classId?.toTargetPsi(session))
|
||||
}
|
||||
parent = parent.parent as? KtDotQualifiedExpression
|
||||
unresolvedCounter++
|
||||
}
|
||||
return emptyList()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class KotlinReferenceResolver : ResolveCache.PolyVariantResolver<AbstractKtReference<KtElement>> {
|
||||
class KotlinResolveResult(element: PsiElement) : PsiElementResolveResult(element)
|
||||
|
||||
private fun resolveToPsiElements(ref: AbstractKtReference<KtElement>): Collection<PsiElement> {
|
||||
if (FirResolution.enabled) {
|
||||
return FirReferenceResolveHelper.resolveToPsiElements(ref)
|
||||
}
|
||||
val bindingContext = ref.expression.analyze(BodyResolveMode.PARTIAL)
|
||||
return resolveToPsiElements(ref, bindingContext, ref.getTargetDescriptors(bindingContext))
|
||||
}
|
||||
|
||||
private fun resolveToPsiElements(
|
||||
ref: AbstractKtReference<KtElement>,
|
||||
context: BindingContext,
|
||||
targetDescriptors: Collection<DeclarationDescriptor>
|
||||
): Collection<PsiElement> {
|
||||
if (targetDescriptors.isNotEmpty()) {
|
||||
return targetDescriptors.flatMap { target -> resolveToPsiElements(ref, target) }.toSet()
|
||||
}
|
||||
|
||||
val labelTargets = getLabelTargets(ref, context)
|
||||
if (labelTargets != null) {
|
||||
return labelTargets
|
||||
}
|
||||
|
||||
return Collections.emptySet()
|
||||
}
|
||||
|
||||
private fun resolveToPsiElements(
|
||||
ref: AbstractKtReference<KtElement>,
|
||||
targetDescriptor: DeclarationDescriptor
|
||||
): Collection<PsiElement> {
|
||||
return if (targetDescriptor is PackageViewDescriptor) {
|
||||
val psiFacade = JavaPsiFacade.getInstance(ref.expression.project)
|
||||
val fqName = targetDescriptor.fqName.asString()
|
||||
listOfNotNull(psiFacade.findPackage(fqName))
|
||||
} else {
|
||||
DescriptorToSourceUtilsIde.getAllDeclarations(ref.expression.project, targetDescriptor, ref.expression.resolveScope)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getLabelTargets(ref: AbstractKtReference<KtElement>, context: BindingContext): Collection<PsiElement>? {
|
||||
val reference = ref.expression as? KtReferenceExpression ?: return null
|
||||
val labelTarget = context[BindingContext.LABEL_TARGET, reference]
|
||||
if (labelTarget != null) {
|
||||
return listOf(labelTarget)
|
||||
}
|
||||
return context[BindingContext.AMBIGUOUS_LABEL_TARGET, reference]
|
||||
}
|
||||
|
||||
override fun resolve(ref: AbstractKtReference<KtElement>, incompleteCode: Boolean): Array<ResolveResult> {
|
||||
return runWithCancellationCheck {
|
||||
val resolveToPsiElements = resolveToPsiElements(ref)
|
||||
resolveToPsiElements.map { KotlinResolveResult(it) }.toTypedArray()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val KOTLIN_RESOLVER = KotlinReferenceResolver()
|
||||
}
|
||||
}
|
||||
|
||||
abstract class KtSimpleReference<T : KtReferenceExpression>(expression: T) : AbstractKtReference<T>(expression) {
|
||||
override fun getTargetDescriptors(context: BindingContext) = expression.getReferenceTargets(context)
|
||||
fun KtReference.resolveToDescriptors(bindingContext: BindingContext): Collection<DeclarationDescriptor> {
|
||||
if (this !is KtDescriptorsBasedReference) {
|
||||
error("Reference $this should be KtDescriptorsBasedReference but was ${this::class}")
|
||||
}
|
||||
return resolveToDescriptors(bindingContext)
|
||||
}
|
||||
|
||||
abstract class KtMultiReference<T : KtElement>(expression: T) : AbstractKtReference<T>(expression)
|
||||
|
||||
object KotlinDescriptorsBasedReferenceResolver : ResolveCache.PolyVariantResolver<KtReference> {
|
||||
class KotlinResolveResult(element: PsiElement) : PsiElementResolveResult(element)
|
||||
|
||||
private fun resolveToPsiElements(ref: KtDescriptorsBasedReference): Collection<PsiElement> {
|
||||
if (FirResolution.enabled) {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return FirReferenceResolveHelper.resolveToPsiElements(ref as AbstractKtReference<KtElement>)
|
||||
}
|
||||
val bindingContext = ref.element.analyze(BodyResolveMode.PARTIAL)
|
||||
return resolveToPsiElements(ref, bindingContext, ref.getTargetDescriptors(bindingContext))
|
||||
}
|
||||
|
||||
private fun resolveToPsiElements(
|
||||
ref: KtDescriptorsBasedReference,
|
||||
context: BindingContext,
|
||||
targetDescriptors: Collection<DeclarationDescriptor>
|
||||
): Collection<PsiElement> {
|
||||
if (targetDescriptors.isNotEmpty()) {
|
||||
return targetDescriptors.flatMap { target -> resolveToPsiElements(ref, target) }.toSet()
|
||||
}
|
||||
|
||||
val labelTargets = getLabelTargets(ref, context)
|
||||
if (labelTargets != null) {
|
||||
return labelTargets
|
||||
}
|
||||
|
||||
return Collections.emptySet()
|
||||
}
|
||||
|
||||
private fun resolveToPsiElements(
|
||||
ref: KtDescriptorsBasedReference,
|
||||
targetDescriptor: DeclarationDescriptor
|
||||
): Collection<PsiElement> {
|
||||
return if (targetDescriptor is PackageViewDescriptor) {
|
||||
val psiFacade = JavaPsiFacade.getInstance(ref.element.project)
|
||||
val fqName = targetDescriptor.fqName.asString()
|
||||
listOfNotNull(psiFacade.findPackage(fqName))
|
||||
} else {
|
||||
DescriptorToSourceUtilsIde.getAllDeclarations(ref.element.project, targetDescriptor, ref.element.resolveScope)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getLabelTargets(ref: KtDescriptorsBasedReference, context: BindingContext): Collection<PsiElement>? {
|
||||
val reference = ref.element as? KtReferenceExpression ?: return null
|
||||
val labelTarget = context[BindingContext.LABEL_TARGET, reference]
|
||||
if (labelTarget != null) {
|
||||
return listOf(labelTarget)
|
||||
}
|
||||
return context[BindingContext.AMBIGUOUS_LABEL_TARGET, reference]
|
||||
}
|
||||
|
||||
override fun resolve(ref: KtReference, incompleteCode: Boolean): Array<ResolveResult> {
|
||||
return runWithCancellationCheck {
|
||||
val resolveToPsiElements = resolveToPsiElements(ref as KtDescriptorsBasedReference)
|
||||
resolveToPsiElements.map { KotlinResolveResult(it) }.toTypedArray()
|
||||
}
|
||||
}
|
||||
}
|
||||
+16
-14
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Copyright 2010-2020 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.
|
||||
*/
|
||||
|
||||
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.idea.references
|
||||
import com.intellij.openapi.extensions.Extensions
|
||||
import com.intellij.openapi.util.TextRange
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiReference
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import com.intellij.util.IncorrectOperationException
|
||||
import com.intellij.util.SmartList
|
||||
@@ -33,15 +34,21 @@ import org.jetbrains.kotlin.psi.psiUtil.*
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.DataClassDescriptorResolver
|
||||
import org.jetbrains.kotlin.resolve.ImportedFromObjectCallableDescriptor
|
||||
import org.jetbrains.kotlin.resolve.bindingContextUtil.getReferenceTargets
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getImportableDescriptor
|
||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||
import org.jetbrains.kotlin.types.expressions.OperatorConventions
|
||||
|
||||
class KtSimpleNameReference(expression: KtSimpleNameExpression) : KtSimpleReference<KtSimpleNameExpression>(expression) {
|
||||
class KtSimpleNameReferenceDescriptorsImpl(
|
||||
expression: KtSimpleNameExpression
|
||||
) : KtSimpleNameReference(expression), KtDescriptorsBasedReference {
|
||||
override fun doCanBeReferenceTo(candidateTarget: PsiElement): Boolean =
|
||||
canBeReferenceTo(candidateTarget)
|
||||
|
||||
override fun getTargetDescriptors(context: BindingContext): Collection<DeclarationDescriptor> {
|
||||
return SmartList<DeclarationDescriptor>().apply {
|
||||
// Replace Java property with its accessor(s)
|
||||
for (descriptor in super.getTargetDescriptors(context)) {
|
||||
for (descriptor in expression.getReferenceTargets(context)) {
|
||||
val sizeBefore = size
|
||||
|
||||
if (descriptor !is JavaPropertyDescriptor) {
|
||||
@@ -71,7 +78,7 @@ class KtSimpleNameReference(expression: KtSimpleNameExpression) : KtSimpleRefere
|
||||
if (extension.isReferenceTo(this, element)) return true
|
||||
}
|
||||
|
||||
return super.isReferenceTo(element)
|
||||
return super<KtDescriptorsBasedReference>.isReferenceTo(element)
|
||||
}
|
||||
|
||||
override fun getRangeInElement(): TextRange {
|
||||
@@ -141,23 +148,18 @@ class KtSimpleNameReference(expression: KtSimpleNameExpression) : KtSimpleRefere
|
||||
return expression
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
fun bindToElement(element: PsiElement, shorteningMode: ShorteningMode): PsiElement =
|
||||
override fun bindToElement(element: PsiElement, shorteningMode: ShorteningMode): PsiElement =
|
||||
element.getKotlinFqName()?.let { fqName -> bindToFqName(fqName, shorteningMode, element) } ?: expression
|
||||
|
||||
fun bindToFqName(
|
||||
override fun bindToFqName(
|
||||
fqName: FqName,
|
||||
shorteningMode: ShorteningMode = ShorteningMode.DELAYED_SHORTENING,
|
||||
targetElement: PsiElement? = null
|
||||
shorteningMode: ShorteningMode,
|
||||
targetElement: PsiElement?
|
||||
): PsiElement {
|
||||
val expression = expression
|
||||
if (fqName.isRoot) return expression
|
||||
@@ -289,7 +291,7 @@ class KtSimpleNameReference(expression: KtSimpleNameExpression) : KtSimpleRefere
|
||||
return listOf(element.getReferencedNameAsName())
|
||||
}
|
||||
|
||||
fun getImportAlias(): KtImportAlias? {
|
||||
override fun getImportAlias(): KtImportAlias? {
|
||||
fun DeclarationDescriptor.unwrap() = if (this is ImportedFromObjectCallableDescriptor<*>) callableFromObject else this
|
||||
|
||||
val element = element
|
||||
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright 2010-2020 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.idea.caches.resolve.resolveToCall
|
||||
import org.jetbrains.kotlin.psi.KtBinaryExpression
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
import org.jetbrains.kotlin.resolve.calls.model.isReallySuccess
|
||||
import org.jetbrains.kotlin.types.expressions.OperatorConventions
|
||||
|
||||
class ReadWriteAccessCheckerDescriptorsImpl : ReadWriteAccessChecker {
|
||||
override fun readWriteAccessWithFullExpressionByResolve(assignment: KtBinaryExpression): Pair<ReferenceAccess, KtExpression> {
|
||||
val resolvedCall = assignment.resolveToCall() ?: return ReferenceAccess.READ_WRITE to assignment
|
||||
if (!resolvedCall.isReallySuccess()) return ReferenceAccess.READ_WRITE to assignment
|
||||
return if (resolvedCall.resultingDescriptor.name in OperatorConventions.ASSIGNMENT_OPERATIONS.values)
|
||||
ReferenceAccess.READ to assignment
|
||||
else
|
||||
ReferenceAccess.READ_WRITE to assignment
|
||||
}
|
||||
}
|
||||
+12
-26
@@ -1,13 +1,11 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Copyright 2010-2020 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.psi.PsiMethod
|
||||
import com.intellij.util.SmartList
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
@@ -22,14 +20,22 @@ import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.*
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.bindingContextUtil.getReferenceTargets
|
||||
import org.jetbrains.kotlin.synthetic.SyntheticJavaPropertyDescriptor
|
||||
import org.jetbrains.kotlin.types.expressions.OperatorConventions
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
|
||||
sealed class SyntheticPropertyAccessorReference(expression: KtNameReferenceExpression, private val getter: Boolean) :
|
||||
KtSimpleReference<KtNameReferenceExpression>(expression) {
|
||||
class SyntheticPropertyAccessorReferenceDescriptorImpl(
|
||||
expression: KtNameReferenceExpression,
|
||||
getter: Boolean
|
||||
) : SyntheticPropertyAccessorReference(expression, getter), KtDescriptorsBasedReference {
|
||||
override fun isReferenceTo(element: PsiElement): Boolean =
|
||||
super<SyntheticPropertyAccessorReference>.isReferenceTo(element)
|
||||
|
||||
override fun additionalIsReferenceToChecker(element: PsiElement): Boolean = matchesTarget(element)
|
||||
|
||||
override fun getTargetDescriptors(context: BindingContext): Collection<DeclarationDescriptor> {
|
||||
val descriptors = super.getTargetDescriptors(context)
|
||||
val descriptors = expression.getReferenceTargets(context)
|
||||
if (descriptors.none { it is SyntheticJavaPropertyDescriptor }) return emptyList()
|
||||
|
||||
val result = SmartList<FunctionDescriptor>()
|
||||
@@ -45,23 +51,6 @@ sealed class SyntheticPropertyAccessorReference(expression: KtNameReferenceExpre
|
||||
return result
|
||||
}
|
||||
|
||||
override fun isReferenceTo(element: PsiElement): Boolean {
|
||||
if (element !is PsiMethod || !isAccessorName(element.name)) return false
|
||||
if (!getter && expression.readWriteAccess(true) == ReferenceAccess.READ) return false
|
||||
return super.isReferenceTo(element)
|
||||
}
|
||||
|
||||
private 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
|
||||
|
||||
private fun renameByPropertyName(newName: String): PsiElement? {
|
||||
val nameIdentifier = KtPsiFactory(expression).createNameIdentifier(newName)
|
||||
expression.getReferencedNameElement().replace(nameIdentifier)
|
||||
@@ -183,7 +172,4 @@ sealed class SyntheticPropertyAccessorReference(expression: KtNameReferenceExpre
|
||||
|
||||
override val resolvesByNames: Collection<Name>
|
||||
get() = listOf(element.getReferencedNameAsName())
|
||||
|
||||
class Getter(expression: KtNameReferenceExpression) : SyntheticPropertyAccessorReference(expression, true)
|
||||
class Setter(expression: KtNameReferenceExpression) : SyntheticPropertyAccessorReference(expression, false)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Copyright 2010-2020 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.
|
||||
*/
|
||||
|
||||
@@ -221,20 +221,20 @@ fun AbstractKtReference<out KtExpression>.renameImplicitConventionalCall(newName
|
||||
return newExpression
|
||||
}
|
||||
|
||||
val KtSimpleNameExpression.mainReference: KtSimpleNameReference
|
||||
val KtSimpleNameExpression.mainReference: KtSimpleNameReferenceDescriptorsImpl
|
||||
get() = references.firstIsInstance()
|
||||
|
||||
val KtReferenceExpression.mainReference: KtReference
|
||||
get() = if (this is KtSimpleNameExpression) mainReference else references.firstIsInstance<KtReference>()
|
||||
val KtReferenceExpression.mainReference: KtDescriptorsBasedReference
|
||||
get() = if (this is KtSimpleNameExpression) mainReference else references.firstIsInstance<KtDescriptorsBasedReference>()
|
||||
|
||||
val KDocName.mainReference: KDocReference
|
||||
get() = references.firstIsInstance()
|
||||
|
||||
val KtElement.mainReference: KtReference?
|
||||
val KtElement.mainReference: KtDescriptorsBasedReference?
|
||||
get() = when (this) {
|
||||
is KtReferenceExpression -> mainReference
|
||||
is KDocName -> mainReference
|
||||
else -> references.firstIsInstanceOrNull<KtReference>()
|
||||
else -> references.firstIsInstanceOrNull<KtDescriptorsBasedReference>()
|
||||
}
|
||||
|
||||
fun KtElement.resolveMainReferenceToDescriptors(): Collection<DeclarationDescriptor> {
|
||||
@@ -248,46 +248,6 @@ fun PsiReference.getImportAlias(): KtImportAlias? {
|
||||
|
||||
// ----------- Read/write access -----------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
enum class ReferenceAccess(val isRead: Boolean, val isWrite: Boolean) {
|
||||
READ(true, false), WRITE(false, true), READ_WRITE(true, true)
|
||||
}
|
||||
|
||||
fun KtExpression.readWriteAccess(useResolveForReadWrite: Boolean) = readWriteAccessWithFullExpression(useResolveForReadWrite).first
|
||||
|
||||
fun KtExpression.readWriteAccessWithFullExpression(useResolveForReadWrite: Boolean): Pair<ReferenceAccess, KtExpression> {
|
||||
var expression = getQualifiedExpressionForSelectorOrThis()
|
||||
loop@ while (true) {
|
||||
when (val parent = expression.parent) {
|
||||
is KtParenthesizedExpression, is KtAnnotatedExpression, is KtLabeledExpression -> expression = parent as KtExpression
|
||||
else -> break@loop
|
||||
}
|
||||
}
|
||||
|
||||
val assignment = expression.getAssignmentByLHS()
|
||||
if (assignment != null) {
|
||||
when (assignment.operationToken) {
|
||||
KtTokens.EQ -> return ReferenceAccess.WRITE to assignment
|
||||
|
||||
else -> {
|
||||
if (!useResolveForReadWrite) return ReferenceAccess.READ_WRITE to assignment
|
||||
|
||||
val resolvedCall = assignment.resolveToCall() ?: return ReferenceAccess.READ_WRITE to assignment
|
||||
if (!resolvedCall.isReallySuccess()) return ReferenceAccess.READ_WRITE to assignment
|
||||
return if (resolvedCall.resultingDescriptor.name in OperatorConventions.ASSIGNMENT_OPERATIONS.values)
|
||||
ReferenceAccess.READ to assignment
|
||||
else
|
||||
ReferenceAccess.READ_WRITE to assignment
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val unaryExpression = expression.parent as? KtUnaryExpression
|
||||
return if (unaryExpression != null && unaryExpression.operationToken in constant { setOf(KtTokens.PLUSPLUS, KtTokens.MINUSMINUS) })
|
||||
ReferenceAccess.READ_WRITE to unaryExpression
|
||||
else
|
||||
ReferenceAccess.READ to expression
|
||||
}
|
||||
|
||||
fun KtReference.canBeResolvedViaImport(target: DeclarationDescriptor, bindingContext: BindingContext): Boolean {
|
||||
if (this is KDocReference) {
|
||||
val qualifier = element.getQualifier() ?: return true
|
||||
|
||||
-22
@@ -1,22 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2019 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.plugin.references
|
||||
|
||||
import com.intellij.openapi.extensions.ExtensionPointName
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.idea.references.KtSimpleNameReference
|
||||
import org.jetbrains.kotlin.psi.KtPsiFactory
|
||||
|
||||
interface SimpleNameReferenceExtension {
|
||||
companion object {
|
||||
val EP_NAME: ExtensionPointName<SimpleNameReferenceExtension> =
|
||||
ExtensionPointName.create("org.jetbrains.kotlin.simpleNameReferenceExtension")
|
||||
}
|
||||
|
||||
fun isReferenceTo(reference: KtSimpleNameReference, element: PsiElement): Boolean
|
||||
|
||||
fun handleElementRename(reference: KtSimpleNameReference, psiFactory: KtPsiFactory, newElementName: String): PsiElement?
|
||||
}
|
||||
Reference in New Issue
Block a user