From 50dd94502b30bdda9aa43a2ed31538bd4a902e8e Mon Sep 17 00:00:00 2001 From: Dmitrii Gridin Date: Fri, 5 Jan 2024 23:40:46 +0100 Subject: [PATCH] [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 --- .../ReferenceInformationProvider.kt | 25 +++++++++++++++++++ .../SymbolLightAbstractAnnotation.kt | 9 ++++--- .../annotations/SymbolLightJavaAnnotation.kt | 6 ++++- .../annotations/SymbolLightLazyAnnotation.kt | 6 ++++- .../SymbolLightSimpleAnnotation.kt | 5 +++- .../classes/SymbolLightClassForEnumEntry.kt | 11 +++++--- ...bolLightPsiJavaCodeReferenceElementBase.kt | 16 +++++++----- ...JavaCodeReferenceElementWithNoReference.kt | 10 +++++--- ...siJavaCodeReferenceElementWithReference.kt | 18 ++++++++++--- 9 files changed, 83 insertions(+), 23 deletions(-) create mode 100644 analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/annotations/ReferenceInformationProvider.kt diff --git a/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/annotations/ReferenceInformationProvider.kt b/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/annotations/ReferenceInformationProvider.kt new file mode 100644 index 00000000000..d688c8dd0a0 --- /dev/null +++ b/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/annotations/ReferenceInformationProvider.kt @@ -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 \ No newline at end of file diff --git a/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/annotations/SymbolLightAbstractAnnotation.kt b/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/annotations/SymbolLightAbstractAnnotation.kt index d0f5f2c1bf3..de96a358a47 100644 --- a/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/annotations/SymbolLightAbstractAnnotation.kt +++ b/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/annotations/SymbolLightAbstractAnnotation.kt @@ -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() { diff --git a/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/annotations/SymbolLightJavaAnnotation.kt b/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/annotations/SymbolLightJavaAnnotation.kt index 16bed60dd30..9d54fc2f8a7 100644 --- a/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/annotations/SymbolLightJavaAnnotation.kt +++ b/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/annotations/SymbolLightJavaAnnotation.kt @@ -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, ) : 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 || diff --git a/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/annotations/SymbolLightLazyAnnotation.kt b/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/annotations/SymbolLightLazyAnnotation.kt index e1444eeef84..6d0dd973286 100644 --- a/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/annotations/SymbolLightLazyAnnotation.kt +++ b/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/annotations/SymbolLightLazyAnnotation.kt @@ -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 = (annotationApplication as? KtAnnotationApplicationWithArgumentsInfo)?.let(::lazyOf) ?: lazyPub { val applications = annotationsProvider[classId] diff --git a/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/annotations/SymbolLightSimpleAnnotation.kt b/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/annotations/SymbolLightSimpleAnnotation.kt index 940c5312eaf..3c384c5d2f1 100644 --- a/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/annotations/SymbolLightSimpleAnnotation.kt +++ b/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/annotations/SymbolLightSimpleAnnotation.kt @@ -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 = listOf(), override val kotlinOrigin: KtCallElement? = null, ) : SymbolLightAbstractAnnotation(parent) { + override fun createReferenceInformationProvider(): ReferenceInformationProvider = ReferenceInformationHolder( + referenceName = fqName?.substringAfterLast('.'), + ) override fun getQualifiedName(): String? = fqName diff --git a/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/classes/SymbolLightClassForEnumEntry.kt b/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/classes/SymbolLightClassForEnumEntry.kt index bf119445632..70efc4197ac 100644 --- a/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/classes/SymbolLightClassForEnumEntry.kt +++ b/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/classes/SymbolLightClassForEnumEntry.kt @@ -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 diff --git a/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/codeReferences/SymbolLightPsiJavaCodeReferenceElementBase.kt b/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/codeReferences/SymbolLightPsiJavaCodeReferenceElementBase.kt index 1299ea8beef..502facd33a1 100644 --- a/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/codeReferences/SymbolLightPsiJavaCodeReferenceElementBase.kt +++ b/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/codeReferences/SymbolLightPsiJavaCodeReferenceElementBase.kt @@ -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.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 diff --git a/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/codeReferences/SymbolLightPsiJavaCodeReferenceElementWithNoReference.kt b/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/codeReferences/SymbolLightPsiJavaCodeReferenceElementWithNoReference.kt index 02225d52454..948dc1b520c 100644 --- a/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/codeReferences/SymbolLightPsiJavaCodeReferenceElementWithNoReference.kt +++ b/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/codeReferences/SymbolLightPsiJavaCodeReferenceElementWithNoReference.kt @@ -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 diff --git a/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/codeReferences/SymbolLightPsiJavaCodeReferenceElementWithReference.kt b/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/codeReferences/SymbolLightPsiJavaCodeReferenceElementWithReference.kt index 41f13f711a6..049f869b24d 100644 --- a/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/codeReferences/SymbolLightPsiJavaCodeReferenceElementWithReference.kt +++ b/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/codeReferences/SymbolLightPsiJavaCodeReferenceElementWithReference.kt @@ -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 -} \ No newline at end of file + + private val nameExpression: KtSimpleNameExpression? get() = reference.element as? KtSimpleNameExpression + + override fun getReferenceName(): String? = super.getReferenceName() ?: nameExpression?.getReferencedName() + override fun getReferenceNameElement(): PsiElement? = nameExpression?.getReferencedNameElement() +}