diff --git a/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/annotations/SymbolAnnotationValues.kt b/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/annotations/SymbolAnnotationValues.kt index 49eaf4bc44b..d5b20dc6f8f 100644 --- a/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/annotations/SymbolAnnotationValues.kt +++ b/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/annotations/SymbolAnnotationValues.kt @@ -6,8 +6,8 @@ package org.jetbrains.kotlin.light.classes.symbol.annotations import com.intellij.openapi.util.Key -import com.intellij.openapi.util.NlsSafe import com.intellij.psi.* +import com.intellij.psi.impl.light.LightTypeElement import org.jetbrains.kotlin.asJava.elements.KtLightElementBase import org.jetbrains.kotlin.light.classes.symbol.toArrayIfNotEmptyOrDefault import org.jetbrains.kotlin.psi.KtElement @@ -63,6 +63,20 @@ internal class SymbolPsiExpression( override fun getText(): String = psiExpression.text } +internal class SymbolPsiClassObjectAccessExpression( + override val kotlinOrigin: KtElement?, + lightParent: PsiElement, + private val psiType: PsiType, +) : SymbolPsiAnnotationMemberValue(kotlinOrigin, lightParent), PsiClassObjectAccessExpression { + override fun getType(): PsiType = psiType + override fun getOperand(): PsiTypeElement = LightTypeElementWithParent(this, type) + override fun getText(): String = type.getCanonicalText(false) + ".class" +} + +private class LightTypeElementWithParent(private val lightParent: PsiElement, type: PsiType) : LightTypeElement(lightParent.manager, type) { + override fun getParent(): PsiElement = lightParent +} + internal class SymbolPsiReference( override val kotlinOrigin: KtElement?, lightParent: PsiElement, diff --git a/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/annotations/SymbolLightAbstractAnnotationParameterList.kt b/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/annotations/SymbolLightAbstractAnnotationParameterList.kt index badf80b241a..13ed398d0bd 100644 --- a/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/annotations/SymbolLightAbstractAnnotationParameterList.kt +++ b/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/annotations/SymbolLightAbstractAnnotationParameterList.kt @@ -5,7 +5,9 @@ package org.jetbrains.kotlin.light.classes.symbol.annotations +import com.intellij.psi.JavaElementVisitor import com.intellij.psi.PsiAnnotationParameterList +import com.intellij.psi.PsiElementVisitor import org.jetbrains.kotlin.analysis.api.annotations.KtNamedAnnotationValue import org.jetbrains.kotlin.asJava.classes.lazyPub import org.jetbrains.kotlin.asJava.elements.KtLightElementBase @@ -15,6 +17,14 @@ internal sealed class SymbolLightAbstractAnnotationParameterList( parent: SymbolLightAbstractAnnotation, ) : KtLightElementBase(parent), PsiAnnotationParameterList { override val kotlinOrigin: KtElement? get() = (parent as SymbolLightAbstractAnnotation).kotlinOrigin?.valueArgumentList + + override fun accept(visitor: PsiElementVisitor) { + if (visitor is JavaElementVisitor) { + visitor.visitAnnotationParameterList(this) + } else { + visitor.visitElement(this) + } + } } @Suppress("NOTHING_TO_INLINE") diff --git a/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/annotations/SymbolNameValuePairForAnnotationArgument.kt b/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/annotations/SymbolNameValuePairForAnnotationArgument.kt index 598cc3ba307..5ace8455df9 100644 --- a/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/annotations/SymbolNameValuePairForAnnotationArgument.kt +++ b/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/annotations/SymbolNameValuePairForAnnotationArgument.kt @@ -38,4 +38,12 @@ internal class SymbolNameValuePairForAnnotationArgument( override fun getLiteralValue(): String? = (value as? PsiLiteralExpression)?.value?.toString() override fun getName(): String = constantValue.name.asString() + + override fun accept(visitor: PsiElementVisitor) { + if (visitor is JavaElementVisitor) { + visitor.visitNameValuePair(this) + } else { + visitor.visitElement(this) + } + } } diff --git a/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/symbolLightUtils.kt b/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/symbolLightUtils.kt index 4f22c9e24f4..2e330f29fb5 100644 --- a/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/symbolLightUtils.kt +++ b/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/symbolLightUtils.kt @@ -205,22 +205,20 @@ private fun KtEnumEntryAnnotationValue.asPsiReferenceExpression(parent: PsiEleme return SymbolPsiReference(sourcePsi, parent, psiReference) } -private fun KtKClassAnnotationValue.toAnnotationMemberValue(parent: PsiElement): PsiExpression? { +private fun KtKClassAnnotationValue.toAnnotationMemberValue(parent: PsiElement): SymbolPsiClassObjectAccessExpression? { val typeString = when (this) { is KtKClassAnnotationValue.KtNonLocalKClassAnnotationValue -> classId.asSingleFqName().asString() is KtKClassAnnotationValue.KtLocalKClassAnnotationValue -> null is KtKClassAnnotationValue.KtErrorClassAnnotationValue -> unresolvedQualifierName } ?: return null - val canonicalText = psiType( + val psiType = psiType( kotlinFqName = typeString, context = parent, boxPrimitiveType = false, /* TODO value.arrayNestedness > 0*/ - ).let(TypeConversionUtil::erasure).getCanonicalText(false) + ).let(TypeConversionUtil::erasure) - return parent.project.withElementFactorySafe { - createExpressionFromText("$canonicalText.class", parent) - } + return SymbolPsiClassObjectAccessExpression(sourcePsi, parent, psiType) } private fun KtConstantValue.asStringForPsiExpression(): String = diff --git a/analysis/symbol-light-classes/tests/org/jetbrains/kotlin/light/classes/symbol/base/AbstractSymbolLightClassesParentingTestBase.kt b/analysis/symbol-light-classes/tests/org/jetbrains/kotlin/light/classes/symbol/base/AbstractSymbolLightClassesParentingTestBase.kt index d38d2291c55..83b59bb12df 100644 --- a/analysis/symbol-light-classes/tests/org/jetbrains/kotlin/light/classes/symbol/base/AbstractSymbolLightClassesParentingTestBase.kt +++ b/analysis/symbol-light-classes/tests/org/jetbrains/kotlin/light/classes/symbol/base/AbstractSymbolLightClassesParentingTestBase.kt @@ -165,6 +165,30 @@ open class AbstractSymbolLightClassesParentingTestBase( } } + override fun visitNameValuePair(pair: PsiNameValuePair) { + checkParentAndVisitChildren(pair) { + value?.let(::checkAnnotationMemberValue) + } + } + + override fun visitAnnotationParameterList(list: PsiAnnotationParameterList) { + checkParentAndVisitChildren(list) { visitor -> + attributes.forEach { it.accept(visitor) } + } + } + + private fun checkAnnotationMemberValue(memberValue: PsiAnnotationMemberValue) { + checkParentAndVisitChildren(memberValue) { + if (this is PsiClassObjectAccessExpression) { + checkDeclarationParent(this.operand) + } + + if (this is PsiArrayInitializerMemberValue) { + this.initializers.forEach(::checkAnnotationMemberValue) + } + } + } + private fun checkDeclarationParent(declaration: PsiElement) { val expectedParent = declarationStack.lastOrNull() ?: return val parent = declaration.parent @@ -217,6 +241,10 @@ open class AbstractSymbolLightClassesParentingTestBase( assertions.assertTrue(modifierList.annotations.any { it == annotation }) { "$annotation is not found in ${modifierList.annotations}" } + + checkParentAndVisitChildren(annotation, notCheckItself = true) { visitor -> + parameterList.accept(visitor) + } } } } diff --git a/analysis/symbol-light-classes/tests/org/jetbrains/kotlin/light/classes/symbol/base/AbstractSymbolLightClassesParentingTestByFqName.kt b/analysis/symbol-light-classes/tests/org/jetbrains/kotlin/light/classes/symbol/base/AbstractSymbolLightClassesParentingTestByFqName.kt index 29d5473f138..bf6567beea0 100644 --- a/analysis/symbol-light-classes/tests/org/jetbrains/kotlin/light/classes/symbol/base/AbstractSymbolLightClassesParentingTestByFqName.kt +++ b/analysis/symbol-light-classes/tests/org/jetbrains/kotlin/light/classes/symbol/base/AbstractSymbolLightClassesParentingTestByFqName.kt @@ -23,6 +23,8 @@ abstract class AbstractSymbolLightClassesParentingTestByFqName( val ktFile = ktFiles.first() val lightClass = findLightClass(fqName, ktFile.project) ?: return - lightClass.accept(createLightElementsVisitor(module.directives, testServices.assertions)) + ignoreExceptionIfIgnoreDirectivePresent(module) { + lightClass.accept(createLightElementsVisitor(module.directives, testServices.assertions)) + } } } diff --git a/analysis/symbol-light-classes/tests/org/jetbrains/kotlin/light/classes/symbol/base/AbstractSymbolLightClassesTestBase.kt b/analysis/symbol-light-classes/tests/org/jetbrains/kotlin/light/classes/symbol/base/AbstractSymbolLightClassesTestBase.kt index f50ba59077f..7314386c672 100644 --- a/analysis/symbol-light-classes/tests/org/jetbrains/kotlin/light/classes/symbol/base/AbstractSymbolLightClassesTestBase.kt +++ b/analysis/symbol-light-classes/tests/org/jetbrains/kotlin/light/classes/symbol/base/AbstractSymbolLightClassesTestBase.kt @@ -96,7 +96,7 @@ abstract class AbstractSymbolLightClassesTestBase( project: Project ): String - private inline fun ignoreExceptionIfIgnoreDirectivePresent(module: TestModule, action: () -> Unit) { + protected fun ignoreExceptionIfIgnoreDirectivePresent(module: TestModule, action: () -> Unit) { try { action() } catch (e: Throwable) {