diff --git a/compiler-java/src/com/redhat/ceylon/compiler/java/codegen/AbstractTransformer.java b/compiler-java/src/com/redhat/ceylon/compiler/java/codegen/AbstractTransformer.java index 19d66d98ac4..457c70fb60e 100755 --- a/compiler-java/src/com/redhat/ceylon/compiler/java/codegen/AbstractTransformer.java +++ b/compiler-java/src/com/redhat/ceylon/compiler/java/codegen/AbstractTransformer.java @@ -54,7 +54,7 @@ import com.redhat.ceylon.compiler.java.loader.TypeFactory; import com.redhat.ceylon.compiler.java.tools.CeylonLog; import com.redhat.ceylon.compiler.loader.AbstractModelLoader; -import com.redhat.ceylon.compiler.loader.ModifierAnnotation; +import com.redhat.ceylon.compiler.loader.LanguageAnnotation; import com.redhat.ceylon.compiler.typechecker.model.Annotation; import com.redhat.ceylon.compiler.typechecker.model.Class; import com.redhat.ceylon.compiler.typechecker.model.ClassOrInterface; @@ -2957,7 +2957,7 @@ List makeAtTransient() { protected void initModelAnnotations() { if (gen().omittedModelAnnotations == null) { HashMap map = new HashMap(); - for (ModifierAnnotation mod : ModifierAnnotation.values()) { + for (LanguageAnnotation mod : LanguageAnnotation.values()) { map.put(mod.name, mod.mask); } gen().omittedModelAnnotations = map; diff --git a/compiler-java/src/com/redhat/ceylon/compiler/loader/AbstractModelLoader.java b/compiler-java/src/com/redhat/ceylon/compiler/loader/AbstractModelLoader.java index 4a5c70c844b..edc8a07caab 100644 --- a/compiler-java/src/com/redhat/ceylon/compiler/loader/AbstractModelLoader.java +++ b/compiler-java/src/com/redhat/ceylon/compiler/loader/AbstractModelLoader.java @@ -187,14 +187,30 @@ public abstract class AbstractModelLoader implements ModelCompleter, ModelLoader private static final String CEYLON_DYNAMIC_ANNOTATION = "com.redhat.ceylon.compiler.java.metadata.Dynamic"; private static final String JAVA_DEPRECATED_ANNOTATION = "java.lang.Deprecated"; - private static final String CEYLON_LANGUAGE_ABSTRACT_ANNOTATION = "ceylon.language.AbstractAnnotation$annotation$"; - private static final String CEYLON_LANGUAGE_ACTUAL_ANNOTATION = "ceylon.language.ActualAnnotation$annotation$"; - private static final String CEYLON_LANGUAGE_ANNOTATION_ANNOTATION = "ceylon.language.AnnotationAnnotation$annotation$"; - private static final String CEYLON_LANGUAGE_DEFAULT_ANNOTATION = "ceylon.language.DefaultAnnotation$annotation$"; - private static final String CEYLON_LANGUAGE_FORMAL_ANNOTATION = "ceylon.language.FormalAnnotation$annotation$"; - private static final String CEYLON_LANGUAGE_SHARED_ANNOTATION = "ceylon.language.SharedAnnotation$annotation$"; - private static final String CEYLON_LANGUAGE_LATE_ANNOTATION = "ceylon.language.LateAnnotation$annotation$"; - private static final String CEYLON_LANGUAGE_SEALED_ANNOTATION = "ceylon.language.SealedAnnotation$annotation$"; + static final String CEYLON_LANGUAGE_ABSTRACT_ANNOTATION = "ceylon.language.AbstractAnnotation$annotation$"; + static final String CEYLON_LANGUAGE_ACTUAL_ANNOTATION = "ceylon.language.ActualAnnotation$annotation$"; + static final String CEYLON_LANGUAGE_ANNOTATION_ANNOTATION = "ceylon.language.AnnotationAnnotation$annotation$"; + static final String CEYLON_LANGUAGE_DEFAULT_ANNOTATION = "ceylon.language.DefaultAnnotation$annotation$"; + static final String CEYLON_LANGUAGE_FORMAL_ANNOTATION = "ceylon.language.FormalAnnotation$annotation$"; + static final String CEYLON_LANGUAGE_SHARED_ANNOTATION = "ceylon.language.SharedAnnotation$annotation$"; + static final String CEYLON_LANGUAGE_LATE_ANNOTATION = "ceylon.language.LateAnnotation$annotation$"; + static final String CEYLON_LANGUAGE_SEALED_ANNOTATION = "ceylon.language.SealedAnnotation$annotation$"; + static final String CEYLON_LANGUAGE_VARIABLE_ANNOTATION = "ceylon.language.VariableAnnotation$annotation$"; + static final String CEYLON_LANGUAGE_FINAL_ANNOTATION = "ceylon.language.FinalAnnotation$annotation$"; + static final String CEYLON_LANGUAGE_NATIVE_ANNOTATION = "ceylon.language.NativeAnnotation$annotation$"; + static final String CEYLON_LANGUAGE_OPTIONAL_ANNOTATION = "ceylon.language.OptionalAnnotation$annotation$"; + static final String CEYLON_LANGUAGE_SERIALIZABLE_ANNOTATION = "ceylon.language.SerializableAnnotation$annotation$"; + + static final String CEYLON_LANGUAGE_DOC_ANNOTATION = "ceylon.language.DocAnnotation$annotation$"; + static final String CEYLON_LANGUAGE_THROWS_ANNOTATIONS = "ceylon.language.ThrownExceptionAnnotation$annotations$"; + static final String CEYLON_LANGUAGE_THROWS_ANNOTATION = "ceylon.language.ThrownExceptionAnnotation$annotation$"; + static final String CEYLON_LANGUAGE_AUTHORS_ANNOTATION = "ceylon.language.AuthorsAnnotation$annotation$"; + static final String CEYLON_LANGUAGE_SEE_ANNOTATIONS = "ceylon.language.SeeAnnotation$annotations$"; + static final String CEYLON_LANGUAGE_SEE_ANNOTATION = "ceylon.language.SeeAnnotation$annotation$"; + static final String CEYLON_LANGUAGE_DEPRECATED_ANNOTATION = "ceylon.language.DeprecationAnnotation$annotation$"; + static final String CEYLON_LANGUAGE_SUPPRESS_WARNINGS_ANNOTATION = "ceylon.language.SuppressWarningsAnnotation$annotation$"; + static final String CEYLON_LANGUAGE_LICENSE_ANNOTATION = "ceylon.language.LicenseAnnotation$annotation$"; + static final String CEYLON_LANGUAGE_TAGS_ANNOTATION = "ceylon.language.TagsAnnotation$annotation$"; // important that these are with :: private static final String CEYLON_LANGUAGE_CALLABLE_TYPE_NAME = "ceylon.language::Callable"; @@ -2305,19 +2321,44 @@ private boolean isFromJDK(ClassMirror classMirror) { } private void setAnnotations(Declaration decl, AnnotatedMirror classMirror) { - Long mods = (Long)getAnnotationValue(classMirror, CEYLON_ANNOTATIONS_ANNOTATION, "modifiers"); - if (mods != null) { - for (ModifierAnnotation mod : ModifierAnnotation.values()) { - if ((mod.mask & mods) != 0) { - decl.getAnnotations().add(mod.makeAnnotation()); + if (classMirror.getAnnotation(CEYLON_ANNOTATIONS_ANNOTATION) != null) { + // If the class has @Annotations then use it (in >=1.2 only ceylon.language does) + Long mods = (Long)getAnnotationValue(classMirror, CEYLON_ANNOTATIONS_ANNOTATION, "modifiers"); + if (mods != null) { + // If there is a modifiers value then use it to load the modifiers + for (LanguageAnnotation mod : LanguageAnnotation.values()) { + if (mod.isModifier()) { + if ((mod.mask & mods) != 0) { + decl.getAnnotations().addAll(mod.makeFromCeylonAnnotation(null)); + } + } } + } - - } - List annotations = getAnnotationArrayValue(classMirror, CEYLON_ANNOTATIONS_ANNOTATION); - if(annotations != null) { - for(AnnotationMirror annotation : annotations){ - decl.getAnnotations().add(readModelAnnotation(annotation)); + // Load anything else the long way, reading the @Annotation(name=...) + List annotations = getAnnotationArrayValue(classMirror, CEYLON_ANNOTATIONS_ANNOTATION); + if(annotations != null) { + for(AnnotationMirror annotation : annotations){ + decl.getAnnotations().add(readModelAnnotation(annotation)); + } + } + } else { + // If the class lacks @Annotations then set the modifier annotations + // according to the presence of @Shared$annotation etc + Declaration receiver; + if ((decl instanceof Value) + && ((Value)decl).getTypeDeclaration().isAnonymous()) { + receiver = ((Value)decl).getTypeDeclaration(); + } else { + receiver = null; + } + for (LanguageAnnotation mod : LanguageAnnotation.values()) { + if (classMirror.getAnnotation(mod.annotationType) != null) { + decl.getAnnotations().addAll(mod.makeFromCeylonAnnotation(classMirror.getAnnotation(mod.annotationType))); + if (receiver != null) { + receiver.getAnnotations().addAll(mod.makeFromCeylonAnnotation(classMirror.getAnnotation(mod.annotationType))); + } + } } } // Add a ceylon deprecated("") if it's annotated with java.lang.Deprecated diff --git a/compiler-java/src/com/redhat/ceylon/compiler/loader/LanguageAnnotation.java b/compiler-java/src/com/redhat/ceylon/compiler/loader/LanguageAnnotation.java new file mode 100644 index 00000000000..d1d8744d2c5 --- /dev/null +++ b/compiler-java/src/com/redhat/ceylon/compiler/loader/LanguageAnnotation.java @@ -0,0 +1,150 @@ +package com.redhat.ceylon.compiler.loader; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import com.redhat.ceylon.compiler.loader.mirror.AnnotationMirror; +import com.redhat.ceylon.compiler.typechecker.model.Annotation; + +/** + * Enumerates the language module annotations and allows them to be loaded from mirrors + */ +public enum LanguageAnnotation { + /* modifier annotations */ + ANNOTATION("annotation", 1L<<0, AbstractModelLoader.CEYLON_LANGUAGE_ANNOTATION_ANNOTATION), + SHARED("shared", 1L<<1, AbstractModelLoader.CEYLON_LANGUAGE_SHARED_ANNOTATION), + VARIABLE("variable", 1L<<2, AbstractModelLoader.CEYLON_LANGUAGE_VARIABLE_ANNOTATION), + ABSTRACT("abstract", 1L<<3, AbstractModelLoader.CEYLON_LANGUAGE_ABSTRACT_ANNOTATION), + SEALED("sealed", 1L<<4, AbstractModelLoader.CEYLON_LANGUAGE_SEALED_ANNOTATION), + FINAL("final", 1L<<5, AbstractModelLoader.CEYLON_LANGUAGE_FINAL_ANNOTATION), + ACTUAL("actual", 1L<<6, AbstractModelLoader.CEYLON_LANGUAGE_ACTUAL_ANNOTATION), + FORMAL("formal", 1L<<7, AbstractModelLoader.CEYLON_LANGUAGE_FORMAL_ANNOTATION), + DEFAULT("default", 1L<<8, AbstractModelLoader.CEYLON_LANGUAGE_DEFAULT_ANNOTATION), + LATE("late", 1L<<9, AbstractModelLoader.CEYLON_LANGUAGE_LATE_ANNOTATION), + NATIVE("native", 1L<<10, AbstractModelLoader.CEYLON_LANGUAGE_NATIVE_ANNOTATION), + OPTIONAL("optional", 1L<<11, AbstractModelLoader.CEYLON_LANGUAGE_OPTIONAL_ANNOTATION), + SERIALIZABLE("serializable", 1L<<12, AbstractModelLoader.CEYLON_LANGUAGE_SERIALIZABLE_ANNOTATION), + + /* documentation annotations */ + DOC("doc", 0, AbstractModelLoader.CEYLON_LANGUAGE_DOC_ANNOTATION) { + public List makeFromCeylonAnnotation(AnnotationMirror mirror) { + Annotation anno = new Annotation(name); + anno.addPositionalArgment((String)mirror.getValue("description")); + return Collections.singletonList(anno); + } + }, + THROWS("throws", 0, AbstractModelLoader.CEYLON_LANGUAGE_THROWS_ANNOTATIONS) { + public List makeFromCeylonAnnotation(AnnotationMirror mirror) { + List thrownExceptions = (List)mirror.getValue("value"); + List result = new ArrayList(thrownExceptions.size()); + for (AnnotationMirror thrown : thrownExceptions) { + Annotation anno = new Annotation(name); + // can't decode the declaration + anno.addPositionalArgment(parseMetamodelReference((String)thrown.getValue("type"))); + anno.addPositionalArgment((String)thrown.getValue("when")); + result.add(anno); + } + return result; + } + }, + BY("by", 0, AbstractModelLoader.CEYLON_LANGUAGE_AUTHORS_ANNOTATION) { + public List makeFromCeylonAnnotation(AnnotationMirror mirror) { + Annotation anno = new Annotation(name); + for (String author : (List)mirror.getValue("authors")) { + anno.addPositionalArgment(author); + } + return Collections.singletonList(anno); + } + }, + SEE("see", 0, AbstractModelLoader.CEYLON_LANGUAGE_SEE_ANNOTATIONS) { + public List makeFromCeylonAnnotation(AnnotationMirror mirror) { + List sees = (List)mirror.getValue("value"); + List result = new ArrayList(sees.size()); + for (AnnotationMirror see : sees) { + Annotation anno = new Annotation(name); + // can't decode the declaration + for (String s : (List)see.getValue("programElements")) { + anno.addPositionalArgment(parseMetamodelReference(s)); + } + result.add(anno); + } + return result; + } + + }, + LICENSE("license", 0, AbstractModelLoader.CEYLON_LANGUAGE_LICENSE_ANNOTATION) { + public List makeFromCeylonAnnotation(AnnotationMirror mirror) { + Annotation anno = new Annotation(name); + anno.addPositionalArgment((String)mirror.getValue("description")); + return Collections.singletonList(anno); + } + }, + DEPRECATED("deprecated", 0, AbstractModelLoader.CEYLON_LANGUAGE_DEPRECATED_ANNOTATION) { + public List makeFromCeylonAnnotation(AnnotationMirror mirror) { + Annotation anno = new Annotation(name); + anno.addPositionalArgment((String)mirror.getValue("reason")); + return Collections.singletonList(anno); + } + }, + TAGGED("tagged", 0, AbstractModelLoader.CEYLON_LANGUAGE_TAGS_ANNOTATION) { + public List makeFromCeylonAnnotation(AnnotationMirror mirror) { + Annotation anno = new Annotation(name); + for (String tag : (List)mirror.getValue("tags")) { + anno.addPositionalArgment(tag); + } + return Collections.singletonList(anno); + } + }, + SUPPRESS_WARNINGS("suppressWarnings", 0, AbstractModelLoader.CEYLON_LANGUAGE_SUPPRESS_WARNINGS_ANNOTATION) { + public List makeFromCeylonAnnotation(AnnotationMirror mirror) { + Annotation anno = new Annotation(name); + anno.addPositionalArgment((String)mirror.getValue("warnings")); + return Collections.singletonList(anno); + } + }; + + /** + * The unqualified Ceylon name of the annotation, e.g. {@code shared} + */ + public final String name; + + /** + * The mask used to address this modifier when encoded as a long. + * zero if this annotation is not a model annotation + */ + public final long mask; + /** + * The qualifier Java name of the annotation type, e.g. {@code ceylon.language.Shared$annotation$} + */ + public final String annotationType; + + LanguageAnnotation(String name, long mask, String annotationType) { + this.name = name; + this.mask = mask; + this.annotationType = annotationType; + } + + /** + * Whether this annotation is a modifier annotation + * (i.e. one whose annotation class is nullary, and + * therefore whose presence/absence is all that matters) + */ + public boolean isModifier() { + return mask != 0; + } + + /** + * Construct a Ceylon annotation model from the information stored in + * the mirror of the Ceylon annotation. + * @param mirror The mirror of the Ceylon annotation. + * @return + */ + public List makeFromCeylonAnnotation(AnnotationMirror mirror) { + return Collections.singletonList(new Annotation(name)); + } + + protected String parseMetamodelReference(String s) { + return s.replaceAll("^.*::[C]", "").replaceAll("^.*\\.[C]", ""); + } +} diff --git a/compiler-java/src/com/redhat/ceylon/compiler/loader/ModifierAnnotation.java b/compiler-java/src/com/redhat/ceylon/compiler/loader/ModifierAnnotation.java deleted file mode 100644 index 53e36d5702c..00000000000 --- a/compiler-java/src/com/redhat/ceylon/compiler/loader/ModifierAnnotation.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.redhat.ceylon.compiler.loader; - -import java.util.HashMap; - -import com.redhat.ceylon.compiler.typechecker.model.Annotation; - -/** - * Enumerates the language module annotations that can be treated as - * modifiers (i.e. whose annotation class is nullary) - */ -public enum ModifierAnnotation { - ANNOTATION("annotation", 1L<<0), - SHARED("shared", 1L<<1), - VARIABLE("variable", 1L<<2), - ABSTRACT("abstract", 1L<<3), - SEALED("sealed", 1L<<4), - FINAL("final", 1L<<5), - ACTUAL("actual", 1L<<6), - FORMAL("formal", 1L<<7), - DEFAULT("default", 1L<<8), - LATE("late", 1L<<9), - NATIVE("native", 1L<<10), - OPTIONAL("optional", 1L<<11), - SERIALIZABLE("serializable", 1L<<12); - - public final String name; - - /** The mask used to address this modifier when encoded as a long. */ - public final long mask; - - ModifierAnnotation(String name, long mask) { - this.name = name; - this.mask = mask; - } - - public Annotation makeAnnotation() { - return new Annotation(name); - } -}