[FIR LC] KT-58330 Introduce SymbolPsiClassObjectAccessExpression
A PSI expression created with `createExpressionFromText` has dummy parent, which might break some inspections (for example, it breaks `JamAttributeElement` class in Spring Framework Plugin in intellij) Modify `AbstractSymbolLightClassesParentingTestBase` to check values of annotations in light classes; implement `accept` in some of them ^KT-58330 Fixed Merge-request: KT-MR-9903 Merged-by: Roman Golyshev <roman.golyshev@jetbrains.com>
This commit is contained in:
committed by
Space Team
parent
957d8ee3d2
commit
0dbf218f0b
+15
-1
@@ -6,8 +6,8 @@
|
|||||||
package org.jetbrains.kotlin.light.classes.symbol.annotations
|
package org.jetbrains.kotlin.light.classes.symbol.annotations
|
||||||
|
|
||||||
import com.intellij.openapi.util.Key
|
import com.intellij.openapi.util.Key
|
||||||
import com.intellij.openapi.util.NlsSafe
|
|
||||||
import com.intellij.psi.*
|
import com.intellij.psi.*
|
||||||
|
import com.intellij.psi.impl.light.LightTypeElement
|
||||||
import org.jetbrains.kotlin.asJava.elements.KtLightElementBase
|
import org.jetbrains.kotlin.asJava.elements.KtLightElementBase
|
||||||
import org.jetbrains.kotlin.light.classes.symbol.toArrayIfNotEmptyOrDefault
|
import org.jetbrains.kotlin.light.classes.symbol.toArrayIfNotEmptyOrDefault
|
||||||
import org.jetbrains.kotlin.psi.KtElement
|
import org.jetbrains.kotlin.psi.KtElement
|
||||||
@@ -63,6 +63,20 @@ internal class SymbolPsiExpression(
|
|||||||
override fun getText(): String = psiExpression.text
|
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(
|
internal class SymbolPsiReference(
|
||||||
override val kotlinOrigin: KtElement?,
|
override val kotlinOrigin: KtElement?,
|
||||||
lightParent: PsiElement,
|
lightParent: PsiElement,
|
||||||
|
|||||||
+10
@@ -5,7 +5,9 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.light.classes.symbol.annotations
|
package org.jetbrains.kotlin.light.classes.symbol.annotations
|
||||||
|
|
||||||
|
import com.intellij.psi.JavaElementVisitor
|
||||||
import com.intellij.psi.PsiAnnotationParameterList
|
import com.intellij.psi.PsiAnnotationParameterList
|
||||||
|
import com.intellij.psi.PsiElementVisitor
|
||||||
import org.jetbrains.kotlin.analysis.api.annotations.KtNamedAnnotationValue
|
import org.jetbrains.kotlin.analysis.api.annotations.KtNamedAnnotationValue
|
||||||
import org.jetbrains.kotlin.asJava.classes.lazyPub
|
import org.jetbrains.kotlin.asJava.classes.lazyPub
|
||||||
import org.jetbrains.kotlin.asJava.elements.KtLightElementBase
|
import org.jetbrains.kotlin.asJava.elements.KtLightElementBase
|
||||||
@@ -15,6 +17,14 @@ internal sealed class SymbolLightAbstractAnnotationParameterList(
|
|||||||
parent: SymbolLightAbstractAnnotation,
|
parent: SymbolLightAbstractAnnotation,
|
||||||
) : KtLightElementBase(parent), PsiAnnotationParameterList {
|
) : KtLightElementBase(parent), PsiAnnotationParameterList {
|
||||||
override val kotlinOrigin: KtElement? get() = (parent as SymbolLightAbstractAnnotation).kotlinOrigin?.valueArgumentList
|
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")
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
|
|||||||
+8
@@ -38,4 +38,12 @@ internal class SymbolNameValuePairForAnnotationArgument(
|
|||||||
override fun getLiteralValue(): String? = (value as? PsiLiteralExpression)?.value?.toString()
|
override fun getLiteralValue(): String? = (value as? PsiLiteralExpression)?.value?.toString()
|
||||||
|
|
||||||
override fun getName(): String = constantValue.name.asString()
|
override fun getName(): String = constantValue.name.asString()
|
||||||
|
|
||||||
|
override fun accept(visitor: PsiElementVisitor) {
|
||||||
|
if (visitor is JavaElementVisitor) {
|
||||||
|
visitor.visitNameValuePair(this)
|
||||||
|
} else {
|
||||||
|
visitor.visitElement(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-6
@@ -205,22 +205,20 @@ private fun KtEnumEntryAnnotationValue.asPsiReferenceExpression(parent: PsiEleme
|
|||||||
return SymbolPsiReference(sourcePsi, parent, psiReference)
|
return SymbolPsiReference(sourcePsi, parent, psiReference)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun KtKClassAnnotationValue.toAnnotationMemberValue(parent: PsiElement): PsiExpression? {
|
private fun KtKClassAnnotationValue.toAnnotationMemberValue(parent: PsiElement): SymbolPsiClassObjectAccessExpression? {
|
||||||
val typeString = when (this) {
|
val typeString = when (this) {
|
||||||
is KtKClassAnnotationValue.KtNonLocalKClassAnnotationValue -> classId.asSingleFqName().asString()
|
is KtKClassAnnotationValue.KtNonLocalKClassAnnotationValue -> classId.asSingleFqName().asString()
|
||||||
is KtKClassAnnotationValue.KtLocalKClassAnnotationValue -> null
|
is KtKClassAnnotationValue.KtLocalKClassAnnotationValue -> null
|
||||||
is KtKClassAnnotationValue.KtErrorClassAnnotationValue -> unresolvedQualifierName
|
is KtKClassAnnotationValue.KtErrorClassAnnotationValue -> unresolvedQualifierName
|
||||||
} ?: return null
|
} ?: return null
|
||||||
|
|
||||||
val canonicalText = psiType(
|
val psiType = psiType(
|
||||||
kotlinFqName = typeString,
|
kotlinFqName = typeString,
|
||||||
context = parent,
|
context = parent,
|
||||||
boxPrimitiveType = false, /* TODO value.arrayNestedness > 0*/
|
boxPrimitiveType = false, /* TODO value.arrayNestedness > 0*/
|
||||||
).let(TypeConversionUtil::erasure).getCanonicalText(false)
|
).let(TypeConversionUtil::erasure)
|
||||||
|
|
||||||
return parent.project.withElementFactorySafe {
|
return SymbolPsiClassObjectAccessExpression(sourcePsi, parent, psiType)
|
||||||
createExpressionFromText("$canonicalText.class", parent)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun KtConstantValue.asStringForPsiExpression(): String =
|
private fun KtConstantValue.asStringForPsiExpression(): String =
|
||||||
|
|||||||
+28
@@ -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) {
|
private fun checkDeclarationParent(declaration: PsiElement) {
|
||||||
val expectedParent = declarationStack.lastOrNull() ?: return
|
val expectedParent = declarationStack.lastOrNull() ?: return
|
||||||
val parent = declaration.parent
|
val parent = declaration.parent
|
||||||
@@ -217,6 +241,10 @@ open class AbstractSymbolLightClassesParentingTestBase(
|
|||||||
assertions.assertTrue(modifierList.annotations.any { it == annotation }) {
|
assertions.assertTrue(modifierList.annotations.any { it == annotation }) {
|
||||||
"$annotation is not found in ${modifierList.annotations}"
|
"$annotation is not found in ${modifierList.annotations}"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
checkParentAndVisitChildren(annotation, notCheckItself = true) { visitor ->
|
||||||
|
parameterList.accept(visitor)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-1
@@ -23,6 +23,8 @@ abstract class AbstractSymbolLightClassesParentingTestByFqName(
|
|||||||
val ktFile = ktFiles.first()
|
val ktFile = ktFiles.first()
|
||||||
val lightClass = findLightClass(fqName, ktFile.project) ?: return
|
val lightClass = findLightClass(fqName, ktFile.project) ?: return
|
||||||
|
|
||||||
lightClass.accept(createLightElementsVisitor(module.directives, testServices.assertions))
|
ignoreExceptionIfIgnoreDirectivePresent(module) {
|
||||||
|
lightClass.accept(createLightElementsVisitor(module.directives, testServices.assertions))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -96,7 +96,7 @@ abstract class AbstractSymbolLightClassesTestBase(
|
|||||||
project: Project
|
project: Project
|
||||||
): String
|
): String
|
||||||
|
|
||||||
private inline fun ignoreExceptionIfIgnoreDirectivePresent(module: TestModule, action: () -> Unit) {
|
protected fun ignoreExceptionIfIgnoreDirectivePresent(module: TestModule, action: () -> Unit) {
|
||||||
try {
|
try {
|
||||||
action()
|
action()
|
||||||
} catch (e: Throwable) {
|
} catch (e: Throwable) {
|
||||||
|
|||||||
Reference in New Issue
Block a user