From 9d2add81f868ed53e96d1e17030b255494fb4eb0 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Thu, 5 Sep 2013 18:17:37 +0400 Subject: [PATCH] Don't break the world if enum in annotation isn't found --- .../lang/resolve/constants/ErrorValue.java | 5 ++ .../jetbrains/jet/lang/types/ErrorUtils.java | 3 +- .../MissingEnum.jar | Bin 0 -> 1423 bytes .../MissingEnum.kt.txt | 12 +++++ .../MissingEnumReferencedInAnnotation.kt | 3 ++ .../MissingEnumReferencedInAnnotation.txt | 14 ++++++ ...actCompileKotlinAgainstCustomJavaTest.java | 4 +- ...mpileKotlinAgainstCustomJavaGenerated.java | 16 ++++++- .../AnnotationDescriptorDeserializer.java | 43 ++++++++++++------ 9 files changed, 83 insertions(+), 17 deletions(-) create mode 100644 compiler/testData/compileKotlinAgainstCustomJava/missingEnumReferencedInAnnotation/MissingEnum.jar create mode 100644 compiler/testData/compileKotlinAgainstCustomJava/missingEnumReferencedInAnnotation/MissingEnum.kt.txt create mode 100644 compiler/testData/compileKotlinAgainstCustomJava/missingEnumReferencedInAnnotation/MissingEnumReferencedInAnnotation.kt create mode 100644 compiler/testData/compileKotlinAgainstCustomJava/missingEnumReferencedInAnnotation/MissingEnumReferencedInAnnotation.txt diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/constants/ErrorValue.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/constants/ErrorValue.java index 3f2c60a5fcc..48d5aad35f5 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/constants/ErrorValue.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/constants/ErrorValue.java @@ -50,4 +50,9 @@ public class ErrorValue implements CompileTimeConstant { public String getMessage() { return message; } + + @Override + public String toString() { + return message; + } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/ErrorUtils.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/ErrorUtils.java index d9f537ed74d..1ac18056397 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/ErrorUtils.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/ErrorUtils.java @@ -385,7 +385,8 @@ public class ErrorUtils { return createErrorType(value + " is not allowed here", value.getType().getMemberScope()); } - public static ClassifierDescriptor getErrorClass() { + @NotNull + public static ClassDescriptor getErrorClass() { return ERROR_CLASS; } diff --git a/compiler/testData/compileKotlinAgainstCustomJava/missingEnumReferencedInAnnotation/MissingEnum.jar b/compiler/testData/compileKotlinAgainstCustomJava/missingEnumReferencedInAnnotation/MissingEnum.jar new file mode 100644 index 0000000000000000000000000000000000000000..afdaa84ceddea820d287084111bbe3d700417e12 GIT binary patch literal 1423 zcmWIWW@Zs#-~dAJK2>K1B*4kQ!r%MB z$s@C+v@$HjM4l|ss(7aQI`dP}$0A0s?H9z3<=X(w24RrxTws^Dp*fuuC|Z(QT%wO~ zpfj2hewY%+yu5t91)ts3EI$-7@qYchZ8R@7-Ru&n?+yBs}lD$ufy6J1$(yGJY}Z zq;%&wGYxBi3 zJ9gFlm}xRoc1G)7r}g{z^!S@DM!pYwRJHuo_dBO1-S9h<7XP5|_R9s+n^`?)F`xFh z_(a1+qEPKtM?kl6AA_NVP>T|;uv&%Ps*Q_1&OAS^=sfT4n{I;>N&Du!Z{9pNwoxqK z(5!m$V(B&J59-6-hd-XKUb@12{kp5t(#z*xox5$9#?|l6Z?rTPoQUpSwnu0G{8v+c z=q$*2WO??Nh5Lfc_@(Ms7RY~R@izVsj=oCy6Podi3=A8A7OEzO_Lxnuo(Ui|+0KP(?)_&I%-uX+7m^wKS>jtv$QuWyR?D8BdKV%Ca{ ztDOZNbr${oe(J6#W8%Z+ZDF%N-#N3cYI>gl@3X~5$){qOG@TxYot(+`^Wn*hnhU=< zNxzK~I`Zt=hE}mhYBf3nHRTI+7n=Uq&c9u?`PJj*OQN^#WcpfOayH$%%cN=jisJV( zOD27I8@T)K$?E0S>tx$kZ4dlxzrM^ozEXPfdjH+x?^|Zb%9Kg3Z=KE(efvq^i`>i0 zr!WZ~&2(x?@+uOF)LEp!eR+l0p0As?ntaJp>YaT04EG=PM7KE;_lM8>Sn1tdq|?1{ zPL`$C6;IYZcMC0N_g$5aop|oz8H?JbZMU+@R%gs9*<%sE>)-X;=GXu4^mtgPBO@+< zA~MX<@Lu}2igS$*ZkFHKJ@YodMD%tgv55tuFASPtQjdm2Y9oxfmE;pp*Ar1{J^0D0Op(Yc>n+a literal 0 HcmV?d00001 diff --git a/compiler/testData/compileKotlinAgainstCustomJava/missingEnumReferencedInAnnotation/MissingEnum.kt.txt b/compiler/testData/compileKotlinAgainstCustomJava/missingEnumReferencedInAnnotation/MissingEnum.kt.txt new file mode 100644 index 00000000000..d77c01c1433 --- /dev/null +++ b/compiler/testData/compileKotlinAgainstCustomJava/missingEnumReferencedInAnnotation/MissingEnum.kt.txt @@ -0,0 +1,12 @@ +package test + +// To regenerate this test: +// 1. Compile this file +// 2. Delete test/E.class +// 3. Pack test/ into jar + +enum class E { ENTRY } + +annotation class Anno(val e: E) + +Anno(E.ENTRY) open class Class diff --git a/compiler/testData/compileKotlinAgainstCustomJava/missingEnumReferencedInAnnotation/MissingEnumReferencedInAnnotation.kt b/compiler/testData/compileKotlinAgainstCustomJava/missingEnumReferencedInAnnotation/MissingEnumReferencedInAnnotation.kt new file mode 100644 index 00000000000..c964ab991a5 --- /dev/null +++ b/compiler/testData/compileKotlinAgainstCustomJava/missingEnumReferencedInAnnotation/MissingEnumReferencedInAnnotation.kt @@ -0,0 +1,3 @@ +package test + +class Subclass : Class() diff --git a/compiler/testData/compileKotlinAgainstCustomJava/missingEnumReferencedInAnnotation/MissingEnumReferencedInAnnotation.txt b/compiler/testData/compileKotlinAgainstCustomJava/missingEnumReferencedInAnnotation/MissingEnumReferencedInAnnotation.txt new file mode 100644 index 00000000000..bac7cc02590 --- /dev/null +++ b/compiler/testData/compileKotlinAgainstCustomJava/missingEnumReferencedInAnnotation/MissingEnumReferencedInAnnotation.txt @@ -0,0 +1,14 @@ +package test + +internal final annotation class Anno : jet.Annotation { + public constructor Anno(/*0*/ e: [ERROR : test.E]) + internal final val e: [ERROR : test.E] +} + +test.Anno(e = Unresolved enum entry: test.E.ENTRY: [ERROR : Unresolved enum entry: test.E.ENTRY]) internal open class Class { + public constructor Class() +} + +internal final class Subclass : test.Class { + public constructor Subclass() +} diff --git a/compiler/tests/org/jetbrains/jet/jvm/compiler/AbstractCompileKotlinAgainstCustomJavaTest.java b/compiler/tests/org/jetbrains/jet/jvm/compiler/AbstractCompileKotlinAgainstCustomJavaTest.java index 47d8acfe310..e0fc544af53 100644 --- a/compiler/tests/org/jetbrains/jet/jvm/compiler/AbstractCompileKotlinAgainstCustomJavaTest.java +++ b/compiler/tests/org/jetbrains/jet/jvm/compiler/AbstractCompileKotlinAgainstCustomJavaTest.java @@ -34,6 +34,7 @@ import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.java.AnalyzerFacadeForJVM; import org.jetbrains.jet.lang.resolve.name.FqName; import org.jetbrains.jet.test.TestCaseWithTmpdir; +import org.jetbrains.jet.test.util.DescriptorValidator; import org.jetbrains.jet.test.util.NamespaceComparator; import org.junit.Assert; @@ -70,7 +71,8 @@ public abstract class AbstractCompileKotlinAgainstCustomJavaTest extends TestCas NamespaceDescriptor namespaceDescriptor = bindingContext.get(BindingContext.FQNAME_TO_NAMESPACE_DESCRIPTOR, namespaceFqn); assertNotNull("Failed to find namespace: " + namespaceFqn, namespaceDescriptor); - validateAndCompareNamespaceWithFile(namespaceDescriptor, NamespaceComparator.DONT_INCLUDE_METHODS_OF_OBJECT, expectedFile); + validateAndCompareNamespaceWithFile(namespaceDescriptor, NamespaceComparator.DONT_INCLUDE_METHODS_OF_OBJECT.withValidationStrategy( + DescriptorValidator.ValidationVisitor.ALLOW_ERROR_TYPES), expectedFile); } private JetCoreEnvironment getEnvironment(File ktFile) { diff --git a/compiler/tests/org/jetbrains/jet/jvm/compiler/CompileKotlinAgainstCustomJavaGenerated.java b/compiler/tests/org/jetbrains/jet/jvm/compiler/CompileKotlinAgainstCustomJavaGenerated.java index 81c3b875e9f..5d7afaeb7e7 100644 --- a/compiler/tests/org/jetbrains/jet/jvm/compiler/CompileKotlinAgainstCustomJavaGenerated.java +++ b/compiler/tests/org/jetbrains/jet/jvm/compiler/CompileKotlinAgainstCustomJavaGenerated.java @@ -31,7 +31,7 @@ import org.jetbrains.jet.jvm.compiler.AbstractCompileKotlinAgainstCustomJavaTest /** This class is generated by {@link org.jetbrains.jet.generators.tests.GenerateTests}. DO NOT MODIFY MANUALLY */ @SuppressWarnings("all") @TestMetadata("compiler/testData/compileKotlinAgainstCustomJava") -@InnerTestClasses({CompileKotlinAgainstCustomJavaGenerated.DuplicateLibraries.class}) +@InnerTestClasses({CompileKotlinAgainstCustomJavaGenerated.DuplicateLibraries.class, CompileKotlinAgainstCustomJavaGenerated.MissingEnumReferencedInAnnotation.class}) public class CompileKotlinAgainstCustomJavaGenerated extends AbstractCompileKotlinAgainstCustomJavaTest { public void testAllFilesPresentInCompileKotlinAgainstCustomJava() throws Exception { JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("compiler/testData/compileKotlinAgainstCustomJava"), Pattern.compile("^(.+)\\.kt$"), true); @@ -50,10 +50,24 @@ public class CompileKotlinAgainstCustomJavaGenerated extends AbstractCompileKotl } + @TestMetadata("compiler/testData/compileKotlinAgainstCustomJava/missingEnumReferencedInAnnotation") + public static class MissingEnumReferencedInAnnotation extends AbstractCompileKotlinAgainstCustomJavaTest { + public void testAllFilesPresentInMissingEnumReferencedInAnnotation() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("compiler/testData/compileKotlinAgainstCustomJava/missingEnumReferencedInAnnotation"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("MissingEnumReferencedInAnnotation.kt") + public void testMissingEnumReferencedInAnnotation() throws Exception { + doTest("compiler/testData/compileKotlinAgainstCustomJava/missingEnumReferencedInAnnotation/MissingEnumReferencedInAnnotation.kt"); + } + + } + public static Test suite() { TestSuite suite = new TestSuite("CompileKotlinAgainstCustomJavaGenerated"); suite.addTestSuite(CompileKotlinAgainstCustomJavaGenerated.class); suite.addTestSuite(DuplicateLibraries.class); + suite.addTestSuite(MissingEnumReferencedInAnnotation.class); return suite; } } diff --git a/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/resolver/AnnotationDescriptorDeserializer.java b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/resolver/AnnotationDescriptorDeserializer.java index 265298c5409..3650d8a9e91 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/resolver/AnnotationDescriptorDeserializer.java +++ b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/resolver/AnnotationDescriptorDeserializer.java @@ -32,6 +32,7 @@ import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; import org.jetbrains.jet.lang.resolve.DescriptorUtils; import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant; import org.jetbrains.jet.lang.resolve.constants.EnumValue; +import org.jetbrains.jet.lang.resolve.constants.ErrorValue; import org.jetbrains.jet.lang.resolve.java.JvmAbi; import org.jetbrains.jet.lang.resolve.java.JvmAnnotationNames; import org.jetbrains.jet.lang.resolve.java.PackageClassUtils; @@ -42,7 +43,7 @@ import org.jetbrains.jet.lang.resolve.lazy.storage.MemoizedFunctionToNotNull; import org.jetbrains.jet.lang.resolve.lazy.storage.StorageManager; import org.jetbrains.jet.lang.resolve.name.FqName; import org.jetbrains.jet.lang.resolve.name.Name; -import org.jetbrains.jet.lang.resolve.scopes.JetScope; +import org.jetbrains.jet.lang.types.ErrorUtils; import javax.inject.Inject; import java.io.IOException; @@ -184,8 +185,7 @@ public class AnnotationDescriptorDeserializer implements AnnotationDeserializer if (ignoreAnnotation(desc)) return null; FqName annotationFqName = convertJvmDescriptorToFqName(desc); - final ClassDescriptor annotationClass = javaClassResolver.resolveClass(annotationFqName, IGNORE_KOTLIN_SOURCES); - assert annotationClass != null : "Annotation class is not found: " + desc; + final ClassDescriptor annotationClass = resolveAnnotationClass(annotationFqName); final AnnotationDescriptor annotation = new AnnotationDescriptor(); annotation.setAnnotationType(annotationClass.getDefaultType()); @@ -194,22 +194,31 @@ public class AnnotationDescriptorDeserializer implements AnnotationDeserializer @Override public void visit(String name, Object value) { CompileTimeConstant argument = JavaAnnotationArgumentResolver.resolveCompileTimeConstantValue(value, null); - if (argument != null) { - setArgumentValueByName(name, argument); - } + setArgumentValueByName(name, argument != null ? argument : new ErrorValue("Unsupported annotation argument: " + name)); } @Override public void visitEnum(String name, String desc, String value) { FqName fqName = convertJvmDescriptorToFqName(desc); - ClassDescriptor enumClass = javaClassResolver.resolveClass(fqName, IGNORE_KOTLIN_SOURCES); - assert enumClass != null : "Enum class referenced in annotation is not found: " + desc; - JetScope scope = DescriptorUtils.getEnumEntriesScope(enumClass); - Collection properties = scope.getProperties(Name.identifier(value)); - assert properties.size() == 1 : "Enum class should have exactly one property with the referenced name: " + value + - "\n" + properties + "\n" + enumClass; - EnumValue enumValue = new EnumValue((PropertyDescriptor) properties.iterator().next()); - setArgumentValueByName(name, enumValue); + setArgumentValueByName(name, enumEntryValue(fqName, Name.identifier(value))); + } + + @NotNull + private CompileTimeConstant enumEntryValue(@NotNull FqName enumFqName, @NotNull Name name) { + ClassDescriptor enumClass = javaClassResolver.resolveClass(enumFqName, IGNORE_KOTLIN_SOURCES); + if (enumClass != null && enumClass.getKind() == ClassKind.ENUM_CLASS) { + ClassDescriptor classObject = enumClass.getClassObjectDescriptor(); + if (classObject != null) { + Collection properties = classObject.getDefaultType().getMemberScope().getProperties(name); + if (properties.size() == 1) { + VariableDescriptor property = properties.iterator().next(); + if (property instanceof PropertyDescriptor) { + return new EnumValue((PropertyDescriptor) property); + } + } + } + } + return new ErrorValue("Unresolved enum entry: " + enumFqName + "." + name); } @Override @@ -227,6 +236,12 @@ public class AnnotationDescriptorDeserializer implements AnnotationDeserializer }; } + @NotNull + private ClassDescriptor resolveAnnotationClass(@NotNull FqName fqName) { + ClassDescriptor annotationClass = javaClassResolver.resolveClass(fqName, IGNORE_KOTLIN_SOURCES); + return annotationClass != null ? annotationClass : ErrorUtils.getErrorClass(); + } + @NotNull @Override public List loadCallableAnnotations(