langtools/src/share/classes/com/sun/tools/javac/comp/Annotate.java
changeset 10 06bc494ca11e
child 1260 a772ba9ba43d
equal deleted inserted replaced
0:fd16c54261b3 10:06bc494ca11e
       
     1 /*
       
     2  * Copyright 2003-2006 Sun Microsystems, Inc.  All Rights Reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.  Sun designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Sun in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
       
    22  * CA 95054 USA or visit www.sun.com if you need additional information or
       
    23  * have any questions.
       
    24  */
       
    25 
       
    26 package com.sun.tools.javac.comp;
       
    27 
       
    28 import com.sun.tools.javac.util.*;
       
    29 import com.sun.tools.javac.code.*;
       
    30 import com.sun.tools.javac.code.Symbol.*;
       
    31 import com.sun.tools.javac.tree.*;
       
    32 import com.sun.tools.javac.tree.JCTree.*;
       
    33 
       
    34 /** Enter annotations on symbols.  Annotations accumulate in a queue,
       
    35  *  which is processed at the top level of any set of recursive calls
       
    36  *  requesting it be processed.
       
    37  *
       
    38  *  <p><b>This is NOT part of any API supported by Sun Microsystems.  If
       
    39  *  you write code that depends on this, you do so at your own risk.
       
    40  *  This code and its internal interfaces are subject to change or
       
    41  *  deletion without notice.</b>
       
    42  */
       
    43 public class Annotate {
       
    44     protected static final Context.Key<Annotate> annotateKey =
       
    45         new Context.Key<Annotate>();
       
    46 
       
    47     public static Annotate instance(Context context) {
       
    48         Annotate instance = context.get(annotateKey);
       
    49         if (instance == null)
       
    50             instance = new Annotate(context);
       
    51         return instance;
       
    52     }
       
    53 
       
    54     final Attr attr;
       
    55     final TreeMaker make;
       
    56     final Log log;
       
    57     final Symtab syms;
       
    58     final Name.Table names;
       
    59     final Resolve rs;
       
    60     final Types types;
       
    61     final ConstFold cfolder;
       
    62     final Check chk;
       
    63 
       
    64     protected Annotate(Context context) {
       
    65         context.put(annotateKey, this);
       
    66         attr = Attr.instance(context);
       
    67         make = TreeMaker.instance(context);
       
    68         log = Log.instance(context);
       
    69         syms = Symtab.instance(context);
       
    70         names = Name.Table.instance(context);
       
    71         rs = Resolve.instance(context);
       
    72         types = Types.instance(context);
       
    73         cfolder = ConstFold.instance(context);
       
    74         chk = Check.instance(context);
       
    75     }
       
    76 
       
    77 /* ********************************************************************
       
    78  * Queue maintenance
       
    79  *********************************************************************/
       
    80 
       
    81     private int enterCount = 0;
       
    82 
       
    83     ListBuffer<Annotator> q = new ListBuffer<Annotator>();
       
    84 
       
    85     public void later(Annotator a) {
       
    86         q.append(a);
       
    87     }
       
    88 
       
    89     public void earlier(Annotator a) {
       
    90         q.prepend(a);
       
    91     }
       
    92 
       
    93     /** Called when the Enter phase starts. */
       
    94     public void enterStart() {
       
    95         enterCount++;
       
    96     }
       
    97 
       
    98     /** Called after the Enter phase completes. */
       
    99     public void enterDone() {
       
   100         enterCount--;
       
   101         flush();
       
   102     }
       
   103 
       
   104     public void flush() {
       
   105         if (enterCount != 0) return;
       
   106         enterCount++;
       
   107         try {
       
   108             while (q.nonEmpty())
       
   109                 q.next().enterAnnotation();
       
   110         } finally {
       
   111             enterCount--;
       
   112         }
       
   113     }
       
   114 
       
   115     /** A client that has annotations to add registers an annotator,
       
   116      *  the method it will use to add the annotation.  There are no
       
   117      *  parameters; any needed data should be captured by the
       
   118      *  Annotator.
       
   119      */
       
   120     public interface Annotator {
       
   121         void enterAnnotation();
       
   122         String toString();
       
   123     }
       
   124 
       
   125 
       
   126 /* ********************************************************************
       
   127  * Compute an attribute from its annotation.
       
   128  *********************************************************************/
       
   129 
       
   130     /** Process a single compound annotation, returning its
       
   131      *  Attribute. Used from MemberEnter for attaching the attributes
       
   132      *  to the annotated symbol.
       
   133      */
       
   134     Attribute.Compound enterAnnotation(JCAnnotation a,
       
   135                                        Type expected,
       
   136                                        Env<AttrContext> env) {
       
   137         // The annotation might have had its type attributed (but not checked)
       
   138         // by attr.attribAnnotationTypes during MemberEnter, in which case we do not
       
   139         // need to do it again.
       
   140         Type at = (a.annotationType.type != null ? a.annotationType.type
       
   141                   : attr.attribType(a.annotationType, env));
       
   142         a.type = chk.checkType(a.annotationType.pos(), at, expected);
       
   143         if (a.type.isErroneous())
       
   144             return new Attribute.Compound(a.type, List.<Pair<MethodSymbol,Attribute>>nil());
       
   145         if ((a.type.tsym.flags() & Flags.ANNOTATION) == 0) {
       
   146             log.error(a.annotationType.pos(),
       
   147                       "not.annotation.type", a.type.toString());
       
   148             return new Attribute.Compound(a.type, List.<Pair<MethodSymbol,Attribute>>nil());
       
   149         }
       
   150         List<JCExpression> args = a.args;
       
   151         if (args.length() == 1 && args.head.getTag() != JCTree.ASSIGN) {
       
   152             // special case: elided "value=" assumed
       
   153             args.head = make.at(args.head.pos).
       
   154                 Assign(make.Ident(names.value), args.head);
       
   155         }
       
   156         ListBuffer<Pair<MethodSymbol,Attribute>> buf =
       
   157             new ListBuffer<Pair<MethodSymbol,Attribute>>();
       
   158         for (List<JCExpression> tl = args; tl.nonEmpty(); tl = tl.tail) {
       
   159             JCExpression t = tl.head;
       
   160             if (t.getTag() != JCTree.ASSIGN) {
       
   161                 log.error(t.pos(), "annotation.value.must.be.name.value");
       
   162                 continue;
       
   163             }
       
   164             JCAssign assign = (JCAssign)t;
       
   165             if (assign.lhs.getTag() != JCTree.IDENT) {
       
   166                 log.error(t.pos(), "annotation.value.must.be.name.value");
       
   167                 continue;
       
   168             }
       
   169             JCIdent left = (JCIdent)assign.lhs;
       
   170             Symbol method = rs.resolveQualifiedMethod(left.pos(),
       
   171                                                       env,
       
   172                                                       a.type,
       
   173                                                       left.name,
       
   174                                                       List.<Type>nil(),
       
   175                                                       null);
       
   176             left.sym = method;
       
   177             left.type = method.type;
       
   178             if (method.owner != a.type.tsym)
       
   179                 log.error(left.pos(), "no.annotation.member", left.name, a.type);
       
   180             Type result = method.type.getReturnType();
       
   181             Attribute value = enterAttributeValue(result, assign.rhs, env);
       
   182             if (!method.type.isErroneous())
       
   183                 buf.append(new Pair<MethodSymbol,Attribute>
       
   184                            ((MethodSymbol)method, value));
       
   185         }
       
   186         return new Attribute.Compound(a.type, buf.toList());
       
   187     }
       
   188 
       
   189     Attribute enterAttributeValue(Type expected,
       
   190                                   JCExpression tree,
       
   191                                   Env<AttrContext> env) {
       
   192         if (expected.isPrimitive() || types.isSameType(expected, syms.stringType)) {
       
   193             Type result = attr.attribExpr(tree, env, expected);
       
   194             if (result.isErroneous())
       
   195                 return new Attribute.Error(expected);
       
   196             if (result.constValue() == null) {
       
   197                 log.error(tree.pos(), "attribute.value.must.be.constant");
       
   198                 return new Attribute.Error(expected);
       
   199             }
       
   200             result = cfolder.coerce(result, expected);
       
   201             return new Attribute.Constant(expected, result.constValue());
       
   202         }
       
   203         if (expected.tsym == syms.classType.tsym) {
       
   204             Type result = attr.attribExpr(tree, env, expected);
       
   205             if (result.isErroneous())
       
   206                 return new Attribute.Error(expected);
       
   207             if (TreeInfo.name(tree) != names._class) {
       
   208                 log.error(tree.pos(), "annotation.value.must.be.class.literal");
       
   209                 return new Attribute.Error(expected);
       
   210             }
       
   211             return new Attribute.Class(types,
       
   212                                        (((JCFieldAccess) tree).selected).type);
       
   213         }
       
   214         if ((expected.tsym.flags() & Flags.ANNOTATION) != 0) {
       
   215             if (tree.getTag() != JCTree.ANNOTATION) {
       
   216                 log.error(tree.pos(), "annotation.value.must.be.annotation");
       
   217                 expected = syms.errorType;
       
   218             }
       
   219             return enterAnnotation((JCAnnotation)tree, expected, env);
       
   220         }
       
   221         if (expected.tag == TypeTags.ARRAY) { // should really be isArray()
       
   222             if (tree.getTag() != JCTree.NEWARRAY) {
       
   223                 tree = make.at(tree.pos).
       
   224                     NewArray(null, List.<JCExpression>nil(), List.of(tree));
       
   225             }
       
   226             JCNewArray na = (JCNewArray)tree;
       
   227             if (na.elemtype != null) {
       
   228                 log.error(na.elemtype.pos(), "new.not.allowed.in.annotation");
       
   229                 return new Attribute.Error(expected);
       
   230             }
       
   231             ListBuffer<Attribute> buf = new ListBuffer<Attribute>();
       
   232             for (List<JCExpression> l = na.elems; l.nonEmpty(); l=l.tail) {
       
   233                 buf.append(enterAttributeValue(types.elemtype(expected),
       
   234                                                l.head,
       
   235                                                env));
       
   236             }
       
   237             return new Attribute.
       
   238                 Array(expected, buf.toArray(new Attribute[buf.length()]));
       
   239         }
       
   240         if (expected.tag == TypeTags.CLASS &&
       
   241             (expected.tsym.flags() & Flags.ENUM) != 0) {
       
   242             attr.attribExpr(tree, env, expected);
       
   243             Symbol sym = TreeInfo.symbol(tree);
       
   244             if (sym == null ||
       
   245                 TreeInfo.nonstaticSelect(tree) ||
       
   246                 sym.kind != Kinds.VAR ||
       
   247                 (sym.flags() & Flags.ENUM) == 0) {
       
   248                 log.error(tree.pos(), "enum.annotation.must.be.enum.constant");
       
   249                 return new Attribute.Error(expected);
       
   250             }
       
   251             VarSymbol enumerator = (VarSymbol) sym;
       
   252             return new Attribute.Enum(expected, enumerator);
       
   253         }
       
   254         if (!expected.isErroneous())
       
   255             log.error(tree.pos(), "annotation.value.not.allowable.type");
       
   256         return new Attribute.Error(attr.attribExpr(tree, env, expected));
       
   257     }
       
   258 }