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 00000000000..afdaa84cedd Binary files /dev/null and b/compiler/testData/compileKotlinAgainstCustomJava/missingEnumReferencedInAnnotation/MissingEnum.jar differ 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(