use of org.eclipse.ceylon.model.loader.model.AnnotationTarget in project ceylon by eclipse.
the class AnnotationUtil method isNaturalTarget.
/**
* Whether an annotation (with the given {@code annotationCtorDecl}
* annotation constructor) used on the given declaration ({@code useSite})
* should be added to the Java annotations of the given generated program
* elements ({@code target})
* @param annotationCtorDecl
* @param useSite
* @param target
* @return
*/
public static boolean isNaturalTarget(// use site is either a Declaration, or a Package, or a Module,
Function annotationCtorDecl, // module imports
Object useSite, OutputElement target) {
EnumSet<AnnotationTarget> interopTargets;
if (annotationCtorDecl instanceof AnnotationProxyMethod) {
AnnotationProxyMethod annotationProxyMethod = (AnnotationProxyMethod) annotationCtorDecl;
if (annotationProxyMethod.getAnnotationTarget() == target) {
// Foo__WHATEVER, so honour the WHATEVER
return true;
}
interopTargets = annotationProxyMethod.getAnnotationTargets();
} else {
interopTargets = null;
}
if (useSite instanceof Declaration) {
if (ModelUtil.isConstructor((Declaration) useSite)) {
if (useSite instanceof Functional) {
return target == OutputElement.CONSTRUCTOR;
} else if (useSite instanceof Value) {
// If the constructor has a getter we can't annotate, let's
// put the annotations on the constructor
Class constructedClass = ModelUtil.getConstructedClass((Declaration) useSite);
// See CeylonVisitor.transformSingletonConstructor for those tests
if (constructedClass.isToplevel() || constructedClass.isClassMember())
return target == OutputElement.GETTER;
return target == OutputElement.CONSTRUCTOR;
}
} else if (useSite instanceof Class) {
if (((Class) useSite).getParameterList() != null && interopTargets != null && interopTargets.contains(AnnotationTarget.CONSTRUCTOR) && !interopTargets.contains(AnnotationTarget.TYPE)) {
return target == OutputElement.CONSTRUCTOR;
}
return target == OutputElement.TYPE;
} else if (useSite instanceof Interface) {
return target == OutputElement.TYPE;
} else if (useSite instanceof Value) {
Value value = (Value) useSite;
boolean p = value.isParameter() && target == OutputElement.PARAMETER;
if (annotationCtorDecl instanceof AnnotationProxyMethod) {
if (!value.isTransient() && (interopTargets == null || interopTargets.contains(AnnotationTarget.FIELD))) {
return target == OutputElement.FIELD;
} else {
return target == OutputElement.GETTER;
}
} else {
return p || target == OutputElement.GETTER;
}
} else if (useSite instanceof Setter) {
return target == OutputElement.SETTER;
} else if (useSite instanceof Function) {
return target == OutputElement.METHOD;
} else if (useSite instanceof Constructor) {
return target == OutputElement.CONSTRUCTOR;
} else if (useSite instanceof TypeAlias) {
return target == OutputElement.TYPE;
}
} else if (useSite instanceof Package) {
return (annotationCtorDecl instanceof AnnotationProxyMethod) ? target == OutputElement.PACKAGE : target == OutputElement.TYPE;
} else if (useSite instanceof Module) {
return target == OutputElement.TYPE;
} else if (useSite instanceof Tree.ImportModule) {
return target == OutputElement.FIELD;
}
throw new RuntimeException("" + useSite);
}
use of org.eclipse.ceylon.model.loader.model.AnnotationTarget in project ceylon by eclipse.
the class AnnotationVisitor method checkAnnotations.
private void checkAnnotations(Tree.AnnotationList annotationList, Type declarationType, Type modelType, Node that) {
Unit unit = annotationList.getUnit();
List<Tree.Annotation> annotations = annotationList.getAnnotations();
for (Tree.Annotation annotation : annotations) {
Type t = annotation.getTypeModel();
if (t != null) {
TypeDeclaration cad = unit.getConstrainedAnnotationDeclaration();
Type cat = t.getSupertype(cad);
if (cat != null) {
// check *Ceylon* annotation constraints
List<Type> args = cat.getTypeArgumentList();
if (args.size() > 2) {
Type constraint = args.get(2);
checkAssignable(declarationType, constraint, annotation, "annotated program element does not satisfy annotation constraint");
}
if (args.size() > 3) {
Type constraint = args.get(3);
if (!constraint.isAnything()) {
checkAssignable(modelType, constraint, annotation, "annotated program element does not satisfy annotation constraint");
}
}
}
EnumSet<AnnotationTarget> target = null;
Tree.Primary primary = annotation.getPrimary();
if (primary instanceof Tree.MemberOrTypeExpression) {
Declaration ac = ((Tree.MemberOrTypeExpression) primary).getDeclaration();
if (ac instanceof TypedDeclaration) {
target = ((TypedDeclaration) ac).getAnnotationTargets();
}
}
if (target != null) {
// check the *Java* annotation constraints
boolean ok = false;
if (that instanceof Tree.PackageDescriptor) {
if (target.contains(PACKAGE)) {
ok = true;
}
}
if (that instanceof Tree.InterfaceDefinition) {
if (target.contains(TYPE)) {
ok = true;
}
}
if (that instanceof Tree.ClassDefinition) {
Tree.ClassDefinition c = (Tree.ClassDefinition) that;
boolean initializer = c.getParameterList() != null;
if (target.contains(TYPE)) {
// it always goes on the class,
// not on the constructor
ok = true;
}
if (target.contains(CONSTRUCTOR) && initializer) {
// it goes on the constructor
ok = true;
}
if (target.contains(ANNOTATION_TYPE) && c.getDeclarationModel().isAnnotation()) {
// it goes on the annotation type
ok = true;
}
}
if (that instanceof Tree.ObjectDefinition) {
if (target.contains(FIELD)) {
ok = true;
}
}
if (that instanceof Tree.Constructor || that instanceof Tree.Enumerated) {
if (target.contains(CONSTRUCTOR)) {
ok = true;
}
}
if (that instanceof Tree.MethodDefinition || that instanceof Tree.MethodDeclaration || that instanceof Tree.AttributeGetterDefinition || that instanceof Tree.AttributeSetterDefinition) {
if (target.contains(METHOD)) {
// it goes on the method, getter,
// or setter, unambiguously
ok = true;
}
}
if (that instanceof Tree.AttributeDeclaration) {
Tree.AttributeDeclaration ad = (Tree.AttributeDeclaration) that;
Value model = ad.getDeclarationModel();
boolean parameter = model.isParameter();
boolean classMember = model.isClassMember();
boolean toplevel = model.isToplevel();
boolean local = !toplevel && !model.isClassOrInterfaceMember();
if (target.contains(PARAMETER) && parameter) {
// in this case there is a parameter,
// so the annotation *never* goes on
// the field, getter, nor setter
ok = true;
}
Tree.SpecifierOrInitializerExpression se = ad.getSpecifierOrInitializerExpression();
if (se instanceof Tree.LazySpecifierExpression || model.isFormal()) {
if (target.contains(METHOD)) {
// there is no field, so it
// goes on the getter
ok = true;
}
} else {
// if it's cannot go on the field
if (classMember || toplevel) {
if (target.contains(FIELD)) {
ok = true;
} else if (target.contains(METHOD)) {
ok = true;
}
}
if (target.contains(LOCAL_VARIABLE) && !parameter && local) {
ok = true;
}
}
}
if (!ok) {
StringBuilder message = new StringBuilder();
for (AnnotationTarget at : target) {
if (message.length() > 0) {
message.append(", ");
}
message.append(at);
}
annotation.addError("annotated program element does not satisfy annotation constraint: the annotation is declared 'target {" + message + "}'");
}
}
}
}
TypeDeclaration od = unit.getOptionalAnnotationDeclaration();
for (int i = 0; i < annotations.size(); i++) {
Tree.Annotation ann = annotations.get(i);
Type t = ann.getTypeModel();
if (t != null) {
TypeDeclaration td = t.getDeclaration();
// this implicitly excludes Java annotations but they are checked in the backend for duplicates
if (td.inherits(od)) {
for (int j = 0; j < i; j++) {
Tree.Annotation other = annotations.get(j);
Type ot = other.getTypeModel();
if (ot != null) {
TypeDeclaration otd = ot.getDeclaration();
if (otd.equals(td)) {
ann.addError("duplicate annotation: there are multiple annotations of type '" + td.getName() + "'");
break;
}
}
}
}
}
}
}
use of org.eclipse.ceylon.model.loader.model.AnnotationTarget in project ceylon by eclipse.
the class ClassTransformer method transformAnnotationConstraints.
private List<JCAnnotation> transformAnnotationConstraints(Class klass) {
TypeDeclaration meta = (TypeDeclaration) typeFact().getLanguageModuleDeclaration("ConstrainedAnnotation");
Type constrainedType = klass.getType().getSupertype(meta);
EnumSet<AnnotationTarget> types = EnumSet.noneOf(AnnotationTarget.class);
if (constrainedType != null) {
Type programElement = constrainedType.getTypeArgumentList().get(2);
if (programElement.covers(((TypeDeclaration) typeFact().getLanguageModuleDeclarationDeclaration("InterfaceDeclaration")).getType()) || programElement.covers(((TypeDeclaration) typeFact().getLanguageModuleDeclarationDeclaration("ClassDeclaration")).getType()) || programElement.covers(((TypeDeclaration) typeFact().getLanguageModuleDeclarationDeclaration("ClassWithInitializerDeclaration")).getType()) || programElement.covers(((TypeDeclaration) typeFact().getLanguageModuleDeclarationDeclaration("ClassWithConstructorsDeclaration")).getType()) || programElement.covers(((TypeDeclaration) typeFact().getLanguageModuleDeclarationDeclaration("Package")).getType()) || programElement.covers(((TypeDeclaration) typeFact().getLanguageModuleDeclarationDeclaration("Module")).getType())) {
types.add(AnnotationTarget.TYPE);
}
if (programElement.covers(((TypeDeclaration) typeFact().getLanguageModuleDeclarationDeclaration("ValueDeclaration")).getType()) || programElement.covers(((TypeDeclaration) typeFact().getLanguageModuleDeclarationDeclaration("FunctionDeclaration")).getType())) {
types.add(AnnotationTarget.METHOD);
types.add(AnnotationTarget.PARAMETER);
}
if (programElement.covers(((TypeDeclaration) typeFact().getLanguageModuleDeclarationDeclaration("CallableConstructorDeclaration")).getType())) {
types.add(AnnotationTarget.CONSTRUCTOR);
}
if (programElement.covers(((TypeDeclaration) typeFact().getLanguageModuleDeclarationDeclaration("ValueConstructorDeclaration")).getType())) {
types.add(AnnotationTarget.METHOD);
}
if (programElement.covers(((TypeDeclaration) typeFact().getLanguageModuleDeclarationDeclaration("Import")).getType())) {
types.add(AnnotationTarget.FIELD);
}
if (programElement.covers(((TypeDeclaration) typeFact().getLanguageModuleDeclarationDeclaration("SetterDeclaration")).getType())) {
types.add(AnnotationTarget.METHOD);
}
if (programElement.covers(((TypeDeclaration) typeFact().getLanguageModuleDeclarationDeclaration("AliasDeclaration")).getType())) {
types.add(AnnotationTarget.TYPE);
}
}
return makeAtAnnotationTarget(types);
}
Aggregations