[SLC] fix PsiJavaCodeReferenceElement contract violation

We should provide valid getReferenceName as it is used
in many places (e.g. from com.intellij.psi.impl.PsiImplUtil.findAnnotation)

^KT-61605 Fixed
^KT-64605 Fixed
This commit is contained in:
Dmitrii Gridin
2024-01-05 23:40:46 +01:00
committed by Space Team
parent b33798d65a
commit 50dd94502b
9 changed files with 83 additions and 23 deletions
@@ -0,0 +1,25 @@
/*
* Copyright 2010-2024 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.light.classes.symbol.annotations
/**
* Provides additional information for [SymbolLightPsiJavaCodeReferenceElementBase][org.jetbrains.kotlin.light.classes.symbol.codeReferences.SymbolLightPsiJavaCodeReferenceElementBase]
* to reach better API coverage of [com.intellij.psi.PsiReference]
*
* @see org.jetbrains.kotlin.light.classes.symbol.codeReferences.SymbolLightPsiJavaCodeReferenceElementBase
* @see ReferenceInformationHolder
*/
internal interface ReferenceInformationProvider {
/**
* @see com.intellij.psi.PsiQualifiedReference.getReferenceName
*/
val referenceName: String?
}
/**
* @see ReferenceInformationProvider
*/
internal class ReferenceInformationHolder(override val referenceName: String?) : ReferenceInformationProvider
@@ -1,5 +1,5 @@
/*
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Copyright 2010-2024 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.
*/
@@ -34,10 +34,13 @@ internal abstract class SymbolLightAbstractAnnotation(parent: PsiElement) :
val reference = (kotlinOrigin as? KtAnnotationEntry)?.typeReference?.reference
?: (kotlinOrigin?.calleeExpression?.nameReference)?.references?.firstOrNull()
if (reference != null) SymbolLightPsiJavaCodeReferenceElementWithReference(ktElement, reference)
else SymbolLightPsiJavaCodeReferenceElementWithNoReference(ktElement)
val provider = createReferenceInformationProvider()
if (reference != null) SymbolLightPsiJavaCodeReferenceElementWithReference(ktElement, reference, provider)
else SymbolLightPsiJavaCodeReferenceElementWithNoReference(ktElement, provider)
}
abstract fun createReferenceInformationProvider(): ReferenceInformationProvider
override fun getNameReferenceElement(): PsiJavaCodeReferenceElement = _nameReferenceElement
override fun delete() {
@@ -1,5 +1,5 @@
/*
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Copyright 2010-2024 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.
*/
@@ -17,6 +17,10 @@ internal open class SymbolLightJavaAnnotation(
owner: PsiModifierList,
private val argumentsComputer: SymbolLightJavaAnnotation.() -> List<KtNamedAnnotationValue>,
) : SymbolLightAbstractAnnotation(owner) {
override fun createReferenceInformationProvider(): ReferenceInformationProvider = ReferenceInformationHolder(
referenceName = javaQualifier.substringAfterLast('.'),
)
override val kotlinOrigin: KtCallElement? get() = originalLightAnnotation.kotlinOrigin
override fun equals(other: Any?): Boolean = other === this ||
@@ -1,5 +1,5 @@
/*
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Copyright 2010-2024 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.
*/
@@ -28,6 +28,10 @@ internal class SymbolLightLazyAnnotation(
private val fqName: FqName = classId.asSingleFqName()
override fun createReferenceInformationProvider(): ReferenceInformationProvider = ReferenceInformationHolder(
referenceName = classId.shortClassName.asString(),
)
val annotationApplicationWithArgumentsInfo: Lazy<KtAnnotationApplicationWithArgumentsInfo> =
(annotationApplication as? KtAnnotationApplicationWithArgumentsInfo)?.let(::lazyOf) ?: lazyPub {
val applications = annotationsProvider[classId]
@@ -1,5 +1,5 @@
/*
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Copyright 2010-2024 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.
*/
@@ -17,6 +17,9 @@ internal class SymbolLightSimpleAnnotation(
private val arguments: List<KtNamedAnnotationValue> = listOf(),
override val kotlinOrigin: KtCallElement? = null,
) : SymbolLightAbstractAnnotation(parent) {
override fun createReferenceInformationProvider(): ReferenceInformationProvider = ReferenceInformationHolder(
referenceName = fqName?.substringAfterLast('.'),
)
override fun getQualifiedName(): String? = fqName
@@ -1,5 +1,5 @@
/*
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Copyright 2010-2024 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.
*/
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.asJava.classes.lazyPub
import org.jetbrains.kotlin.asJava.elements.KtLightField
import org.jetbrains.kotlin.asJava.elements.KtLightIdentifier
import org.jetbrains.kotlin.asJava.elements.KtLightMethod
import org.jetbrains.kotlin.light.classes.symbol.annotations.ReferenceInformationHolder
import org.jetbrains.kotlin.light.classes.symbol.cachedValue
import org.jetbrains.kotlin.light.classes.symbol.codeReferences.SymbolLightPsiJavaCodeReferenceElementWithNoReference
import org.jetbrains.kotlin.light.classes.symbol.fields.SymbolLightFieldForEnumEntry
@@ -29,8 +30,12 @@ internal class SymbolLightClassForEnumEntry(
) : SymbolLightClassBase(ktModule, enumConstant.manager), PsiEnumConstantInitializer {
override fun getBaseClassType(): PsiClassType = enumConstant.type as PsiClassType //???TODO
override fun getBaseClassReference(): PsiJavaCodeReferenceElement =
SymbolLightPsiJavaCodeReferenceElementWithNoReference(enumConstant) //???TODO
override fun getBaseClassReference(): PsiJavaCodeReferenceElement = SymbolLightPsiJavaCodeReferenceElementWithNoReference(
enumConstant,
ReferenceInformationHolder(
referenceName = enumConstant.name,
)
)
override fun getArgumentList(): PsiExpressionList? = null
@@ -1,5 +1,5 @@
/*
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Copyright 2010-2024 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.
*/
@@ -7,11 +7,12 @@ package org.jetbrains.kotlin.light.classes.symbol.codeReferences
import com.intellij.psi.*
import com.intellij.psi.scope.PsiScopeProcessor
import org.jetbrains.kotlin.light.classes.symbol.annotations.ReferenceInformationProvider
internal abstract class SymbolLightPsiJavaCodeReferenceElementBase(private val ktElement: PsiElement) :
PsiElement by ktElement,
PsiJavaCodeReferenceElement {
internal sealed class SymbolLightPsiJavaCodeReferenceElementBase(
private val ktElement: PsiElement,
private val referenceInformationProvider: ReferenceInformationProvider,
) : PsiElement by ktElement, PsiJavaCodeReferenceElement {
override fun multiResolve(incompleteCode: Boolean): Array<JavaResolveResult> = JavaResolveResult.EMPTY_ARRAY
override fun processVariants(processor: PsiScopeProcessor) {}
@@ -20,7 +21,10 @@ internal abstract class SymbolLightPsiJavaCodeReferenceElementBase(private val k
override fun getQualifier(): PsiElement? = null
override fun getReferenceName(): String? = null
/**
* @see com.intellij.psi.impl.PsiImplUtil.findAnnotation
*/
override fun getReferenceName(): String? = referenceInformationProvider.referenceName
override fun getReferenceNameElement(): PsiElement? = null
@@ -1,5 +1,5 @@
/*
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Copyright 2010-2024 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.
*/
@@ -9,10 +9,12 @@ import com.intellij.openapi.util.TextRange
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiReference
import com.intellij.util.IncorrectOperationException
import org.jetbrains.kotlin.light.classes.symbol.annotations.ReferenceInformationProvider
internal class SymbolLightPsiJavaCodeReferenceElementWithNoReference(private val ktElement: PsiElement) :
SymbolLightPsiJavaCodeReferenceElementBase(ktElement),
PsiReference {
internal class SymbolLightPsiJavaCodeReferenceElementWithNoReference(
private val ktElement: PsiElement,
referenceInformationProvider: ReferenceInformationProvider,
) : SymbolLightPsiJavaCodeReferenceElementBase(ktElement, referenceInformationProvider), PsiReference {
override fun getElement(): PsiElement = ktElement
@@ -1,5 +1,5 @@
/*
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Copyright 2010-2024 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.
*/
@@ -7,10 +7,20 @@ package org.jetbrains.kotlin.light.classes.symbol.codeReferences
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiReference
import org.jetbrains.kotlin.light.classes.symbol.annotations.ReferenceInformationProvider
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
internal class SymbolLightPsiJavaCodeReferenceElementWithReference(private val ktElement: PsiElement, reference: PsiReference) :
SymbolLightPsiJavaCodeReferenceElementBase(ktElement),
internal class SymbolLightPsiJavaCodeReferenceElementWithReference(
private val ktElement: PsiElement,
private val reference: PsiReference,
referenceInformationProvider: ReferenceInformationProvider,
) : SymbolLightPsiJavaCodeReferenceElementBase(ktElement, referenceInformationProvider),
PsiReference by reference {
override fun getElement(): PsiElement = ktElement
}
private val nameExpression: KtSimpleNameExpression? get() = reference.element as? KtSimpleNameExpression
override fun getReferenceName(): String? = super.getReferenceName() ?: nameExpression?.getReferencedName()
override fun getReferenceNameElement(): PsiElement? = nameExpression?.getReferencedNameElement()
}