Light-annotations: fix for reading class-literal varargs (KT-29027, IDEA-204252)

This commit is contained in:
Nicolay Mitropolsky
2018-12-26 15:54:16 +03:00
committed by Nicolay Mitropolsky
parent bcb220b919
commit ebd6caaa71
4 changed files with 123 additions and 8 deletions
@@ -157,9 +157,13 @@ class KtLightAnnotationForSourceEntry(
val valueArguments = callEntry.value.arguments
val argument = valueArguments.firstOrNull()?.getArgumentExpression() ?: return null
if (!callEntry.key.type.let { KotlinBuiltIns.isArray(it) }) return null
if (!callEntry.key.type.let { KotlinBuiltIns.isArrayOrPrimitiveArray(it) }) return null
if (argument !is KtStringTemplateExpression && argument !is KtConstantExpression && getAnnotationName(argument) == null) {
if (argument !is KtStringTemplateExpression &&
argument !is KtConstantExpression &&
argument !is KtClassLiteralExpression &&
getAnnotationName(argument) == null
) {
return null
}
@@ -159,9 +159,13 @@ class KtLightAnnotationForSourceEntry(
val valueArguments = callEntry.value.arguments
val argument = valueArguments.firstOrNull()?.getArgumentExpression() ?: return null
if (!callEntry.key.type.let { KotlinBuiltIns.isArray(it) }) return null
if (!callEntry.key.type.let { KotlinBuiltIns.isArrayOrPrimitiveArray(it) }) return null
if (argument !is KtStringTemplateExpression && argument !is KtConstantExpression && getAnnotationName(argument) == null) {
if (argument !is KtStringTemplateExpression &&
argument !is KtConstantExpression &&
argument !is KtClassLiteralExpression &&
getAnnotationName(argument) == null
) {
return null
}
@@ -474,6 +474,39 @@ class KtLightAnnotationTest : KotlinLightCodeInsightFixtureTestCase() {
}
private fun doVarargTest(type: String, parameters: List<String>) {
val paramsJoined = parameters.joinToString(", ")
myFixture.addClass(
"""
public @interface Annotation {
$type[] value() default {};
}
""".trimIndent()
)
myFixture.configureByText(
"AnnotatedClass.kt", """
@Annotation($paramsJoined)
open class AnnotatedClass
""".trimIndent()
)
myFixture.testHighlighting("Annotation.java", "AnnotatedClass.kt")
val annotations = myFixture.findClass("AnnotatedClass").expectAnnotations(1)
val annotationAttributeVal = annotations.first().findAttributeValue("value") as PsiArrayInitializerMemberValue
assertTextAndRange("($paramsJoined)", annotationAttributeVal)
UsefulTestCase.assertInstanceOf(annotationAttributeVal.parent, PsiNameValuePair::class.java)
for ((i, arg) in parameters.withIndex()) {
assertTextAndRange(arg, annotationAttributeVal.initializers[i])
}
}
fun testVarargInt() = doVarargTest("int", listOf("1", "2", "3"))
fun testVarargClasses() = doVarargTest("""Class<?>""", listOf("Any::class", "String::class", "Int::class"))
fun testVarargWithSpread() {
myFixture.addClass("""
public @interface Annotation {
@@ -27,6 +27,7 @@ import com.intellij.testFramework.LightProjectDescriptor
import com.intellij.testFramework.UsefulTestCase
import junit.framework.TestCase
import org.jetbrains.kotlin.asJava.elements.KtLightAnnotationForSourceEntry
import org.jetbrains.kotlin.asJava.elements.KtLightPsiArrayInitializerMemberValue
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.idea.completion.test.assertInstanceOf
import org.jetbrains.kotlin.idea.facet.configureFacet
@@ -241,6 +242,44 @@ class KtLightAnnotationTest : KotlinLightCodeInsightFixtureTestCase() {
)
}
fun testArrayOfClassLiterals() {
myFixture.addClass(
"""
public @interface ClazzAnnotation {
Class<?>[] cls();
}
""".trimIndent()
)
myFixture.configureByText(
"AnnotatedClass.kt", """
@ClazzAnnotation(cls = [String::class, Throwable::class, ShortArray::class, Array<Array<Int>>::class, Long::class, Unit::class])
class AnnotatedClass
""".trimIndent()
)
myFixture.testHighlighting("AnnotatedClass.kt")
val annotations = myFixture.findClass("AnnotatedClass").expectAnnotations(1)
val annotationAttributeVal = annotations.first().findAttributeValue("cls") as KtLightPsiArrayInitializerMemberValue
assertTextAndRange(
"[String::class, Throwable::class, ShortArray::class, Array<Array<Int>>::class, Long::class, Unit::class]",
annotationAttributeVal
)
val classLiterals = annotationAttributeVal.initializers.toList().map { it as PsiClassObjectAccessExpression }
val scope = GlobalSearchScope.everythingScope(project)
TestCase.assertEquals(
listOf(
PsiType.getJavaLangString(myFixture.psiManager, scope),
PsiType.getTypeByName("java.lang.Throwable", project, scope),
PsiType.SHORT.createArrayType(),
PsiType.getTypeByName("java.lang.Integer", project, scope).createArrayType().createArrayType(),
PsiType.LONG,
PsiType.getTypeByName("kotlin.Unit", project, scope)
),
classLiterals.map { it.operand.type }
)
}
fun testAnnotationsInAnnotationsArrayDeclarations() {
myFixture.addClass("""
public @interface OuterAnnotation {
@@ -437,6 +476,39 @@ class KtLightAnnotationTest : KotlinLightCodeInsightFixtureTestCase() {
}
private fun doVarargTest(type: String, parameters: List<String>) {
val paramsJoined = parameters.joinToString(", ")
myFixture.addClass(
"""
public @interface Annotation {
$type[] value() default {};
}
""".trimIndent()
)
myFixture.configureByText(
"AnnotatedClass.kt", """
@Annotation($paramsJoined)
open class AnnotatedClass
""".trimIndent()
)
myFixture.testHighlighting("Annotation.java", "AnnotatedClass.kt")
val annotations = myFixture.findClass("AnnotatedClass").expectAnnotations(1)
val annotationAttributeVal = annotations.first().findAttributeValue("value") as PsiArrayInitializerMemberValue
assertTextAndRange("($paramsJoined)", annotationAttributeVal)
UsefulTestCase.assertInstanceOf(annotationAttributeVal.parent, PsiNameValuePair::class.java)
for ((i, arg) in parameters.withIndex()) {
assertTextAndRange(arg, annotationAttributeVal.initializers[i])
}
}
fun testVarargInt() = doVarargTest("int", listOf("1", "2", "3"))
fun testVarargClasses() = doVarargTest("""Class<?>""", listOf("Any::class", "String::class", "Int::class"))
fun testVarargWithSpread() {
myFixture.addClass("""
public @interface Annotation {
@@ -687,10 +759,12 @@ class KtLightAnnotationTest : KotlinLightCodeInsightFixtureTestCase() {
}
private fun PsiModifierListOwner.expectAnnotations(number: Int): Array<PsiAnnotation> =
this.modifierList!!.annotations.apply {
TestCase.assertEquals("expected one annotation, found ${this.joinToString(", ") { it.qualifiedName ?: "unknown" }}",
number, size)
}
this.modifierList!!.annotations.apply {
assertEquals(
"expected $number annotation(s), found [${this.joinToString(", ") { it.qualifiedName ?: "unknown" }}]",
number, size
)
}
private fun configureKotlinVersion(version: String) {
WriteAction.run<Throwable> {