org.jetbrains.kotlin.idea.references.KtDefaultAnnotationArgumentReference.kt Maven / Gradle / Ivy
/*
* 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.*
import com.intellij.psi.impl.source.resolve.ResolveCache
import com.intellij.psi.util.MethodSignatureUtil
import org.jetbrains.kotlin.asJava.unwrapped
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtAnnotationEntry
import org.jetbrains.kotlin.psi.KtParameter
import org.jetbrains.kotlin.psi.KtPrimaryConstructor
import org.jetbrains.kotlin.psi.KtValueArgument
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
/**
* A reference pointing to a single argument in annotation's constructor call.
* It is created only when the following conditions hold:
*
* - Annotation's constructor call has a **single** argument
* - This argument is passed as is, without an explicit name
*
* Examples:
* ```
* @Foo("bar") // reference is created
* @Foo("bar", "baz") // no reference, there are two arguments
* @Foo(name = "bar") // no reference, named argument is used
* ```
*/
class KtDefaultAnnotationArgumentReference(element: KtValueArgument) : AbstractKtReference(element) {
override val resolver: ResolveCache.PolyVariantResolver
get() = Resolver
override val resolvesByNames: Collection
get() = listOf(Name.identifier(PsiAnnotation.DEFAULT_REFERENCED_METHOD_NAME))
override fun getRangeInElement() = TextRange.EMPTY_RANGE
override fun getCanonicalText() = PsiAnnotation.DEFAULT_REFERENCED_METHOD_NAME
override fun isReferenceTo(candidateTarget: PsiElement): Boolean {
val unwrapped = candidateTarget.unwrapped
return (unwrapped is PsiMethod || unwrapped is KtParameter) && unwrapped == resolve()
}
override fun canRename(): Boolean = true
private object Resolver : ResolveCache.PolyVariantResolver {
override fun resolve(t: KtReference, incompleteCode: Boolean): Array {
require(t is KtDefaultAnnotationArgumentReference)
val annotationPsi = t.resolveAnnotationCallee() ?: return emptyArray()
return when (annotationPsi) {
is PsiClass -> {
val name = PsiAnnotation.DEFAULT_REFERENCED_METHOD_NAME
val signature = MethodSignatureUtil.createMethodSignature(
name, PsiType.EMPTY_ARRAY, PsiTypeParameter.EMPTY_ARRAY, PsiSubstitutor.EMPTY
)
val method = MethodSignatureUtil.findMethodBySignature(annotationPsi, signature, false) ?: return emptyArray()
arrayOf(PsiElementResolveResult(method))
}
is KtPrimaryConstructor -> {
// parameters in primary constructor on Kotlin annotation can have any names,
// so we just take the first parameter
val property = annotationPsi.valueParameters.firstOrNull() ?: return emptyArray()
arrayOf(PsiElementResolveResult(property))
}
else -> emptyArray()
}
}
private fun KtDefaultAnnotationArgumentReference.resolveAnnotationCallee(): PsiElement? =
element.getStrictParentOfType()
?.calleeExpression
?.constructorReferenceExpression
?.mainReference
?.resolve()
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy