lightAnnotations: KtLightPsiClassObjectAccessExpression added
as implementation of `PsiClassObjectAccessExpression` for class literals in annotations
This commit is contained in:
committed by
xiexed
parent
92727d2945
commit
0fb879dfc2
+36
-18
@@ -9,14 +9,16 @@ import com.intellij.openapi.util.text.StringUtil
|
||||
import com.intellij.psi.*
|
||||
import com.intellij.psi.impl.LanguageConstantExpressionEvaluator
|
||||
import com.intellij.psi.impl.light.LightIdentifier
|
||||
import com.intellij.psi.impl.light.LightTypeElement
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import org.jetbrains.kotlin.asJava.LightClassGenerationSupport
|
||||
import org.jetbrains.kotlin.psi.KtElement
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
import org.jetbrains.kotlin.psi.KtPsiFactory
|
||||
import org.jetbrains.kotlin.psi.KtValueArgument
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.SimpleType
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
|
||||
class KtLightPsiArrayInitializerMemberValue(
|
||||
override val kotlinOrigin: KtElement,
|
||||
@@ -30,7 +32,7 @@ class KtLightPsiArrayInitializerMemberValue(
|
||||
override fun isPhysical(): Boolean = false
|
||||
}
|
||||
|
||||
class KtLightPsiLiteral(
|
||||
open class KtLightPsiLiteral(
|
||||
override val kotlinOrigin: KtExpression,
|
||||
val lightParent: PsiElement
|
||||
) : KtLightElementBase(lightParent), PsiLiteralExpression {
|
||||
@@ -41,19 +43,7 @@ class KtLightPsiLiteral(
|
||||
override fun getType(): PsiType? {
|
||||
val bindingContext = LightClassGenerationSupport.getInstance(this.project).analyze(kotlinOrigin)
|
||||
val kotlinType = bindingContext[BindingContext.EXPECTED_EXPRESSION_TYPE, kotlinOrigin] ?: return null
|
||||
val typeFqName = kotlinType.constructor.declarationDescriptor?.fqNameSafe?.asString() ?: return null
|
||||
return when (typeFqName) {
|
||||
"kotlin.Int" -> PsiType.INT
|
||||
"kotlin.Long" -> PsiType.LONG
|
||||
"kotlin.Short" -> PsiType.SHORT
|
||||
"kotlin.Boolean" -> PsiType.BOOLEAN
|
||||
"kotlin.Byte" -> PsiType.BYTE
|
||||
"kotlin.Char" -> PsiType.CHAR
|
||||
"kotlin.Double" -> PsiType.DOUBLE
|
||||
"kotlin.Float" -> PsiType.FLOAT
|
||||
"kotlin.String" -> PsiType.getJavaLangString(kotlinOrigin.manager, GlobalSearchScope.projectScope(kotlinOrigin.project))
|
||||
else -> null
|
||||
}
|
||||
return psiType(kotlinType, kotlinOrigin)
|
||||
}
|
||||
|
||||
override fun getParent(): PsiElement = lightParent
|
||||
@@ -70,6 +60,34 @@ class KtLightPsiLiteral(
|
||||
override fun getReferences(): Array<out PsiReference> = kotlinOrigin.references
|
||||
}
|
||||
|
||||
class KtLightPsiClassObjectAccessExpression(override val kotlinOrigin: KtClassLiteralExpression, lightParent: PsiElement) :
|
||||
KtLightPsiLiteral(kotlinOrigin, lightParent), PsiClassObjectAccessExpression {
|
||||
override fun getType(): PsiType {
|
||||
val bindingContext = LightClassGenerationSupport.getInstance(this.project).analyze(kotlinOrigin)
|
||||
val kotlinType = bindingContext[BindingContext.COMPILE_TIME_VALUE, kotlinOrigin]
|
||||
?.getValue(TypeUtils.NO_EXPECTED_TYPE).safeAs<SimpleType>() ?: return PsiType.VOID
|
||||
return psiType(kotlinType, kotlinOrigin) ?: return PsiType.VOID
|
||||
}
|
||||
|
||||
override fun getOperand(): PsiTypeElement = LightTypeElement(kotlinOrigin.manager, type)
|
||||
}
|
||||
|
||||
private fun psiType(kotlinType: KotlinType, context: PsiElement): PsiType? {
|
||||
val typeFqName = kotlinType.constructor.declarationDescriptor?.fqNameSafe?.asString() ?: return null
|
||||
return when (typeFqName) {
|
||||
"kotlin.Int" -> PsiType.INT
|
||||
"kotlin.Long" -> PsiType.LONG
|
||||
"kotlin.Short" -> PsiType.SHORT
|
||||
"kotlin.Boolean" -> PsiType.BOOLEAN
|
||||
"kotlin.Byte" -> PsiType.BYTE
|
||||
"kotlin.Char" -> PsiType.CHAR
|
||||
"kotlin.Double" -> PsiType.DOUBLE
|
||||
"kotlin.Float" -> PsiType.FLOAT
|
||||
"kotlin.String" -> PsiType.getJavaLangString(context.manager, GlobalSearchScope.projectScope(context.project))
|
||||
else -> PsiType.getTypeByName(typeFqName, context.project, context.resolveScope)
|
||||
}
|
||||
}
|
||||
|
||||
class KtLightPsiNameValuePair private constructor(
|
||||
override val kotlinOrigin: KtElement,
|
||||
val valueArgument: KtValueArgument,
|
||||
|
||||
+36
-18
@@ -9,14 +9,16 @@ import com.intellij.openapi.util.text.StringUtil
|
||||
import com.intellij.psi.*
|
||||
import com.intellij.psi.impl.LanguageConstantExpressionEvaluator
|
||||
import com.intellij.psi.impl.light.LightIdentifier
|
||||
import com.intellij.psi.impl.light.LightTypeElement
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import org.jetbrains.kotlin.asJava.LightClassGenerationSupport
|
||||
import org.jetbrains.kotlin.psi.KtElement
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
import org.jetbrains.kotlin.psi.KtPsiFactory
|
||||
import org.jetbrains.kotlin.psi.KtValueArgument
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.SimpleType
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
|
||||
class KtLightPsiArrayInitializerMemberValue(
|
||||
override val kotlinOrigin: KtElement,
|
||||
@@ -30,7 +32,7 @@ class KtLightPsiArrayInitializerMemberValue(
|
||||
override fun isPhysical(): Boolean = true
|
||||
}
|
||||
|
||||
class KtLightPsiLiteral(
|
||||
open class KtLightPsiLiteral(
|
||||
override val kotlinOrigin: KtExpression,
|
||||
val lightParent: PsiElement
|
||||
) : KtLightElementBase(lightParent), PsiLiteralExpression {
|
||||
@@ -41,19 +43,7 @@ class KtLightPsiLiteral(
|
||||
override fun getType(): PsiType? {
|
||||
val bindingContext = LightClassGenerationSupport.getInstance(this.project).analyze(kotlinOrigin)
|
||||
val kotlinType = bindingContext[BindingContext.EXPECTED_EXPRESSION_TYPE, kotlinOrigin] ?: return null
|
||||
val typeFqName = kotlinType.constructor.declarationDescriptor?.fqNameSafe?.asString() ?: return null
|
||||
return when (typeFqName) {
|
||||
"kotlin.Int" -> PsiType.INT
|
||||
"kotlin.Long" -> PsiType.LONG
|
||||
"kotlin.Short" -> PsiType.SHORT
|
||||
"kotlin.Boolean" -> PsiType.BOOLEAN
|
||||
"kotlin.Byte" -> PsiType.BYTE
|
||||
"kotlin.Char" -> PsiType.CHAR
|
||||
"kotlin.Double" -> PsiType.DOUBLE
|
||||
"kotlin.Float" -> PsiType.FLOAT
|
||||
"kotlin.String" -> PsiType.getJavaLangString(kotlinOrigin.manager, GlobalSearchScope.projectScope(kotlinOrigin.project))
|
||||
else -> null
|
||||
}
|
||||
return psiType(kotlinType, kotlinOrigin)
|
||||
}
|
||||
|
||||
override fun getParent(): PsiElement = lightParent
|
||||
@@ -70,6 +60,34 @@ class KtLightPsiLiteral(
|
||||
override fun getReferences(): Array<out PsiReference> = kotlinOrigin.references
|
||||
}
|
||||
|
||||
class KtLightPsiClassObjectAccessExpression(override val kotlinOrigin: KtClassLiteralExpression, lightParent: PsiElement) :
|
||||
KtLightPsiLiteral(kotlinOrigin, lightParent), PsiClassObjectAccessExpression {
|
||||
override fun getType(): PsiType {
|
||||
val bindingContext = LightClassGenerationSupport.getInstance(this.project).analyze(kotlinOrigin)
|
||||
val kotlinType = bindingContext[BindingContext.COMPILE_TIME_VALUE, kotlinOrigin]
|
||||
?.getValue(TypeUtils.NO_EXPECTED_TYPE).safeAs<SimpleType>() ?: return PsiType.VOID
|
||||
return psiType(kotlinType, kotlinOrigin) ?: return PsiType.VOID
|
||||
}
|
||||
|
||||
override fun getOperand(): PsiTypeElement = LightTypeElement(kotlinOrigin.manager, type)
|
||||
}
|
||||
|
||||
private fun psiType(kotlinType: KotlinType, context: PsiElement): PsiType? {
|
||||
val typeFqName = kotlinType.constructor.declarationDescriptor?.fqNameSafe?.asString() ?: return null
|
||||
return when (typeFqName) {
|
||||
"kotlin.Int" -> PsiType.INT
|
||||
"kotlin.Long" -> PsiType.LONG
|
||||
"kotlin.Short" -> PsiType.SHORT
|
||||
"kotlin.Boolean" -> PsiType.BOOLEAN
|
||||
"kotlin.Byte" -> PsiType.BYTE
|
||||
"kotlin.Char" -> PsiType.CHAR
|
||||
"kotlin.Double" -> PsiType.DOUBLE
|
||||
"kotlin.Float" -> PsiType.FLOAT
|
||||
"kotlin.String" -> PsiType.getJavaLangString(context.manager, GlobalSearchScope.projectScope(context.project))
|
||||
else -> PsiType.getTypeByName(typeFqName, context.project, context.resolveScope)
|
||||
}
|
||||
}
|
||||
|
||||
class KtLightPsiNameValuePair private constructor(
|
||||
override val kotlinOrigin: KtElement,
|
||||
val valueArgument: KtValueArgument,
|
||||
|
||||
@@ -330,6 +330,9 @@ private fun KtElement.getResolvedCall(): ResolvedCall<out CallableDescriptor>? {
|
||||
fun convertToLightAnnotationMemberValue(lightParent: PsiElement, argument: KtExpression): PsiAnnotationMemberValue {
|
||||
val argument = unwrapCall(argument)
|
||||
when (argument) {
|
||||
is KtClassLiteralExpression -> {
|
||||
return KtLightPsiClassObjectAccessExpression(argument, lightParent)
|
||||
}
|
||||
is KtStringTemplateExpression, is KtConstantExpression -> {
|
||||
return KtLightPsiLiteral(argument, lightParent)
|
||||
}
|
||||
|
||||
+6
@@ -22,6 +22,7 @@ import com.intellij.psi.*
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import org.jetbrains.annotations.NotNull
|
||||
import org.jetbrains.annotations.Nullable
|
||||
import org.jetbrains.annotations.TestOnly
|
||||
import org.jetbrains.kotlin.asJava.LightClassGenerationSupport
|
||||
import org.jetbrains.kotlin.asJava.classes.cannotModify
|
||||
import org.jetbrains.kotlin.asJava.classes.lazyPub
|
||||
@@ -331,6 +332,9 @@ private fun KtElement.getResolvedCall(): ResolvedCall<out CallableDescriptor>? {
|
||||
fun convertToLightAnnotationMemberValue(lightParent: PsiElement, argument: KtExpression): PsiAnnotationMemberValue {
|
||||
val argument = unwrapCall(argument)
|
||||
when (argument) {
|
||||
is KtClassLiteralExpression -> {
|
||||
return KtLightPsiClassObjectAccessExpression(argument, lightParent)
|
||||
}
|
||||
is KtStringTemplateExpression, is KtConstantExpression -> {
|
||||
return KtLightPsiLiteral(argument, lightParent)
|
||||
}
|
||||
@@ -393,8 +397,10 @@ private fun getAnnotationName(callee: KtExpression): String? {
|
||||
return null
|
||||
}
|
||||
|
||||
@TestOnly
|
||||
var accessAnnotationsClsDelegateIsAllowed = false
|
||||
|
||||
@TestOnly
|
||||
fun <T> withAllowedAnnotationsClsDelegate(body: () -> T): T {
|
||||
val prev = accessAnnotationsClsDelegateIsAllowed
|
||||
try {
|
||||
|
||||
@@ -30,6 +30,7 @@ import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.idea.completion.test.assertInstanceOf
|
||||
import org.jetbrains.kotlin.idea.facet.configureFacet
|
||||
import org.jetbrains.kotlin.idea.facet.getOrCreateFacet
|
||||
import org.jetbrains.kotlin.idea.search.projectScope
|
||||
import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase
|
||||
import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor
|
||||
|
||||
@@ -208,6 +209,32 @@ class KtLightAnnotationTest : KotlinLightCodeInsightFixtureTestCase() {
|
||||
})
|
||||
}
|
||||
|
||||
fun testClassLiteral() {
|
||||
myFixture.addClass(
|
||||
"""
|
||||
public @interface ClazzAnnotation {
|
||||
Class<?> cls();
|
||||
}
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
myFixture.configureByText(
|
||||
"AnnotatedClass.kt", """
|
||||
@ClazzAnnotation(cls = String::class)
|
||||
class AnnotatedClass
|
||||
""".trimIndent()
|
||||
)
|
||||
myFixture.testHighlighting("AnnotatedClass.kt")
|
||||
|
||||
val annotations = myFixture.findClass("AnnotatedClass").expectAnnotations(1)
|
||||
val annotationAttributeVal = annotations.first().findAttributeValue("cls") as PsiClassObjectAccessExpression
|
||||
assertTextAndRange("String::class", annotationAttributeVal)
|
||||
TestCase.assertEquals(
|
||||
PsiType.getJavaLangString(myFixture.psiManager, myFixture.project.projectScope()),
|
||||
annotationAttributeVal.operand.type
|
||||
)
|
||||
}
|
||||
|
||||
fun testAnnotationsInAnnotationsArrayDeclarations() {
|
||||
myFixture.addClass("""
|
||||
public @interface OuterAnnotation {
|
||||
|
||||
@@ -30,6 +30,7 @@ import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.idea.completion.test.assertInstanceOf
|
||||
import org.jetbrains.kotlin.idea.facet.configureFacet
|
||||
import org.jetbrains.kotlin.idea.facet.getOrCreateFacet
|
||||
import org.jetbrains.kotlin.idea.search.projectScope
|
||||
import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase
|
||||
import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor
|
||||
|
||||
@@ -209,6 +210,32 @@ class KtLightAnnotationTest : KotlinLightCodeInsightFixtureTestCase() {
|
||||
})
|
||||
}
|
||||
|
||||
fun testClassLiteral() {
|
||||
myFixture.addClass(
|
||||
"""
|
||||
public @interface ClazzAnnotation {
|
||||
Class<?> cls();
|
||||
}
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
myFixture.configureByText(
|
||||
"AnnotatedClass.kt", """
|
||||
@ClazzAnnotation(cls = String::class)
|
||||
class AnnotatedClass
|
||||
""".trimIndent()
|
||||
)
|
||||
myFixture.testHighlighting("AnnotatedClass.kt")
|
||||
|
||||
val annotations = myFixture.findClass("AnnotatedClass").expectAnnotations(1)
|
||||
val annotationAttributeVal = annotations.first().findAttributeValue("cls") as PsiClassObjectAccessExpression
|
||||
assertTextAndRange("String::class", annotationAttributeVal)
|
||||
TestCase.assertEquals(
|
||||
PsiType.getJavaLangString(myFixture.psiManager, myFixture.project.projectScope()),
|
||||
annotationAttributeVal.operand.type
|
||||
)
|
||||
}
|
||||
|
||||
fun testAnnotationsInAnnotationsArrayDeclarations() {
|
||||
myFixture.addClass("""
|
||||
public @interface OuterAnnotation {
|
||||
|
||||
Reference in New Issue
Block a user