Package com.redhat.ceylon.compiler.typechecker.analyzer

Source Code of com.redhat.ceylon.compiler.typechecker.analyzer.AnnotationVisitor

package com.redhat.ceylon.compiler.typechecker.analyzer;

import static com.redhat.ceylon.compiler.typechecker.analyzer.Util.checkAssignable;
import static com.redhat.ceylon.compiler.typechecker.model.Module.LANGUAGE_MODULE_NAME;
import static com.redhat.ceylon.compiler.typechecker.model.Util.isAbstraction;

import java.util.ArrayList;
import java.util.List;

import com.redhat.ceylon.compiler.typechecker.model.Class;
import com.redhat.ceylon.compiler.typechecker.model.Declaration;
import com.redhat.ceylon.compiler.typechecker.model.Functional;
import com.redhat.ceylon.compiler.typechecker.model.Interface;
import com.redhat.ceylon.compiler.typechecker.model.IntersectionType;
import com.redhat.ceylon.compiler.typechecker.model.Method;
import com.redhat.ceylon.compiler.typechecker.model.MethodOrValue;
import com.redhat.ceylon.compiler.typechecker.model.NothingType;
import com.redhat.ceylon.compiler.typechecker.model.Package;
import com.redhat.ceylon.compiler.typechecker.model.Parameter;
import com.redhat.ceylon.compiler.typechecker.model.ProducedType;
import com.redhat.ceylon.compiler.typechecker.model.TypeAlias;
import com.redhat.ceylon.compiler.typechecker.model.TypeDeclaration;
import com.redhat.ceylon.compiler.typechecker.model.TypedDeclaration;
import com.redhat.ceylon.compiler.typechecker.model.UnionType;
import com.redhat.ceylon.compiler.typechecker.model.Unit;
import com.redhat.ceylon.compiler.typechecker.model.Value;
import com.redhat.ceylon.compiler.typechecker.tree.Node;
import com.redhat.ceylon.compiler.typechecker.tree.Tree;
import com.redhat.ceylon.compiler.typechecker.tree.Tree.Annotation;
import com.redhat.ceylon.compiler.typechecker.tree.Tree.AnnotationList;
import com.redhat.ceylon.compiler.typechecker.tree.Tree.PositionalArgument;
import com.redhat.ceylon.compiler.typechecker.tree.Tree.Term;
import com.redhat.ceylon.compiler.typechecker.tree.Visitor;

public class AnnotationVisitor extends Visitor {
   
    private static final String DOC_LINK_MODULE = "module ";
    private static final String DOC_LINK_PACKAGE = "package ";
    private static final String DOC_LINK_CLASS = "class ";
    private static final String DOC_LINK_INTERFACE = "interface ";
    private static final String DOC_LINK_FUNCTION = "function ";
    private static final String DOC_LINK_VALUE = "value ";
    private static final String DOC_LINK_ALIAS = "alias ";

    private static boolean isIllegalAnnotationParameterType(ProducedType pt) {
        if (pt!=null) {
            TypeDeclaration ptd = pt.getDeclaration();
            if (ptd instanceof IntersectionType || ptd instanceof UnionType) {
                return true;
            }
            Unit unit = pt.getDeclaration().getUnit();
            if (!ptd.isAnnotation() && !isEnum(ptd) &&
                    !ptd.equals(unit.getBooleanDeclaration()) &&
                    !ptd.equals(unit.getStringDeclaration()) &&
                    !ptd.equals(unit.getIntegerDeclaration()) &&
                    !ptd.equals(unit.getFloatDeclaration()) &&
                    !ptd.equals(unit.getCharacterDeclaration()) &&
                    !ptd.equals(unit.getIterableDeclaration()) &&
                    !ptd.equals(unit.getSequentialDeclaration()) &&
                    !pt.isSubtypeOf(unit.getType(unit.getDeclarationDeclaration()))) {
                return true;
            }
            if (ptd.equals(unit.getIterableDeclaration()) ||
                    ptd.equals(unit.getSequentialDeclaration())) {
                if (isIllegalAnnotationParameterType(unit.getIteratedType(pt))) {
                    return true;
                }
            }
        }
        return false;
    }
   
    private static boolean isEnum(TypeDeclaration ptd) {
        List<TypeDeclaration> ctds = ptd.getCaseTypeDeclarations();
        if (ctds==null) {
            return false;
        }
        else {
            for (TypeDeclaration td: ctds) {
                if (!td.isAnonymous()) return false;
            }
            return true;
        }
    }
   
    private void checkAnnotationParameter(Functional a, Tree.Parameter pn) {
        Parameter p = pn.getParameterModel();
      if (!(p.getModel() instanceof Value)) {
        pn.addError("annotations may not have callable parameters");
      }
      else {
        ProducedType pt = p.getType();
        if (pt!=null && isIllegalAnnotationParameterType(pt)) {
          Node errorNode = pn instanceof Tree.ValueParameterDeclaration ?
              ((Tree.ValueParameterDeclaration) pn).getTypedDeclaration().getType() : pn;
          errorNode.addError("illegal annotation parameter type: '" +
              pt.getProducedTypeName() + "'");
        }
        Tree.SpecifierOrInitializerExpression se = null;
        if (pn instanceof Tree.InitializerParameter) {
          se = ((Tree.InitializerParameter) pn).getSpecifierExpression();
        }
        else if (pn instanceof Tree.ParameterDeclaration) {
          Tree.TypedDeclaration td = ((Tree.ParameterDeclaration) pn).getTypedDeclaration();
          if (td instanceof Tree.MethodDeclaration) {
            se = ((Tree.MethodDeclaration) td).getSpecifierExpression();
          }
          else if (td instanceof Tree.AttributeDeclaration) {
            se = ((Tree.AttributeDeclaration) td).getSpecifierOrInitializerExpression();
          }
        }
        if (se!=null) {
          checkAnnotationArgument(a, se.getExpression(), pt);
        }
      }
    }
   
    private void checkAnnotationArgument(Functional a, Tree.Expression e, ProducedType pt) {
        if (e!=null) {
            Tree.Term term = e.getTerm();
            if (term instanceof Tree.Literal) {
                //ok
            }
            else if (term instanceof Tree.NegativeOp &&
                    ((Tree.NegativeOp) term).getTerm() instanceof Tree.Literal) {
                //ok
            }
            else if (term instanceof Tree.MetaLiteral) {
                //ok
            }
            else if (term instanceof Tree.Tuple) {
                Tree.SequencedArgument sa =
                        ((Tree.Tuple) term).getSequencedArgument();
                if (sa!=null) {
                    for (PositionalArgument arg: sa.getPositionalArguments()) {
                        if (arg instanceof Tree.ListedArgument){
                            Tree.Expression expression = ((Tree.ListedArgument) arg).getExpression();
                            if (expression!=null) {
                                checkAnnotationArgument(a, expression, arg.getTypeModel());
                            }
                        }
                        else {
                            e.addError("illegal annotation argument: must be a literal value, metamodel reference, annotation instantiation, or parameter reference");
                        }
                    }
                }
            }
            else if (term instanceof Tree.SequenceEnumeration) {
                Tree.SequencedArgument sa =
                        ((Tree.SequenceEnumeration) term).getSequencedArgument();
                if (sa!=null) {
                    for (Tree.PositionalArgument arg: sa.getPositionalArguments()){
                        if (arg instanceof Tree.ListedArgument){
                            Tree.Expression expression =
                                    ((Tree.ListedArgument) arg).getExpression();
                            if (expression!=null) {
                                checkAnnotationArgument(a, expression, arg.getTypeModel());
                            }
                        }
                        else {
                            e.addError("illegal annotation argument: must be a literal value, metamodel reference, annotation instantiation, or parameter reference");
                        }
                    }
                }
            }
            else if (term instanceof Tree.InvocationExpression) {
                checkAnnotationInstantiation(a, e, pt);
            }
            else if (term instanceof Tree.BaseMemberExpression) {
                Tree.BaseMemberExpression bme = (Tree.BaseMemberExpression) term;
                Declaration d = bme.getDeclaration();
                if (a!=null && d!=null && d.isParameter()) {
                    Parameter p = ((MethodOrValue) d).getInitializerParameter();
                    if (!p.getDeclaration().equals(a)) {
                        e.addError("illegal annotation argument: must be a reference to a parameter of the annotation");
                    }
                }
                else if (d instanceof Value &&
                        (((Value) d).isEnumValue() || ((Value) d).getTypeDeclaration().isAnonymous())) {
                    //ok
                }
                else {
                    e.addError("illegal annotation argument: must be a literal value, metamodel reference, annotation instantiation, or parameter reference");
                }
            }
            else if (term instanceof Tree.QualifiedMemberExpression) {
                Tree.QualifiedMemberExpression qme = (Tree.QualifiedMemberExpression) term;
                Declaration d = qme.getDeclaration();
                if (d!=null && !d.isStaticallyImportable()) {
                    e.addError("illegal annotation argument: must be a literal value, metamodel reference, annotation instantiation, or parameter reference");
                   
                }
                else {
                    Tree.Primary p = qme.getPrimary();
                    while (!(p instanceof Tree.BaseTypeExpression)) {
                        if (p instanceof Tree.QualifiedTypeExpression) {
                            p = ((Tree.QualifiedTypeExpression) p).getPrimary();
                        }
                        else {
                            e.addError("illegal annotation argument: must be a literal value, metamodel reference, annotation instantiation, or parameter reference");
                            break;
                        }
                    }
                }
            }
            else {
                e.addError("illegal annotation argument: must be a literal value, metamodel reference, annotation instantiation, or parameter reference");
            }
        }
    }

    @Override
    public void visit(Tree.PackageDescriptor that) {
        super.visit(that);
        Unit unit = that.getUnit();
        checkAnnotations(that.getAnnotationList(),
                unit.getPackageDeclarationType(), null);
    }
   
    @Override
    public void visit(Tree.ModuleDescriptor that) {
        super.visit(that);
        Unit unit = that.getUnit();
        checkAnnotations(that.getAnnotationList(),
                unit.getModuleDeclarationType(), null);
    }
   
    @Override
    public void visit(Tree.ImportModule that) {
        super.visit(that);
        Unit unit = that.getUnit();
        checkAnnotations(that.getAnnotationList(),
                unit.getImportDeclarationType(), null);
    }
   
    @Override
    public void visit(Tree.AnyClass that) {
        super.visit(that);
        Class c = that.getDeclarationModel();
        if (c.isAnnotation()) {
            checkAnnotationType(that, c);
        }
       
        TypeDeclaration dm = that.getDeclarationModel();
        Unit unit = that.getUnit();
        checkAnnotations(that.getAnnotationList(),
                unit.getClassDeclarationType(),
                unit.getClassMetatype(dm.getType()));
    }

    @Override
    public void visit(Tree.AnyInterface that) {
        super.visit(that);
        TypeDeclaration dm = that.getDeclarationModel();
        Unit unit = that.getUnit();
        checkAnnotations(that.getAnnotationList(),
                unit.getInterfaceDeclarationType(),
                unit.getInterfaceMetatype(dm.getType()));
    }
   
    @Override
    public void visit(Tree.AnyAttribute that) {
        super.visit(that);
        TypedDeclaration dm = that.getDeclarationModel();
        Unit unit = that.getUnit();
        checkAnnotations(that.getAnnotationList(),
                unit.getValueDeclarationType(dm),
                unit.getValueMetatype(dm.getTypedReference()));
    }

    @Override
    public void visit(Tree.AnyMethod that) {
        super.visit(that);
        Method a = that.getDeclarationModel();
        if (a.isAnnotation()) {
            checkAnnotationConstructor(that, a);
        }
       
        TypedDeclaration dm = that.getDeclarationModel();
        Unit unit = that.getUnit();
        checkAnnotations(that.getAnnotationList(),
                unit.getFunctionDeclarationType(),
                unit.getFunctionMetatype(dm.getTypedReference()));
    }

    private void checkAnnotationType(Tree.AnyClass that, Class c) {
        if (c.isParameterized()) {
            that.addError("annotation class may not be a parameterized type");
        }
        /*if (c.isAbstract()) {
            that.addError("annotation class may not be abstract");
        }*/
        if (!c.isFinal()) {
            that.addError("annotation class must be final");
        }
        if (c.getExtendedTypeDeclaration() != null
                && !c.getExtendedTypeDeclaration()
                .equals(that.getUnit().getBasicDeclaration())) {
            that.addError("annotation class must directly extend 'Basic'");
        }
        for (Tree.Parameter pn: that.getParameterList().getParameters()) {
            checkAnnotationParameter(c, pn);
        }
        if (that instanceof Tree.ClassDefinition) {
            Tree.ClassBody body = ((Tree.ClassDefinition) that).getClassBody();
            if (body!=null && getExecutableStatements(body).size()>0) {
                that.addError("annotation class body may not contain executable statements");
            }
        }
    }

    private void checkAnnotationConstructor(Tree.AnyMethod that, Method a) {
        Tree.Type type = that.getType();
        if (type!=null) {
            ProducedType t = type.getTypeModel();
            if (t!=null && t.getDeclaration()!=null) {
                if (t.getDeclaration().isAnnotation()) {
                    TypeDeclaration annotationDec = that.getUnit().getAnnotationDeclaration();
                    if (t.getDeclaration() instanceof NothingType) {
                        that.addError("annotation constructor may not return 'Nothing'");
                    }
                    if (!t.getDeclaration().inherits(annotationDec)) {
                        that.addError("annotation constructor must return a subtype of 'Annotation'");
                    }
                    if (!that.getUnit().getPackage().getQualifiedNameString()
                            .equals(LANGUAGE_MODULE_NAME)) {
                        String packageName = t.getDeclaration()
                                .getUnit().getPackage().getQualifiedNameString();
                        String typeName = t.getDeclaration().getName();
                        if (packageName.equals(LANGUAGE_MODULE_NAME) &&
                                (typeName.equals("Shared") ||
                                typeName.equals("Abstract") ||
                                typeName.equals("Default") ||
                                typeName.equals("Formal") ||
                                typeName.equals("Actual") ||
                                typeName.equals("Final") ||
                                typeName.equals("Variable") ||
                                typeName.equals("Late") ||
                                typeName.equals("Native") ||
                                typeName.equals("Deprecated") ||
                                typeName.equals("Annotation"))) {
                            type.addError("annotation constructor may not return modifier annotation type");
                        }
                    }
                }
                else {
                    type.addError("annotation constructor must return an annotation type");
                }
            }
        }
        List<Tree.ParameterList> pls = that.getParameterLists();
        if (pls.size() == 1) {
            for (Tree.Parameter pn: pls.get(0).getParameters()) {
                checkAnnotationParameter(a, pn);
            }
        }
        else {
            that.addError("annotation constructor must have exactly one parameter list");
        }
        if (that instanceof Tree.MethodDefinition) {
            Tree.Block block = ((Tree.MethodDefinition) that).getBlock();
            if (block!=null) {
                List<Tree.Statement> list = getExecutableStatements(block);
                if (list.size()==1) {
                    Tree.Statement s = list.get(0);
                    if (s instanceof Tree.Return) {
                        Tree.Expression e = ((Tree.Return) s).getExpression();
                        checkAnnotationInstantiation(a, e, a.getType());
                    }
                    else {
                        s.addError("annotation constructor body must return an annotation instance");
                    }
                }
                else {
                    block.addError("annotation constructor body must have exactly one statement");
                }
            }
        }
        else {
            Tree.SpecifierExpression se = ((Tree.MethodDeclaration) that).getSpecifierExpression();
            if (se!=null) {
                checkAnnotationInstantiation(a, se.getExpression(), a.getType());
            }
        }
    }
   
    private static List<Tree.Statement> getExecutableStatements(Tree.Body block) {
        List<Tree.Statement> list = new ArrayList<Tree.Statement>();
        for (Tree.Statement s: block.getStatements()) {
            if (Util.isExecutableStatement(block.getUnit(), s)) {
                list.add(s);
            }
        }
        return list;
    }
   
    private void checkAnnotationInstantiation(Functional a, Tree.Expression e, ProducedType pt) {
        if (e!=null) {
            Term term = e.getTerm();
            if (term instanceof Tree.InvocationExpression) {
                Tree.InvocationExpression ie = (Tree.InvocationExpression) term;
                /*if (!ie.getTypeModel().isExactly(pt)) {
                    ie.addError("annotation constructor must return exactly the annotation type");
                }*/
                Tree.Primary primary = ie.getPrimary();
                if (!(primary instanceof Tree.BaseTypeExpression)
                        && (!(primary instanceof Tree.BaseMemberExpression)
                                || !((Tree.BaseMemberExpression)primary).getDeclaration().isAnnotation())) {
                    term.addError("annotation constructor must return a newly-instantiated annotation");
                }
                checkAnnotationArguments(a, ie);
            }
            else {
                term.addError("annotation constructor must return a newly-instantiated annotation");
            }
        }
    }

    private void checkAnnotationArguments(Functional a, Tree.InvocationExpression ie) {
        Tree.PositionalArgumentList pal = ie.getPositionalArgumentList();
        Tree.NamedArgumentList nal = ie.getNamedArgumentList();
        if (pal!=null) {
            checkPositionalArguments(a, pal.getPositionalArguments());
        }
        if (nal!=null) {
            checkNamedArguments(a, nal);
            if (nal.getSequencedArgument()!=null) {
                nal.getSequencedArgument().addError("illegal annotation argument");
//                checkPositionlArgument(a, nal.getSequencedArgument().getPositionalArguments());
            }
        }
    }

    private void checkNamedArguments(Functional a, Tree.NamedArgumentList nal) {
        for (Tree.NamedArgument na: nal.getNamedArguments()) {
            if (na!=null) {
                if (na instanceof Tree.SpecifiedArgument) {
                    Tree.SpecifierExpression se = ((Tree.SpecifiedArgument) na).getSpecifierExpression();
                    if (se!=null && na.getParameter()!=null) {
                        checkAnnotationArgument(a, se.getExpression(),
                                na.getParameter().getType());
                    }
                }
                else {
                    na.addError("illegal annotation argument");
                }
            }
        }
    }

    private void checkPositionalArguments(Functional a, List<Tree.PositionalArgument> pal) {
        for (Tree.PositionalArgument pa: pal) {
            if (pa!=null && pa.getParameter()!=null) {
                if (pa instanceof Tree.ListedArgument) {
                    checkAnnotationArgument(a, ((Tree.ListedArgument) pa).getExpression(),
                            pa.getParameter().getType());
                }
                else if (pa instanceof Tree.SpreadArgument) {
                    checkAnnotationArgument(a, ((Tree.SpreadArgument) pa).getExpression(),
                            pa.getParameter().getType());
                }
                else {
                    pa.addError("illegal annotation argument");
                }
            }
        }
    }
   
    @Override
    public void visit(Tree.DocLink that) {
        super.visit(that);
        String text = that.getText();
       
        int pipeIndex = text.indexOf("|");
        if (pipeIndex != -1) {
            text = text.substring(pipeIndex + 1);
        }
       
        String kind = null;
        if (text.startsWith(DOC_LINK_MODULE)) {
            kind = DOC_LINK_MODULE;
            text = text.substring(DOC_LINK_MODULE.length());
        } else if (text.startsWith(DOC_LINK_PACKAGE)) {
            kind = DOC_LINK_PACKAGE;
            text = text.substring(DOC_LINK_PACKAGE.length());
        } else if (text.startsWith(DOC_LINK_CLASS)) {
            kind = DOC_LINK_CLASS;
            text = text.substring(DOC_LINK_CLASS.length());
        } else if (text.startsWith(DOC_LINK_INTERFACE)) {
            kind = DOC_LINK_INTERFACE;
            text = text.substring(DOC_LINK_INTERFACE.length());
        } else if (text.startsWith(DOC_LINK_FUNCTION)) {
            kind = DOC_LINK_FUNCTION;
            text = text.substring(DOC_LINK_FUNCTION.length());
        } else if (text.startsWith(DOC_LINK_VALUE)) {
            kind = DOC_LINK_VALUE;
            text = text.substring(DOC_LINK_VALUE.length());
        } else if (text.startsWith(DOC_LINK_ALIAS)) {
            kind = DOC_LINK_ALIAS;
            text = text.substring(DOC_LINK_ALIAS.length());
        }
       
        boolean parentheses = false;
        if( text.endsWith("()") ) {
            parentheses = true;
            text = text.substring(0, text.length()-2);
        }
       
        int scopeIndex = text.indexOf("::");
       
        String packageName;
        if (DOC_LINK_MODULE.equals(kind) || DOC_LINK_PACKAGE.equals(kind)) {
            packageName = text;
        } else {
            packageName = scopeIndex < 0 ? null : text.substring(0, scopeIndex);
        }
               
        String path = scopeIndex < 0 ? text : text.substring(scopeIndex + 2);
        String[] names = path.isEmpty() ? new String[0] : path.split("\\.");
        Declaration base = null;
        if (packageName==null) {
            if (names.length > 0) {
                base = that.getScope().getMemberOrParameter(that.getUnit(),
                    names[0], null, false);
            }
        }
        else {
            Package pack = that.getUnit().getPackage().getModule().getPackage(packageName);
            if (pack == null) {
                if (DOC_LINK_MODULE.equals(kind)) {
                    that.addUsageWarning(Warning.doclink,
                                "module does not exist: '" + packageName + "'");
                } else {
                    that.addUsageWarning(Warning.doclink,
                                "package does not exist: '" + packageName + "'");
                }
            }
            else {
                that.setPkg(pack);
                if (DOC_LINK_MODULE.equals(kind)) {
                    Package rootPack = pack.getModule().getRootPackage();
                    if (pack.equals(rootPack)) {
                        that.setModule(pack.getModule());
                    } else {
                        that.addUsageWarning(Warning.doclink,
                                    "module does not exist: '" + packageName + "'");
                    }
                }
                if (names.length > 0) {
                    base = pack.getDirectMember(names[0], null, false);
                }
            }
           
            if (DOC_LINK_MODULE.equals(kind) || DOC_LINK_PACKAGE.equals(kind)) {
                return;
            }
        }
        if (base==null) {
            that.addUsageWarning(Warning.doclink,
                    "declaration does not exist: '" +
                    (names.length > 0 ? names[0] : text) + "'");
        }
        else {
            that.setBase(base);
            if (names.length>1) {
                that.setQualified(new ArrayList<Declaration>(names.length-1));
            }
            for (int i=1; i<names.length; i++) {
                if (base instanceof Value) {
                    Value value = (Value) base;
                    if (!value.isParameter()
                            && !value.isTransient()
                            && value.getTypeDeclaration() != null
                            && value.getTypeDeclaration().isAnonymous()) {
                        base = value.getTypeDeclaration();
                    }
                }
                if (base instanceof TypeDeclaration || base instanceof Functional) {
                    Declaration qualified = base.getMember(names[i], null, false);
                    if (qualified==null) {
                        that.addUsageWarning(Warning.doclink,
                                    "member declaration or parameter does not exist: '" + names[i] + "'");
                        break;
                    }
                    else {
                        that.getQualified().add(qualified);
                        base = qualified;
                    }
                }
                else {
                    that.addUsageWarning(Warning.doclink,
                                "not a type or functional declaration: '" + base.getName() + "'");
                    break;
                }
            }
        }
       
        if( base != null ) {
            if (kind != null && (names.length == 1 || names.length == that.getQualified().size() + 1)) {
                if (DOC_LINK_CLASS.equals(kind) && !(base instanceof Class)) {
                    that.addUsageWarning(Warning.doclink, "linked declaration is not a class: '" + base.getName() + "'");
                } else if (DOC_LINK_INTERFACE.equals(kind) && !(base instanceof Interface)) {
                    that.addUsageWarning(Warning.doclink, "linked declaration is not an interface: '" + base.getName() + "'");
                } else if (DOC_LINK_ALIAS.equals(kind) && !(base instanceof TypeAlias)) {
                    that.addUsageWarning(Warning.doclink, "linked declaration is not a type alias: '" + base.getName() + "'");
                } else if (DOC_LINK_FUNCTION.equals(kind) && !(base instanceof Method)) {
                    that.addUsageWarning(Warning.doclink, "linked declaration is not a function: '" + base.getName() + "'");
                } else if (DOC_LINK_VALUE.equals(kind) && !(base instanceof Value)) {
                    that.addUsageWarning(Warning.doclink, "linked declaration is not a value: '" + base.getName() + "'");
                }
            }
            if( parentheses && !(base instanceof Functional) ) {
                that.addUsageWarning(Warning.doclink, "linked declaration is not a function: '" + base.getName() + "'");
            }
        }

    }

    @Override
    public void visit(Tree.Annotation that) {
        super.visit(that);
        Declaration dec = ((Tree.MemberOrTypeExpression) that.getPrimary()).getDeclaration();
        /*if (dec!=null && !dec.isToplevel()) {
            that.getPrimary().addError("annotation must be a toplevel function reference");
        }*/
        if (dec!=null) {
            if (!dec.isAnnotation()) {
                that.getPrimary().addError("not an annotation constructor");
            }
            else {
                checkAnnotationArguments(null, (Tree.InvocationExpression) that);
            }
        }
    }

    private void checkAnnotations(AnnotationList annotationList,
            ProducedType declarationType, ProducedType metatype) {
        Unit unit = annotationList.getUnit();
        List<Annotation> anns = annotationList.getAnnotations();
        for (Annotation ann: anns) {
            ProducedType t = ann.getTypeModel();
            if (t!=null) {
                ProducedType pet = t.getSupertype(unit.getConstrainedAnnotationDeclaration());
                if (pet!=null && pet.getTypeArgumentList().size()>2) {
                    ProducedType ct = pet.getTypeArgumentList().get(2);
                    ProducedType mt = declarationType; //intersectionType(declarationType,metatype, unit);
                    checkAssignable(mt, ct, ann,
                            "annotated program element does not satisfy annotation constraints");
                }
            }
        }
        for (int i=0; i<anns.size(); i++) {
            ProducedType t = anns.get(i).getTypeModel();
            if (t!=null && t.getDeclaration().inherits(unit.getOptionalAnnotationDeclaration())) {
                for (int j=0; j<i; j++) {
                    ProducedType ot = anns.get(j).getTypeModel();
                    if (ot!=null && ot.getDeclaration().equals(t.getDeclaration())) {
                        anns.get(i).addError("duplicate annotation: there are multiple annotations of type '" +
                                t.getDeclaration().getName() + "'");
                        break;
                    }
                }
            }
        }
    }
   
    //Note: this simply doesn't belong here at all, since it has
    //      nothing at all to do with annotations, but it has
    //      to happen after ExpressionVisitor because overloaded
    //      references are only resolved when we get to the
    //      containing InvocationExpression, and I did not want
    //      to add a whole new Visitor just for overloading errors
    @Override public void visit(Tree.MemberOrTypeExpression that) {
        super.visit(that);
        Declaration dec = that.getDeclaration();
        if (!that.getStaticMethodReferencePrimary() &&
                isAbstraction(dec)) {
            if (that.getStaticMethodReference() && !dec.isStaticallyImportable()) {
                that.addError("ambiguous static reference to overloaded method or class: '" +
                        dec.getName(that.getUnit()) + "' is overloaded");
            }
            else {
                List<ProducedType> sig = that.getSignature();
                if (sig==null) {
                    that.addError("ambiguous callable reference to overloaded method or class: '" +
                            dec.getName(that.getUnit()) + "' is overloaded");
                }
                else {
                    StringBuilder sb = new StringBuilder();
                    sb.append(" '");
                    for (ProducedType pt: sig) {
                        if (pt!=null) {
                            sb.append(pt.getProducedTypeName(that.getUnit()));
                        }
                        sb.append(", ");
                    }
                    if (!sig.isEmpty()) {
                        sb.setLength(sb.length()-2);
                    }
                    sb.append("'");
                    that.addError("ambiguous invocation of overloaded method or class: " +
                            "there must be exactly one overloaded declaration of '" +
                            dec.getName(that.getUnit()) +
                            "' that accepts the given argument types" + sb);
                }
            }
        }
    }
   
}
TOP

Related Classes of com.redhat.ceylon.compiler.typechecker.analyzer.AnnotationVisitor

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.