Search in sources :

Example 1 with OutputElement

use of com.redhat.ceylon.model.loader.model.OutputElement in project ceylon-compiler by ceylon.

the class ExpressionTransformer method transform.

private List<JCAnnotation> transform(Object useSite, OutputElement target, Tree.AnnotationList annotationList, EnumSet<OutputElement> outputs) {
    if (annotationList == null) {
        return List.nil();
    }
    if ((gen().disableAnnotations & CeylonTransformer.DISABLE_USER_ANNOS) != 0) {
        return List.nil();
    }
    LinkedHashMap<Class, ListBuffer<JCAnnotation>> annotationSet = new LinkedHashMap<>();
    if (annotationList != null) {
        if (annotationList.getAnonymousAnnotation() != null && isNaturalTarget((Function) typeFact().getLanguageModuleDeclaration("doc"), useSite, target)) {
            transformAnonymousAnnotation(annotationList.getAnonymousAnnotation(), annotationSet);
        }
        if (annotationList.getAnnotations() != null) {
            for (Tree.Annotation annotation : annotationList.getAnnotations()) {
                Function annoCtorDecl = ((Function) ((Tree.BaseMemberExpression) annotation.getPrimary()).getDeclaration());
                EnumSet<OutputElement> possibleTargets = AnnotationUtil.interopAnnotationTargeting(outputs, annotation, false);
                if ((isNaturalTarget(annoCtorDecl, useSite, target) && possibleTargets == null) || (possibleTargets != null && possibleTargets.equals(EnumSet.of(target)))) {
                    transformAnnotation(annotation, annotationSet);
                }
            }
        }
    }
    ListBuffer<JCAnnotation> result = ListBuffer.lb();
    for (Class annotationClass : annotationSet.keySet()) {
        ListBuffer<JCAnnotation> annotations = annotationSet.get(annotationClass);
        if (isSequencedAnnotation(annotationClass)) {
            JCAnnotation wrapperAnnotation = make().Annotation(makeJavaType(annotationClass.getType(), JT_ANNOTATIONS), List.<JCExpression>of(make().NewArray(null, null, (List) annotations.toList())));
            result.append(wrapperAnnotation);
        } else {
            if (annotations.size() > 1) {
                makeErroneous(annotationList, "compiler bug: multiple occurances of non-sequenced annotation class " + annotationClass.getQualifiedNameString());
            }
            result.appendList(annotations);
        }
    }
    // Special case: Generate a @java.lang.Deprecated() if Ceylon deprecated
    if (annotationList != null) {
        for (Tree.Annotation annotation : annotationList.getAnnotations()) {
            if (isNaturalTarget((Function) typeFact().getLanguageModuleDeclaration("deprecated"), useSite, target) && isDeprecatedAnnotation(annotation.getPrimary())) {
                result.append(make().Annotation(make().Type(syms().deprecatedType), List.<JCExpression>nil()));
            }
        }
    }
    return result.toList();
}
Also used : ListBuffer(com.sun.tools.javac.util.ListBuffer) LinkedHashMap(java.util.LinkedHashMap) Function(com.redhat.ceylon.model.typechecker.model.Function) JCExpression(com.sun.tools.javac.tree.JCTree.JCExpression) OutputElement(com.redhat.ceylon.model.loader.model.OutputElement) JCTree(com.sun.tools.javac.tree.JCTree) Tree(com.redhat.ceylon.compiler.typechecker.tree.Tree) Class(com.redhat.ceylon.model.typechecker.model.Class) JCNewClass(com.sun.tools.javac.tree.JCTree.JCNewClass) JCAnnotation(com.sun.tools.javac.tree.JCTree.JCAnnotation)

Example 2 with OutputElement

use of com.redhat.ceylon.model.loader.model.OutputElement in project ceylon-compiler by ceylon.

the class AnnotationUtil method duplicateInteropAnnotation.

public static void duplicateInteropAnnotation(EnumSet<OutputElement> outputs, List<Annotation> annotations) {
    for (int i = 0; i < annotations.size(); i++) {
        Tree.Annotation ann = annotations.get(i);
        Type t = ann.getTypeModel();
        EnumSet<OutputElement> mainTargets = interopAnnotationTargeting(outputs, ann, false);
        if (t != null && mainTargets != null) {
            TypeDeclaration td = t.getDeclaration();
            if (!ModelUtil.isCeylonDeclaration(td)) {
                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)) {
                            // check if they have the same targets (if not that's fine)
                            EnumSet<OutputElement> dupeTargets = interopAnnotationTargeting(outputs, other, false);
                            if (dupeTargets != null) {
                                EnumSet<OutputElement> sameTargets = intersection(mainTargets, dupeTargets);
                                if (!sameTargets.isEmpty()) {
                                    ann.addError("duplicate annotation: there are multiple annotations of type '" + td.getName() + "' for targets: '" + sameTargets + "'");
                                    break;
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
Also used : Type(com.redhat.ceylon.model.typechecker.model.Type) OutputElement(com.redhat.ceylon.model.loader.model.OutputElement) Tree(com.redhat.ceylon.compiler.typechecker.tree.Tree) Annotation(com.redhat.ceylon.compiler.typechecker.tree.Tree.Annotation) TypeDeclaration(com.redhat.ceylon.model.typechecker.model.TypeDeclaration)

Example 3 with OutputElement

use of com.redhat.ceylon.model.loader.model.OutputElement in project ceylon-compiler by ceylon.

the class AnnotationUtil method outputs.

public static EnumSet<OutputElement> outputs(Tree.AttributeDeclaration that) {
    EnumSet<OutputElement> result = EnumSet.noneOf(OutputElement.class);
    Value declarationModel = that.getDeclarationModel();
    if (declarationModel != null) {
        if (declarationModel.isClassMember()) {
            if (declarationModel.isParameter()) {
                result.add(PARAMETER);
            }
            if (declarationModel.isShared() || declarationModel.isCaptured()) {
                result.add(GETTER);
                if (!(that.getSpecifierOrInitializerExpression() instanceof Tree.LazySpecifierExpression)) {
                    result.add(FIELD);
                }
            } else if (!declarationModel.isParameter()) {
                result.add(LOCAL_VARIABLE);
            }
        } else if (declarationModel.isInterfaceMember()) {
            result.add(GETTER);
        } else if (declarationModel.isToplevel()) {
            result.add(GETTER);
            result.add(FIELD);
        } else {
            if (declarationModel.isParameter()) {
                result.add(PARAMETER);
            } else {
                result.add(LOCAL_VARIABLE);
            }
        }
    }
    if (result.contains(GETTER) && (declarationModel.isVariable() || declarationModel.isLate())) {
        result.add(SETTER);
    }
    return result;
}
Also used : OutputElement(com.redhat.ceylon.model.loader.model.OutputElement) Value(com.redhat.ceylon.model.typechecker.model.Value)

Example 4 with OutputElement

use of com.redhat.ceylon.model.loader.model.OutputElement in project ceylon-compiler by ceylon.

the class AnnotationUtil method interopAnnotationTargeting.

/**
     * Returns the set of output program elements that the given annotation 
     * could be applied to. If the {@code errors} flag is true then add 
     * warnings/errors to the tree about ambigous/impossible targets.
     */
public static EnumSet<OutputElement> interopAnnotationTargeting(EnumSet<OutputElement> outputs, Tree.Annotation annotation, boolean errors) {
    Declaration annoCtor = ((Tree.BaseMemberExpression) annotation.getPrimary()).getDeclaration();
    if (annoCtor instanceof AnnotationProxyMethod) {
        AnnotationProxyMethod proxyCtor = (AnnotationProxyMethod) annoCtor;
        AnnotationProxyClass annoClass = proxyCtor.getProxyClass();
        EnumSet<OutputElement> possibleTargets;
        if (proxyCtor.getAnnotationTarget() != null) {
            possibleTargets = EnumSet.of(proxyCtor.getAnnotationTarget());
        } else {
            possibleTargets = AnnotationTarget.outputTargets(annoClass);
        }
        EnumSet<OutputElement> actualTargets = possibleTargets.clone();
        actualTargets.retainAll(outputs);
        if (actualTargets.size() > 1) {
            if (errors) {
                StringBuffer sb = new StringBuffer();
                sb.append("ambiguous annotation target: ").append(annoCtor.getName());
                sb.append(" could be applied to several targets, use one of ");
                for (Iterator<OutputElement> iterator = actualTargets.iterator(); iterator.hasNext(); ) {
                    OutputElement x = iterator.next();
                    sb.append(Naming.getDisambigAnnoCtorName((Interface) ((AnnotationProxyMethod) annoCtor).getProxyClass().iface, x));
                    if (iterator.hasNext()) {
                        sb.append(", ");
                    }
                }
                sb.append(" to disambiguate");
                annotation.addUsageWarning(Warning.ambiguousAnnotation, sb.toString(), Backend.Java);
            }
            return null;
        } else if (actualTargets.size() == 0) {
            if (errors) {
                annotation.addError("no target for " + annoCtor.getName() + " annotation: @Target of @interface " + ((AnnotationProxyClass) annoClass).iface.getName() + " lists " + possibleTargets + " but annotated element tranforms to " + outputs, Backend.Java);
            }
        }
        return actualTargets;
    } else {
        return null;
    }
}
Also used : AnnotationProxyMethod(com.redhat.ceylon.model.loader.model.AnnotationProxyMethod) OutputElement(com.redhat.ceylon.model.loader.model.OutputElement) AnnotationProxyClass(com.redhat.ceylon.model.loader.model.AnnotationProxyClass) Declaration(com.redhat.ceylon.model.typechecker.model.Declaration) TypeDeclaration(com.redhat.ceylon.model.typechecker.model.TypeDeclaration) Interface(com.redhat.ceylon.model.typechecker.model.Interface)

Aggregations

OutputElement (com.redhat.ceylon.model.loader.model.OutputElement)4 Tree (com.redhat.ceylon.compiler.typechecker.tree.Tree)2 TypeDeclaration (com.redhat.ceylon.model.typechecker.model.TypeDeclaration)2 Annotation (com.redhat.ceylon.compiler.typechecker.tree.Tree.Annotation)1 AnnotationProxyClass (com.redhat.ceylon.model.loader.model.AnnotationProxyClass)1 AnnotationProxyMethod (com.redhat.ceylon.model.loader.model.AnnotationProxyMethod)1 Class (com.redhat.ceylon.model.typechecker.model.Class)1 Declaration (com.redhat.ceylon.model.typechecker.model.Declaration)1 Function (com.redhat.ceylon.model.typechecker.model.Function)1 Interface (com.redhat.ceylon.model.typechecker.model.Interface)1 Type (com.redhat.ceylon.model.typechecker.model.Type)1 Value (com.redhat.ceylon.model.typechecker.model.Value)1 JCTree (com.sun.tools.javac.tree.JCTree)1 JCAnnotation (com.sun.tools.javac.tree.JCTree.JCAnnotation)1 JCExpression (com.sun.tools.javac.tree.JCTree.JCExpression)1 JCNewClass (com.sun.tools.javac.tree.JCTree.JCNewClass)1 ListBuffer (com.sun.tools.javac.util.ListBuffer)1 LinkedHashMap (java.util.LinkedHashMap)1