From 748c0e7149b4111d5dc57bdc38e70f174ccc7dd8 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Tue, 3 Nov 2015 15:24:20 +0300 Subject: [PATCH] Don't assert that annotation class has constructor in AnnotationDeserializer #KT-9758 Fixed --- .../library-1/Ann.kt | 6 ++++++ .../library-2/Ann.kt | 4 ++++ .../replaceAnnotationClassWithInterface.kt | 3 +++ .../replaceAnnotationClassWithInterface.txt | 11 ++++++++++ .../usage/usage.kt | 7 +++++++ ...ompileKotlinAgainstCustomBinariesTest.java | 13 ++++++++++-- .../components/DescriptorResolverUtils.java | 2 +- .../deserialization/AnnotationDeserializer.kt | 21 ++++++++++--------- 8 files changed, 54 insertions(+), 13 deletions(-) create mode 100644 compiler/testData/compileKotlinAgainstCustomBinaries/replaceAnnotationClassWithInterface/library-1/Ann.kt create mode 100644 compiler/testData/compileKotlinAgainstCustomBinaries/replaceAnnotationClassWithInterface/library-2/Ann.kt create mode 100644 compiler/testData/compileKotlinAgainstCustomBinaries/replaceAnnotationClassWithInterface/replaceAnnotationClassWithInterface.kt create mode 100644 compiler/testData/compileKotlinAgainstCustomBinaries/replaceAnnotationClassWithInterface/replaceAnnotationClassWithInterface.txt create mode 100644 compiler/testData/compileKotlinAgainstCustomBinaries/replaceAnnotationClassWithInterface/usage/usage.kt diff --git a/compiler/testData/compileKotlinAgainstCustomBinaries/replaceAnnotationClassWithInterface/library-1/Ann.kt b/compiler/testData/compileKotlinAgainstCustomBinaries/replaceAnnotationClassWithInterface/library-1/Ann.kt new file mode 100644 index 0000000000000..cca8ef7e89f5c --- /dev/null +++ b/compiler/testData/compileKotlinAgainstCustomBinaries/replaceAnnotationClassWithInterface/library-1/Ann.kt @@ -0,0 +1,6 @@ +package test + +import kotlin.annotation.AnnotationTarget.* + +@Target(CLASS, ANNOTATION_CLASS, TYPE_PARAMETER, PROPERTY, FIELD, LOCAL_VARIABLE, VALUE_PARAMETER, CONSTRUCTOR, FUNCTION, PROPERTY_GETTER, PROPERTY_SETTER, TYPE, EXPRESSION, FILE) +annotation class Ann(val s: String) diff --git a/compiler/testData/compileKotlinAgainstCustomBinaries/replaceAnnotationClassWithInterface/library-2/Ann.kt b/compiler/testData/compileKotlinAgainstCustomBinaries/replaceAnnotationClassWithInterface/library-2/Ann.kt new file mode 100644 index 0000000000000..3081a1aa798b3 --- /dev/null +++ b/compiler/testData/compileKotlinAgainstCustomBinaries/replaceAnnotationClassWithInterface/library-2/Ann.kt @@ -0,0 +1,4 @@ +package test + +// Ha! Ann is no longer an annotation, it's an interface instead. But we shouldn't assert it anywhere in the compiler +interface Ann diff --git a/compiler/testData/compileKotlinAgainstCustomBinaries/replaceAnnotationClassWithInterface/replaceAnnotationClassWithInterface.kt b/compiler/testData/compileKotlinAgainstCustomBinaries/replaceAnnotationClassWithInterface/replaceAnnotationClassWithInterface.kt new file mode 100644 index 0000000000000..33de0788f3556 --- /dev/null +++ b/compiler/testData/compileKotlinAgainstCustomBinaries/replaceAnnotationClassWithInterface/replaceAnnotationClassWithInterface.kt @@ -0,0 +1,3 @@ +package test + +fun bar() = Test().foo("ok") diff --git a/compiler/testData/compileKotlinAgainstCustomBinaries/replaceAnnotationClassWithInterface/replaceAnnotationClassWithInterface.txt b/compiler/testData/compileKotlinAgainstCustomBinaries/replaceAnnotationClassWithInterface/replaceAnnotationClassWithInterface.txt new file mode 100644 index 0000000000000..49802a78229e6 --- /dev/null +++ b/compiler/testData/compileKotlinAgainstCustomBinaries/replaceAnnotationClassWithInterface/replaceAnnotationClassWithInterface.txt @@ -0,0 +1,11 @@ +package test + +public fun bar(): @test.Ann() kotlin.String + +public interface Ann { +} + +@test.Ann() 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 +} diff --git a/compiler/testData/compileKotlinAgainstCustomBinaries/replaceAnnotationClassWithInterface/usage/usage.kt b/compiler/testData/compileKotlinAgainstCustomBinaries/replaceAnnotationClassWithInterface/usage/usage.kt new file mode 100644 index 0000000000000..22b35e03ce592 --- /dev/null +++ b/compiler/testData/compileKotlinAgainstCustomBinaries/replaceAnnotationClassWithInterface/usage/usage.kt @@ -0,0 +1,7 @@ +package test + +@Ann("class") +class Test { + @Ann("function") + fun foo(@Ann("parameter") s: @Ann("parameter type") String): @Ann("return type") String = @Ann("expression") s +} diff --git a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstCustomBinariesTest.java b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstCustomBinariesTest.java index 05e8cee9d58a2..1531c7ba10856 100644 --- a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstCustomBinariesTest.java +++ b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstCustomBinariesTest.java @@ -69,8 +69,10 @@ private File getTestDataFileWithExtension(@NotNull String extension) { } @NotNull - private File compileLibrary(@NotNull String sourcePath) { - return MockLibraryUtil.compileLibraryToJar(new File(getTestDataDirectory(), sourcePath).getPath(), "customKotlinLib", false); + private File compileLibrary(@NotNull String sourcePath, @NotNull String... extraClassPath) { + return MockLibraryUtil.compileLibraryToJar( + new File(getTestDataDirectory(), sourcePath).getPath(), "customKotlinLib", false, extraClassPath + ); } private void doTestWithTxt(@NotNull File... extraClassPath) throws Exception { @@ -341,4 +343,11 @@ public void visitSource(String source, String debug) { assertEquals(null, debugInfo.get()); } } + + public void testReplaceAnnotationClassWithInterface() throws Exception { + File library1 = compileLibrary("library-1"); + File usage = compileLibrary("usage", library1.getPath()); + File library2 = compileLibrary("library-2"); + doTestWithTxt(usage, library2); + } } diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/components/DescriptorResolverUtils.java b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/components/DescriptorResolverUtils.java index bc930f714a67c..5115ffeb6c0f2 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/components/DescriptorResolverUtils.java +++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/components/DescriptorResolverUtils.java @@ -78,7 +78,7 @@ public void conflict(@NotNull CallableMemberDescriptor fromSuper, @NotNull Calla @Nullable public static ValueParameterDescriptor getAnnotationParameterByName(@NotNull Name name, @NotNull ClassDescriptor annotationClass) { Collection constructors = annotationClass.getConstructors(); - assert constructors.size() == 1 : "Annotation class descriptor must have only one constructor"; + if (constructors.size() != 1) return null; for (ValueParameterDescriptor parameter : constructors.iterator().next().getValueParameters()) { if (parameter.getName().equals(name)) { diff --git a/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/AnnotationDeserializer.kt b/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/AnnotationDeserializer.kt index 57b6e86d25bc8..f5797af54222a 100644 --- a/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/AnnotationDeserializer.kt +++ b/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/AnnotationDeserializer.kt @@ -23,6 +23,7 @@ import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptorImpl import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.constants.AnnotationValue import org.jetbrains.kotlin.resolve.constants.ConstantValue import org.jetbrains.kotlin.resolve.constants.ConstantValueFactory @@ -42,18 +43,18 @@ public class AnnotationDeserializer(private val module: ModuleDescriptor) { private val factory = ConstantValueFactory(builtIns) public fun deserializeAnnotation(proto: Annotation, nameResolver: NameResolver): AnnotationDescriptor { - val annotationClass = resolveClass(nameResolver.getClassId(proto.getId())) - - val arguments = if (proto.getArgumentCount() == 0 || ErrorUtils.isError(annotationClass)) { - mapOf() - } - else { - val parameterByName = annotationClass.getConstructors().single().getValueParameters().toMap { it.getName() } - val arguments = proto.getArgumentList().map { resolveArgument(it, parameterByName, nameResolver) }.filterNotNull() - arguments.toMap() + val annotationClass = resolveClass(nameResolver.getClassId(proto.id)) + + var arguments = emptyMap>() + if (proto.argumentCount != 0 && !ErrorUtils.isError(annotationClass) && DescriptorUtils.isAnnotationClass(annotationClass)) { + val constructor = annotationClass.constructors.singleOrNull() + if (constructor != null) { + val parameterByName = constructor.valueParameters.toMapBy { it.name } + arguments = proto.argumentList.map { resolveArgument(it, parameterByName, nameResolver) }.filterNotNull().toMap() + } } - return AnnotationDescriptorImpl(annotationClass.getDefaultType(), arguments, SourceElement.NO_SOURCE) + return AnnotationDescriptorImpl(annotationClass.defaultType, arguments, SourceElement.NO_SOURCE) } private fun resolveArgument(