From f8f0c0b6d7c001e21f60c81c911275958fd9ebe5 Mon Sep 17 00:00:00 2001 From: Denis Zharkov Date: Wed, 9 Aug 2017 18:19:21 +0700 Subject: [PATCH] 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 --- .../structure/impl/annotationArgumentsImpl.kt | 3 +++ .../structure/impl/classFiles/Annotations.kt | 6 ++++-- .../symbols/symbolBasedAnnotationArguments.kt | 4 +++- .../LazyJavaAnnotationDescriptor.kt | 20 ++++++++++++++----- .../java/structure/annotationArguments.kt | 1 + .../reflect/ReflectJavaAnnotationArguments.kt | 3 +++ .../resolve/constants/constantValues.kt | 5 ++--- .../jetbrains/kotlin/types/ErrorUtils.java | 13 ++++++++---- 8 files changed, 40 insertions(+), 15 deletions(-) diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/structure/impl/annotationArgumentsImpl.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/structure/impl/annotationArgumentsImpl.kt index 20419fad2a3..9d9ac93851d 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/structure/impl/annotationArgumentsImpl.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/structure/impl/annotationArgumentsImpl.kt @@ -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( diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/structure/impl/classFiles/Annotations.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/structure/impl/classFiles/Annotations.kt index 28ad4c8cd4d..10e21f38a3f 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/structure/impl/classFiles/Annotations.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/structure/impl/classFiles/Annotations.kt @@ -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 } } } diff --git a/compiler/javac-wrapper/src/org/jetbrains/kotlin/javac/wrappers/symbols/symbolBasedAnnotationArguments.kt b/compiler/javac-wrapper/src/org/jetbrains/kotlin/javac/wrappers/symbols/symbolBasedAnnotationArguments.kt index 61c2da3d179..617ae8070ce 100644 --- a/compiler/javac-wrapper/src/org/jetbrains/kotlin/javac/wrappers/symbols/symbolBasedAnnotationArguments.kt +++ b/compiler/javac-wrapper/src/org/jetbrains/kotlin/javac/wrappers/symbols/symbolBasedAnnotationArguments.kt @@ -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 \ No newline at end of file +) : SymbolBasedAnnotationArgument(name, javac), JavaLiteralAnnotationArgument diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaAnnotationDescriptor.kt b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaAnnotationDescriptor.kt index b8b2fef39ed..cccbafdae05 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaAnnotationDescriptor.kt +++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaAnnotationDescriptor.kt @@ -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): 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 diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/structure/annotationArguments.kt b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/structure/annotationArguments.kt index ac3ae7a4819..ce5c6db53b7 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/structure/annotationArguments.kt +++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/structure/annotationArguments.kt @@ -31,6 +31,7 @@ interface JavaArrayAnnotationArgument : JavaAnnotationArgument { } interface JavaEnumValueAnnotationArgument : JavaAnnotationArgument { + val entryName: Name? fun resolve(): JavaField? } diff --git a/core/descriptors.runtime/src/org/jetbrains/kotlin/load/java/structure/reflect/ReflectJavaAnnotationArguments.kt b/core/descriptors.runtime/src/org/jetbrains/kotlin/load/java/structure/reflect/ReflectJavaAnnotationArguments.kt index e6d8b757f07..b347d581293 100644 --- a/core/descriptors.runtime/src/org/jetbrains/kotlin/load/java/structure/reflect/ReflectJavaAnnotationArguments.kt +++ b/core/descriptors.runtime/src/org/jetbrains/kotlin/load/java/structure/reflect/ReflectJavaAnnotationArguments.kt @@ -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( diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/constantValues.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/constantValues.kt index 3227bd87fce..9c6aed11b1b 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/constantValues.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/constantValues.kt @@ -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(open val value: T) { abstract val type: KotlinType @@ -139,7 +138,7 @@ class EnumValue( ) : ConstantValue(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 accept(visitor: AnnotationArgumentVisitor, data: D) = visitor.visitEnumValue(this, data) @@ -270,4 +269,4 @@ class StringValue( } override fun hashCode() = value.hashCode() -} \ No newline at end of file +} diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/ErrorUtils.java b/core/descriptors/src/org/jetbrains/kotlin/types/ErrorUtils.java index 2aa6a04bf6b..a6d3856fae6 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/ErrorUtils.java +++ b/core/descriptors/src/org/jetbrains/kotlin/types/ErrorUtils.java @@ -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("")); private static class ErrorClassDescriptor extends ClassDescriptorImpl { - public ErrorClassDescriptor(@Nullable String name) { - super(getErrorModule(), Name.special(name == null ? "" : ""), + public ErrorClassDescriptor(@NotNull Name name) { + super(getErrorModule(), name, Modality.OPEN, ClassKind.CLASS, Collections.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("")); + } + + @NotNull + public static ClassDescriptor createErrorClassWithExactName(@NotNull Name name) { + return new ErrorClassDescriptor(name); } @NotNull