Load enum/array annotation arguments for not found classes

It's necessary to load type qualifier related annotations
without JSR305 annotations being in the classpath

 #KT-19419 In Progress
This commit is contained in:
Denis Zharkov
2017-08-09 18:19:21 +07:00
parent a82e313d14
commit f8f0c0b6d7
8 changed files with 40 additions and 15 deletions
@@ -72,6 +72,9 @@ class JavaEnumValueAnnotationArgumentImpl(
else -> throw IllegalStateException("Reference argument should be an enum value, but was $element: ${element.text}")
}
}
override val entryName: Name?
get() = psiReference.referenceName?.let(Name::identifier)
}
class JavaClassObjectAnnotationArgumentImpl(
@@ -184,12 +184,14 @@ class PlainJavaAnnotationAsAnnotationArgument(
class PlainJavaEnumValueAnnotationArgument(
name: String?,
private val desc: String,
private val entryName: String,
entryName: String,
private val context: ClassifierResolutionContext
) : PlainJavaAnnotationArgument(name), JavaEnumValueAnnotationArgument {
override val entryName = Name.identifier(entryName)
override fun resolve(): JavaField? {
val javaClass = context.resolveByInternalName(Type.getType(desc).internalName).classifier as? JavaClass ?: return null
return javaClass.fields.singleOrNull { it.name.asString() == entryName }
return javaClass.fields.singleOrNull { it.name == entryName }
}
}
@@ -61,6 +61,8 @@ class SymbolBasedReferenceAnnotationArgument(
val element: VariableElement,
javac: JavacWrapper
) : SymbolBasedAnnotationArgument(Name.identifier(element.simpleName.toString()), javac), JavaEnumValueAnnotationArgument {
override val entryName: Name?
get() = Name.identifier(element.simpleName.toString())
override fun resolve() = SymbolBasedField(element, javac)
@@ -90,4 +92,4 @@ class SymbolBasedLiteralAnnotationArgument(
override val value : Any,
name : Name,
javac: JavacWrapper
) : SymbolBasedAnnotationArgument(name, javac), JavaLiteralAnnotationArgument
) : SymbolBasedAnnotationArgument(name, javac), JavaLiteralAnnotationArgument
@@ -69,7 +69,7 @@ class LazyJavaAnnotationDescriptor(
private fun resolveAnnotationArgument(argument: JavaAnnotationArgument?): ConstantValue<*>? {
return when (argument) {
is JavaLiteralAnnotationArgument -> factory.createConstantValue(argument.value)
is JavaEnumValueAnnotationArgument -> resolveFromEnumValue(argument.resolve())
is JavaEnumValueAnnotationArgument -> resolveFromEnumValue(argument.resolve(), argument.entryName)
is JavaArrayAnnotationArgument -> resolveFromArray(argument.name ?: DEFAULT_ANNOTATION_MEMBER_NAME, argument.getElements())
is JavaAnnotationAsAnnotationArgument -> resolveFromAnnotation(argument.getAnnotation())
is JavaClassObjectAnnotationArgument -> resolveFromJavaClassObjectType(argument.getReferencedType())
@@ -84,16 +84,26 @@ class LazyJavaAnnotationDescriptor(
private fun resolveFromArray(argumentName: Name, elements: List<JavaAnnotationArgument>): ConstantValue<*>? {
if (type.isError) return null
val valueParameter = DescriptorResolverUtils.getAnnotationParameterByName(argumentName, annotationClass!!) ?: return null
val arrayType =
DescriptorResolverUtils.getAnnotationParameterByName(argumentName, annotationClass!!)?.type
// Try to load annotation arguments even if the annotation class is not found
?: c.components.module.builtIns.getArrayType(
Variance.INVARIANT,
ErrorUtils.createErrorType("Unknown array element type")
)
val values = elements.map {
argument -> resolveAnnotationArgument(argument) ?: factory.createNullValue()
}
return factory.createArrayValue(values, valueParameter.type)
return factory.createArrayValue(values, arrayType)
}
private fun resolveFromEnumValue(element: JavaField?): ConstantValue<*>? {
if (element == null || !element.isEnumEntry) return null
private fun resolveFromEnumValue(element: JavaField?, entryName: Name?): ConstantValue<*>? {
if (element == null || !element.isEnumEntry) {
if (entryName == null) return null
return factory.createEnumValue(ErrorUtils.createErrorClassWithExactName(entryName))
}
val containingJavaClass = element.containingClass
@@ -31,6 +31,7 @@ interface JavaArrayAnnotationArgument : JavaAnnotationArgument {
}
interface JavaEnumValueAnnotationArgument : JavaAnnotationArgument {
val entryName: Name?
fun resolve(): JavaField?
}
@@ -56,6 +56,9 @@ class ReflectJavaEnumValueAnnotationArgument(
val enumClass = if (clazz.isEnum) clazz else clazz.enclosingClass
return ReflectJavaField(enumClass.getDeclaredField(value.name))
}
override val entryName: Name?
get() = Name.identifier(value.name)
}
class ReflectJavaClassObjectAnnotationArgument(
@@ -23,7 +23,6 @@ import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.resolve.descriptorUtil.classValueType
import org.jetbrains.kotlin.types.ErrorUtils
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.utils.sure
abstract class ConstantValue<out T>(open val value: T) {
abstract val type: KotlinType
@@ -139,7 +138,7 @@ class EnumValue(
) : ConstantValue<ClassDescriptor>(value) {
override val type: KotlinType
get() = value.classValueType.sure { "Enum entry must have a class object type: " + value }
get() = value.classValueType ?: ErrorUtils.createErrorType("Containing class for error-class based enum entry $value")
override fun <R, D> accept(visitor: AnnotationArgumentVisitor<R, D>, data: D) = visitor.visitEnumValue(this, data)
@@ -270,4 +269,4 @@ class StringValue(
}
override fun hashCode() = value.hashCode()
}
}
@@ -290,11 +290,11 @@ public class ErrorUtils {
}
}
private static final ErrorClassDescriptor ERROR_CLASS = new ErrorClassDescriptor(null);
private static final ErrorClassDescriptor ERROR_CLASS = new ErrorClassDescriptor(Name.special("<ERROR CLASS>"));
private static class ErrorClassDescriptor extends ClassDescriptorImpl {
public ErrorClassDescriptor(@Nullable String name) {
super(getErrorModule(), Name.special(name == null ? "<ERROR CLASS>" : "<ERROR CLASS: " + name + ">"),
public ErrorClassDescriptor(@NotNull Name name) {
super(getErrorModule(), name,
Modality.OPEN, ClassKind.CLASS, Collections.<KotlinType>emptyList(), SourceElement.NO_SOURCE,
/* isExternal = */ false
);
@@ -340,7 +340,12 @@ public class ErrorUtils {
@NotNull
public static ClassDescriptor createErrorClass(@NotNull String debugMessage) {
return new ErrorClassDescriptor(debugMessage);
return new ErrorClassDescriptor(Name.special("<ERROR CLASS: " + debugMessage + ">"));
}
@NotNull
public static ClassDescriptor createErrorClassWithExactName(@NotNull Name name) {
return new ErrorClassDescriptor(name);
}
@NotNull