From eb205f620ce6ded62be2bc84b8cce74a9548a4d8 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Tue, 4 Jul 2017 16:27:06 +0300 Subject: [PATCH] Do not use parameter descriptors in most annotation implementations Except AnnotationDescriptorImpl, which is refactored in the subsequent commit. Note that we no longer check the presence of parameters with the corresponding names in the annotation class in LazyJavaAnnotationDescriptor, this is why test data changed --- .../lazy/descriptors/LazyAnnotations.kt | 17 +++--- .../replaceAnnotationClassWithInterface.txt | 4 +- ...tationWithArgumentsMissingDependencies.txt | 4 +- .../java/components/JavaAnnotationMapper.kt | 52 ++++++++----------- .../LazyJavaAnnotationDescriptor.kt | 21 ++------ .../java/typeEnhancement/typeEnhancement.kt | 4 +- .../kotlin/builtins/KotlinBuiltIns.java | 20 ------- .../annotations/AnnotationDescriptor.kt | 4 -- .../annotations/AnnotationDescriptorImpl.java | 18 ++++--- 9 files changed, 53 insertions(+), 91 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/LazyAnnotations.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/LazyAnnotations.kt index 0b0f9a63d3b..626c9a4fec3 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/LazyAnnotations.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/LazyAnnotations.kt @@ -126,19 +126,18 @@ class LazyAnnotationDescriptor( c.scope } - override val valueArgumentsByParameterDescriptor by c.storageManager.createLazyValue { + override val allValueArguments by c.storageManager.createLazyValue { val resolutionResults = c.annotationResolver.resolveAnnotationCall(annotationEntry, scope, c.trace) AnnotationResolverImpl.checkAnnotationType(annotationEntry, c.trace, resolutionResults) - if (!resolutionResults.isSingleResult) return@createLazyValue emptyMap>() + if (!resolutionResults.isSingleResult) return@createLazyValue emptyMap>() - @Suppress("UNCHECKED_CAST") - resolutionResults.resultingCall.valueArguments - .mapValues { val (valueParameter, resolvedArgument) = it - if (resolvedArgument == null) null - else c.annotationResolver.getAnnotationArgumentValue(c.trace, valueParameter, resolvedArgument) - } - .filterValues { it != null } as Map> + resolutionResults.resultingCall.valueArguments.mapNotNull { (valueParameter, resolvedArgument) -> + if (resolvedArgument == null) null + else c.annotationResolver.getAnnotationArgumentValue(c.trace, valueParameter, resolvedArgument)?.let { value -> + valueParameter.name to value + } + }.toMap() } override fun forceResolveAllContents() { diff --git a/compiler/testData/compileKotlinAgainstCustomBinaries/replaceAnnotationClassWithInterface/replaceAnnotationClassWithInterface.txt b/compiler/testData/compileKotlinAgainstCustomBinaries/replaceAnnotationClassWithInterface/replaceAnnotationClassWithInterface.txt index ce3621fb144..3c0fb004d1b 100644 --- a/compiler/testData/compileKotlinAgainstCustomBinaries/replaceAnnotationClassWithInterface/replaceAnnotationClassWithInterface.txt +++ b/compiler/testData/compileKotlinAgainstCustomBinaries/replaceAnnotationClassWithInterface/replaceAnnotationClassWithInterface.txt @@ -5,7 +5,7 @@ public fun bar(): @test.Ann kotlin.String public interface Ann { } -@test.Ann public final class Test { +@test.Ann(s = "class") public final class Test { public constructor Test() - @test.Ann public final fun foo(/*0*/ @test.Ann s: @test.Ann kotlin.String): @test.Ann kotlin.String + @test.Ann(s = "function") public final fun foo(/*0*/ @test.Ann(s = "parameter") s: @test.Ann kotlin.String): @test.Ann kotlin.String } diff --git a/compiler/testData/diagnostics/tests/j+k/annotationWithArgumentsMissingDependencies.txt b/compiler/testData/diagnostics/tests/j+k/annotationWithArgumentsMissingDependencies.txt index 807261e07e3..6f4734ffcae 100644 --- a/compiler/testData/diagnostics/tests/j+k/annotationWithArgumentsMissingDependencies.txt +++ b/compiler/testData/diagnostics/tests/j+k/annotationWithArgumentsMissingDependencies.txt @@ -2,10 +2,10 @@ package public fun main(): kotlin.Unit -@missing.Ann /* annotation class not found */ public open class A { +@missing.Ann(x = "") /* annotation class not found */ public open class A { public constructor A() public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean - @missing.Ann /* annotation class not found */ public open fun foo(): kotlin.String! + @missing.Ann(value = 1) /* annotation class not found */ public open fun foo(): kotlin.String! public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String } diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/components/JavaAnnotationMapper.kt b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/components/JavaAnnotationMapper.kt index 1c394bbd8ea..aedc1d30922 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/components/JavaAnnotationMapper.kt +++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/components/JavaAnnotationMapper.kt @@ -17,9 +17,7 @@ package org.jetbrains.kotlin.load.java.components import org.jetbrains.kotlin.builtins.KotlinBuiltIns -import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.SourceElement -import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor import org.jetbrains.kotlin.descriptors.annotations.KotlinRetention import org.jetbrains.kotlin.descriptors.annotations.KotlinTarget @@ -52,20 +50,22 @@ object JavaAnnotationMapper { internal val DEPRECATED_ANNOTATION_MESSAGE = Name.identifier("message") internal val TARGET_ANNOTATION_ALLOWED_TARGETS = Name.identifier("allowedTargets") + internal val RETENTION_ANNOTATION_VALUE = Name.identifier("value") fun mapOrResolveJavaAnnotation(annotation: JavaAnnotation, c: LazyJavaResolverContext): AnnotationDescriptor? = when (annotation.classId) { ClassId.topLevel(JAVA_TARGET_FQ_NAME) -> JavaTargetAnnotationDescriptor(annotation, c) ClassId.topLevel(JAVA_RETENTION_FQ_NAME) -> JavaRetentionAnnotationDescriptor(annotation, c) - ClassId.topLevel(JAVA_REPEATABLE_FQ_NAME) -> JavaAnnotationDescriptor(c, annotation, c.module.builtIns.repeatableAnnotation) - ClassId.topLevel(JAVA_DOCUMENTED_FQ_NAME) -> JavaAnnotationDescriptor(c, annotation, c.module.builtIns.mustBeDocumentedAnnotation) + ClassId.topLevel(JAVA_REPEATABLE_FQ_NAME) -> JavaAnnotationDescriptor(c, annotation, KotlinBuiltIns.FQ_NAMES.repeatable) + ClassId.topLevel(JAVA_DOCUMENTED_FQ_NAME) -> JavaAnnotationDescriptor(c, annotation, KotlinBuiltIns.FQ_NAMES.mustBeDocumented) ClassId.topLevel(JAVA_DEPRECATED_FQ_NAME) -> null else -> LazyJavaAnnotationDescriptor(c, annotation) } - fun findMappedJavaAnnotation(kotlinName: FqName, - annotationOwner: JavaAnnotationOwner, - c: LazyJavaResolverContext + fun findMappedJavaAnnotation( + kotlinName: FqName, + annotationOwner: JavaAnnotationOwner, + c: LazyJavaResolverContext ): AnnotationDescriptor? { if (kotlinName == KotlinBuiltIns.FQ_NAMES.deprecated) { val javaAnnotation = annotationOwner.findAnnotation(JAVA_DEPRECATED_FQ_NAME) @@ -98,55 +98,48 @@ object JavaAnnotationMapper { open class JavaAnnotationDescriptor( c: LazyJavaResolverContext, annotation: JavaAnnotation?, - private val kotlinAnnotationClassDescriptor: ClassDescriptor + override val fqName: FqName ): AnnotationDescriptor { override val source: SourceElement = annotation?.let { c.components.sourceElementFactory.source(it) } ?: SourceElement.NO_SOURCE - override val type: SimpleType get() = kotlinAnnotationClassDescriptor.defaultType - - protected val valueParameters: List - get() = kotlinAnnotationClassDescriptor.constructors.single().valueParameters + override val type: SimpleType by c.storageManager.createLazyValue { c.module.builtIns.getBuiltInClassByFqName(fqName).defaultType } protected val firstArgument: JavaAnnotationArgument? = annotation?.arguments?.firstOrNull() - override val valueArgumentsByParameterDescriptor: Map> get() = emptyMap() + override val allValueArguments: Map> get() = emptyMap() } class JavaDeprecatedAnnotationDescriptor( annotation: JavaAnnotation?, c: LazyJavaResolverContext -): JavaAnnotationDescriptor(c, annotation, c.module.builtIns.deprecatedAnnotation) { - override val valueArgumentsByParameterDescriptor: Map> by c.storageManager.createLazyValue { - val parameterDescriptor = valueParameters.firstOrNull { - it.name == JavaAnnotationMapper.DEPRECATED_ANNOTATION_MESSAGE - } - parameterDescriptor?.let { - mapOf(it to ConstantValueFactory(c.module.builtIns).createStringValue("Deprecated in Java")) - }.orEmpty() +): JavaAnnotationDescriptor(c, annotation, KotlinBuiltIns.FQ_NAMES.deprecated) { + override val allValueArguments: Map> by c.storageManager.createLazyValue { + mapOf(JavaAnnotationMapper.DEPRECATED_ANNOTATION_MESSAGE to + ConstantValueFactory(c.module.builtIns).createStringValue("Deprecated in Java")) } } class JavaTargetAnnotationDescriptor( annotation: JavaAnnotation, c: LazyJavaResolverContext -): JavaAnnotationDescriptor(c, annotation, c.module.builtIns.targetAnnotation) { - override val valueArgumentsByParameterDescriptor by c.storageManager.createLazyValue { +): JavaAnnotationDescriptor(c, annotation, KotlinBuiltIns.FQ_NAMES.target) { + override val allValueArguments by c.storageManager.createLazyValue { val targetArgument = when (firstArgument) { is JavaArrayAnnotationArgument -> JavaAnnotationTargetMapper.mapJavaTargetArguments(firstArgument.getElements(), c.module.builtIns) is JavaEnumValueAnnotationArgument -> JavaAnnotationTargetMapper.mapJavaTargetArguments(listOf(firstArgument), c.module.builtIns) - else -> return@createLazyValue emptyMap>() + else -> null } - mapOf(valueParameters.single() to targetArgument) + targetArgument?.let { mapOf(JavaAnnotationMapper.TARGET_ANNOTATION_ALLOWED_TARGETS to it) }.orEmpty() } } class JavaRetentionAnnotationDescriptor( annotation: JavaAnnotation, c: LazyJavaResolverContext -): JavaAnnotationDescriptor(c, annotation, c.module.builtIns.retentionAnnotation) { - override val valueArgumentsByParameterDescriptor by c.storageManager.createLazyValue { +): JavaAnnotationDescriptor(c, annotation, KotlinBuiltIns.FQ_NAMES.retention) { + override val allValueArguments by c.storageManager.createLazyValue { val retentionArgument = JavaAnnotationTargetMapper.mapJavaRetentionArgument(firstArgument, c.module.builtIns) - retentionArgument?.let { mapOf(valueParameters.single() to it) }.orEmpty() + retentionArgument?.let { mapOf(JavaAnnotationMapper.RETENTION_ANNOTATION_VALUE to it) }.orEmpty() } } @@ -174,7 +167,8 @@ object JavaAnnotationTargetMapper { .mapNotNull { builtIns.getAnnotationTargetEnumEntry(it) } .map(::EnumValue) val parameterDescriptor = DescriptorResolverUtils.getAnnotationParameterByName( - JavaAnnotationMapper.TARGET_ANNOTATION_ALLOWED_TARGETS, builtIns.targetAnnotation + JavaAnnotationMapper.TARGET_ANNOTATION_ALLOWED_TARGETS, + builtIns.getBuiltInClassByFqName(KotlinBuiltIns.FQ_NAMES.target) ) return ArrayValue(kotlinTargets, parameterDescriptor?.type ?: ErrorUtils.createErrorType("Error: AnnotationTarget[]"), builtIns) } 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 43148235a63..b8b2fef39ed 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 @@ -17,7 +17,6 @@ package org.jetbrains.kotlin.load.java.lazy.descriptors import org.jetbrains.kotlin.descriptors.ClassDescriptor -import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.findNonGenericClassAcrossDependencies @@ -39,7 +38,6 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.annotationClass import org.jetbrains.kotlin.resolve.descriptorUtil.resolveTopLevelClass import org.jetbrains.kotlin.storage.getValue import org.jetbrains.kotlin.types.* -import org.jetbrains.kotlin.utils.keysToMapExceptNulls class LazyJavaAnnotationDescriptor( private val c: LazyJavaResolverContext, @@ -61,20 +59,11 @@ class LazyJavaAnnotationDescriptor( private val factory = ConstantValueFactory(c.module.builtIns) - override val valueArgumentsByParameterDescriptor by c.storageManager.createLazyValue { - val constructors = annotationClass!!.constructors - if (constructors.isEmpty()) return@createLazyValue emptyMap>() - - val nameToArg = javaAnnotation.arguments.associateBy { it.name } - - constructors.first().valueParameters.keysToMapExceptNulls { valueParameter -> - var javaAnnotationArgument = nameToArg[valueParameter.name] - if (javaAnnotationArgument == null && valueParameter.name == DEFAULT_ANNOTATION_MEMBER_NAME) { - javaAnnotationArgument = nameToArg[null] - } - - resolveAnnotationArgument(javaAnnotationArgument) - } + override val allValueArguments by c.storageManager.createLazyValue { + javaAnnotation.arguments.mapNotNull { arg -> + val name = arg.name ?: DEFAULT_ANNOTATION_MEMBER_NAME + resolveAnnotationArgument(arg)?.let { value -> name to value } + }.toMap() } private fun resolveAnnotationArgument(argument: JavaAnnotationArgument?): ConstantValue<*>? { diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/typeEnhancement/typeEnhancement.kt b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/typeEnhancement/typeEnhancement.kt index 370f463a4d3..b123b90f116 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/typeEnhancement/typeEnhancement.kt +++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/typeEnhancement/typeEnhancement.kt @@ -19,7 +19,6 @@ package org.jetbrains.kotlin.load.java.typeEnhancement import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassifierDescriptor import org.jetbrains.kotlin.descriptors.SourceElement -import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor import org.jetbrains.kotlin.descriptors.annotations.AnnotationWithTarget import org.jetbrains.kotlin.descriptors.annotations.Annotations @@ -31,6 +30,7 @@ import org.jetbrains.kotlin.load.java.typeEnhancement.MutabilityQualifier.READ_O import org.jetbrains.kotlin.load.java.typeEnhancement.NullabilityQualifier.NOT_NULL import org.jetbrains.kotlin.load.java.typeEnhancement.NullabilityQualifier.NULLABLE import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.platform.JavaToKotlinClassMap import org.jetbrains.kotlin.resolve.constants.ConstantValue import org.jetbrains.kotlin.types.* @@ -209,7 +209,7 @@ private class EnhancedTypeAnnotations(private val fqNameToMatch: FqName) : Annot private object EnhancedTypeAnnotationDescriptor : AnnotationDescriptor { private fun throwError(): Nothing = error("No methods should be called on this descriptor. Only its presence matters") override val type: KotlinType get() = throwError() - override val valueArgumentsByParameterDescriptor: Map> get() = throwError() + override val allValueArguments: Map> get() = throwError() override val source: SourceElement get() = throwError() override fun toString() = "[EnhancedType]" } diff --git a/core/descriptors/src/org/jetbrains/kotlin/builtins/KotlinBuiltIns.java b/core/descriptors/src/org/jetbrains/kotlin/builtins/KotlinBuiltIns.java index 6e885cbd030..c01543fc9bf 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/builtins/KotlinBuiltIns.java +++ b/core/descriptors/src/org/jetbrains/kotlin/builtins/KotlinBuiltIns.java @@ -580,26 +580,6 @@ public abstract class KotlinBuiltIns { return getEnumEntry(getBuiltInClassByName(FQ_NAMES.deprecationLevel.shortName()), level); } - @NotNull - public ClassDescriptor getTargetAnnotation() { - return getAnnotationClassByName(FQ_NAMES.target.shortName()); - } - - @NotNull - public ClassDescriptor getRetentionAnnotation() { - return getAnnotationClassByName(FQ_NAMES.retention.shortName()); - } - - @NotNull - public ClassDescriptor getRepeatableAnnotation() { - return getAnnotationClassByName(FQ_NAMES.repeatable.shortName()); - } - - @NotNull - public ClassDescriptor getMustBeDocumentedAnnotation() { - return getAnnotationClassByName(FQ_NAMES.mustBeDocumented.shortName()); - } - @Nullable public ClassDescriptor getAnnotationTargetEnumEntry(@NotNull KotlinTarget target) { return getEnumEntry(getAnnotationClassByName(FQ_NAMES.annotationTarget.shortName()), target.name()); diff --git a/core/descriptors/src/org/jetbrains/kotlin/descriptors/annotations/AnnotationDescriptor.kt b/core/descriptors/src/org/jetbrains/kotlin/descriptors/annotations/AnnotationDescriptor.kt index ddb37069e26..4a82fd7a69a 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/descriptors/annotations/AnnotationDescriptor.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/descriptors/annotations/AnnotationDescriptor.kt @@ -32,11 +32,7 @@ interface AnnotationDescriptor { val fqName: FqName? get() = (type.constructor.declarationDescriptor as? ClassDescriptor)?.fqNameUnsafe?.takeIf(FqNameUnsafe::isSafe)?.toSafe() - @Deprecated("Use allValueArguments instead") - val valueArgumentsByParameterDescriptor: Map> - val allValueArguments: Map> - get() = valueArgumentsByParameterDescriptor.mapKeys { (parameter) -> parameter.name } val source: SourceElement } diff --git a/core/descriptors/src/org/jetbrains/kotlin/descriptors/annotations/AnnotationDescriptorImpl.java b/core/descriptors/src/org/jetbrains/kotlin/descriptors/annotations/AnnotationDescriptorImpl.java index 7067598099f..99a49064a85 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/descriptors/annotations/AnnotationDescriptorImpl.java +++ b/core/descriptors/src/org/jetbrains/kotlin/descriptors/annotations/AnnotationDescriptorImpl.java @@ -16,6 +16,8 @@ package org.jetbrains.kotlin.descriptors.annotations; +import kotlin.collections.MapsKt; +import kotlin.jvm.functions.Function1; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.descriptors.SourceElement; @@ -56,16 +58,18 @@ public class AnnotationDescriptorImpl implements AnnotationDescriptor { return AnnotationDescriptor.DefaultImpls.getFqName(this); } - @Override - @NotNull - public Map> getValueArgumentsByParameterDescriptor() { - return valueArguments; - } - @NotNull @Override public Map> getAllValueArguments() { - return AnnotationDescriptor.DefaultImpls.getAllValueArguments(this); + return MapsKt.mapKeys( + valueArguments, + new Function1>, Name>() { + @Override + public Name invoke(Map.Entry> entry) { + return entry.getKey().getName(); + } + } + ); } @Override