Kapt: Support nested annotations property.
Also do not rely on Java class comparison, check against qualified names. (cherry picked from commit 7610945)
This commit is contained in:
committed by
Yan Zhulanow
parent
49bd303988
commit
a8b577cd09
@@ -0,0 +1,7 @@
|
|||||||
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
|
annotation class Anno(val a: Anno2, val b: Array<Anno2>, val c: String, val d: KClass<*>, val e: Array<KClass<*>>)
|
||||||
|
annotation class Anno2(val name: String)
|
||||||
|
|
||||||
|
@Anno(a = Anno2("Tim"), b = arrayOf(Anno2("Kate"), Anno2("Mary")), c = "ABC", d = Anno2::class, e = arrayOf(Anno::class))
|
||||||
|
class Test
|
||||||
+8
-8
@@ -47,22 +47,22 @@ fun JeAnnotationValue(psi: PsiAnnotationMemberValue): AnnotationValue {
|
|||||||
return annotationValue
|
return annotationValue
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class JeAnnotationAnnotationValue(val psi: PsiAnnotation) : AnnotationValue {
|
class JeAnnotationAnnotationValue(val psi: PsiAnnotation) : AnnotationValue {
|
||||||
override fun getValue() = JeAnnotationMirror(psi)
|
override fun getValue() = JeAnnotationMirror(psi)
|
||||||
override fun <R : Any?, P : Any?> accept(v: AnnotationValueVisitor<R, P>, p: P) = v.visitAnnotation(value, p)
|
override fun <R : Any?, P : Any?> accept(v: AnnotationValueVisitor<R, P>, p: P) = v.visitAnnotation(value, p)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class JeEnumValueAnnotationValue(val psi: PsiEnumConstant) : AnnotationValue {
|
class JeEnumValueAnnotationValue(val psi: PsiEnumConstant) : AnnotationValue {
|
||||||
override fun getValue() = JeVariableElement(psi)
|
override fun getValue() = JeVariableElement(psi)
|
||||||
override fun <R : Any?, P : Any?> accept(v: AnnotationValueVisitor<R, P>, p: P) = v.visitEnumConstant(value, p)
|
override fun <R : Any?, P : Any?> accept(v: AnnotationValueVisitor<R, P>, p: P) = v.visitEnumConstant(value, p)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class JeTypeAnnotationValue(val psi: PsiClassObjectAccessExpression) : AnnotationValue {
|
class JeTypeAnnotationValue(val psi: PsiClassObjectAccessExpression) : AnnotationValue {
|
||||||
override fun getValue() = psi.operand.type.toJeType(psi.manager)
|
override fun getValue() = psi.operand.type.toJeType(psi.manager)
|
||||||
override fun <R : Any?, P : Any?> accept(v: AnnotationValueVisitor<R, P>, p: P) = v.visitType(value, p)
|
override fun <R : Any?, P : Any?> accept(v: AnnotationValueVisitor<R, P>, p: P) = v.visitType(value, p)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal abstract class JePrimitiveAnnotationValue : AnnotationValue {
|
abstract class JePrimitiveAnnotationValue : AnnotationValue {
|
||||||
override fun <R : Any?, P : Any?> accept(v: AnnotationValueVisitor<R, P>, p: P): R {
|
override fun <R : Any?, P : Any?> accept(v: AnnotationValueVisitor<R, P>, p: P): R {
|
||||||
val value = this.value
|
val value = this.value
|
||||||
return when (value) {
|
return when (value) {
|
||||||
@@ -80,20 +80,20 @@ internal abstract class JePrimitiveAnnotationValue : AnnotationValue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class JeLiteralAnnotationValue(val psi: PsiLiteral) : JePrimitiveAnnotationValue() {
|
class JeLiteralAnnotationValue(val psi: PsiLiteral) : JePrimitiveAnnotationValue() {
|
||||||
override fun getValue() = psi.value
|
override fun getValue() = psi.value
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class JeExpressionAnnotationValue(val psi: PsiExpression) : JePrimitiveAnnotationValue() {
|
class JeExpressionAnnotationValue(val psi: PsiExpression) : JePrimitiveAnnotationValue() {
|
||||||
override fun getValue() = psi.calcConstantValue()
|
override fun getValue() = psi.calcConstantValue()
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class JeArrayAnnotationValue(val psi: PsiArrayInitializerMemberValue) : AnnotationValue {
|
class JeArrayAnnotationValue(val psi: PsiArrayInitializerMemberValue) : AnnotationValue {
|
||||||
override fun getValue() = psi.initializers.map(::JeAnnotationValue)
|
override fun getValue() = psi.initializers.map(::JeAnnotationValue)
|
||||||
override fun <R : Any?, P : Any?> accept(v: AnnotationValueVisitor<R, P>, p: P) = v.visitArray(value, p)
|
override fun <R : Any?, P : Any?> accept(v: AnnotationValueVisitor<R, P>, p: P) = v.visitArray(value, p)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class JeErrorAnnotationValue(val psi: PsiElement) : AnnotationValue {
|
class JeErrorAnnotationValue(val psi: PsiElement) : AnnotationValue {
|
||||||
override fun <R : Any?, P : Any?> accept(v: AnnotationValueVisitor<R, P>, p: P) = v.visitString(psi.text, p)
|
override fun <R : Any?, P : Any?> accept(v: AnnotationValueVisitor<R, P>, p: P) = v.visitString(psi.text, p)
|
||||||
override fun getValue() = null
|
override fun getValue() = null
|
||||||
}
|
}
|
||||||
+18
-7
@@ -17,7 +17,7 @@
|
|||||||
package org.jetbrains.kotlin.java.model.internal
|
package org.jetbrains.kotlin.java.model.internal
|
||||||
|
|
||||||
import com.intellij.psi.*
|
import com.intellij.psi.*
|
||||||
import org.jetbrains.kotlin.asJava.elements.KtLightAnnotation
|
import com.intellij.psi.util.PsiTypesUtil
|
||||||
import org.jetbrains.kotlin.java.model.types.toJeType
|
import org.jetbrains.kotlin.java.model.types.toJeType
|
||||||
import sun.reflect.annotation.AnnotationParser
|
import sun.reflect.annotation.AnnotationParser
|
||||||
import sun.reflect.annotation.ExceptionProxy
|
import sun.reflect.annotation.ExceptionProxy
|
||||||
@@ -74,10 +74,13 @@ private fun getConstantValue(
|
|||||||
|
|
||||||
when {
|
when {
|
||||||
returnType == PsiType.NULL || returnType == PsiType.VOID -> unexpectedType("void")
|
returnType == PsiType.NULL || returnType == PsiType.VOID -> unexpectedType("void")
|
||||||
jReturnType == String::class.java -> return (psiValue as? PsiExpression)?.calcConstantValue(evaluator)
|
returnType.fqName == "java.lang.String" -> return (psiValue as? PsiExpression)?.calcConstantValue(evaluator)
|
||||||
jReturnType == Class::class.java -> {
|
jReturnType.isAnnotation -> {
|
||||||
val type = getObjectType(psiValue).toJeType(manager)
|
if (psiValue !is PsiAnnotation) error("psiValue is not a PsiAnnotation")
|
||||||
return MirroredTypeExceptionProxy(type)
|
val annotationClass = PsiTypesUtil.getPsiClass(returnType) ?: error("Can't resolve type $returnType")
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
val annotation = KotlinAnnotationProxyMaker(psiValue, annotationClass, jReturnType as Class<out Annotation>)
|
||||||
|
return jReturnType.cast(annotation.generate())
|
||||||
}
|
}
|
||||||
jReturnType.isArray -> {
|
jReturnType.isArray -> {
|
||||||
val jComponentType = jReturnType.componentType ?: unexpectedType("no component type for $jReturnType")
|
val jComponentType = jReturnType.componentType ?: unexpectedType("no component type for $jReturnType")
|
||||||
@@ -88,7 +91,7 @@ private fun getConstantValue(
|
|||||||
else -> listOf(psiValue)
|
else -> listOf(psiValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (jComponentType == Class::class.java) {
|
if (!jComponentType.isPrimitive && !jComponentType.isAnnotation) {
|
||||||
val typeMirrors = arrayValues.map { getObjectType(it).toJeType(manager) }
|
val typeMirrors = arrayValues.map { getObjectType(it).toJeType(manager) }
|
||||||
return MirroredTypesExceptionProxy(Collections.unmodifiableList(typeMirrors))
|
return MirroredTypesExceptionProxy(Collections.unmodifiableList(typeMirrors))
|
||||||
} else {
|
} else {
|
||||||
@@ -105,10 +108,18 @@ private fun getConstantValue(
|
|||||||
?: error("$psiValue can not be resolved to enum constant")
|
?: error("$psiValue can not be resolved to enum constant")
|
||||||
return AnnotationUtil.createEnumValue(jReturnType, enumConstant.name)
|
return AnnotationUtil.createEnumValue(jReturnType, enumConstant.name)
|
||||||
}
|
}
|
||||||
else -> return castPrimitiveValue(returnType, (psiValue as? PsiExpression)?.calcConstantValue(evaluator))
|
else -> return if (returnType is PsiClassType) {
|
||||||
|
val type = getObjectType(psiValue).toJeType(manager)
|
||||||
|
MirroredTypeExceptionProxy(type)
|
||||||
|
} else {
|
||||||
|
castPrimitiveValue(returnType, (psiValue as? PsiExpression)?.calcConstantValue(evaluator))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val PsiType.fqName: String?
|
||||||
|
get() = (this as? PsiClassType)?.resolve()?.qualifiedName
|
||||||
|
|
||||||
private fun getObjectType(value: PsiAnnotationMemberValue): PsiType {
|
private fun getObjectType(value: PsiAnnotationMemberValue): PsiType {
|
||||||
when (value) {
|
when (value) {
|
||||||
is PsiClassObjectAccessExpression -> return value.operand.type
|
is PsiClassObjectAccessExpression -> return value.operand.type
|
||||||
|
|||||||
+17
-4
@@ -16,11 +16,9 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.annotation.processing.test.processor
|
package org.jetbrains.kotlin.annotation.processing.test.processor
|
||||||
|
|
||||||
import org.jetbrains.kotlin.java.model.elements.JeAnnotationMirror
|
import org.jetbrains.kotlin.java.model.elements.*
|
||||||
import org.jetbrains.kotlin.java.model.elements.JeMethodExecutableElement
|
|
||||||
import org.jetbrains.kotlin.java.model.elements.JeTypeElement
|
|
||||||
import org.jetbrains.kotlin.java.model.elements.JeVariableElement
|
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance
|
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance
|
||||||
|
import javax.lang.model.element.AnnotationMirror
|
||||||
|
|
||||||
class ProcessorTests : AbstractProcessorTest() {
|
class ProcessorTests : AbstractProcessorTest() {
|
||||||
override val testDataDir = "plugins/annotation-processing/testData/processors"
|
override val testDataDir = "plugins/annotation-processing/testData/processors"
|
||||||
@@ -98,4 +96,19 @@ class ProcessorTests : AbstractProcessorTest() {
|
|||||||
assertEquals(1, implAnnotations.size)
|
assertEquals(1, implAnnotations.size)
|
||||||
assertEquals("Tom", implAnnotations.first().elementValues.values.first().value)
|
assertEquals("Tom", implAnnotations.first().elementValues.values.first().value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun testNested() = test("Nested", "Anno") { set, roundEnv, env ->
|
||||||
|
assertEquals(1, set.size)
|
||||||
|
val annotatedElements = roundEnv.getElementsAnnotatedWith(set.first())
|
||||||
|
assertEquals(1, annotatedElements.size)
|
||||||
|
val test = annotatedElements.first()
|
||||||
|
val anno2 = test.annotationMirrors.first { it is JeAnnotationMirror && it.psi.qualifiedName == "Anno" }
|
||||||
|
|
||||||
|
fun AnnotationMirror.getParam(name: String) = elementValues.entries.first { it.key.simpleName.toString() == name }.value
|
||||||
|
assertTrue(anno2.getParam("a") is JeAnnotationAnnotationValue)
|
||||||
|
assertTrue((anno2.getParam("b") as JeArrayAnnotationValue).value.first() is JeAnnotationAnnotationValue)
|
||||||
|
assertTrue(anno2.getParam("c") is JePrimitiveAnnotationValue)
|
||||||
|
assertTrue(anno2.getParam("d") is JeTypeAnnotationValue)
|
||||||
|
assertTrue((anno2.getParam("e") as JeArrayAnnotationValue).value.first() is JeTypeAnnotationValue)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user