Home » openjdk-7 » com.sun.tools » javac » comp » [javadoc | source]

    1   /*
    2    * Copyright (c) 2003, 2010, Oracle and/or its affiliates. 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.  Oracle designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   22    * or visit www.oracle.com if you need additional information or have any
   23    * 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 supported API.
   39    *  If 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 Names 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 = Names.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               t.type = result;
  186           }
  187           return new Attribute.Compound(a.type, buf.toList());
  188       }
  189   
  190       Attribute enterAttributeValue(Type expected,
  191                                     JCExpression tree,
  192                                     Env<AttrContext> env) {
  193           //first, try completing the attribution value sym - if a completion
  194           //error is thrown, we should recover gracefully, and display an
  195           //ordinary resolution diagnostic.
  196           try {
  197               expected.tsym.complete();
  198           } catch(CompletionFailure e) {
  199               log.error(tree.pos(), "cant.resolve", Kinds.kindName(e.sym), e.sym);
  200               return new Attribute.Error(expected);
  201           }
  202           if (expected.isPrimitive() || types.isSameType(expected, syms.stringType)) {
  203               Type result = attr.attribExpr(tree, env, expected);
  204               if (result.isErroneous())
  205                   return new Attribute.Error(expected);
  206               if (result.constValue() == null) {
  207                   log.error(tree.pos(), "attribute.value.must.be.constant");
  208                   return new Attribute.Error(expected);
  209               }
  210               result = cfolder.coerce(result, expected);
  211               return new Attribute.Constant(expected, result.constValue());
  212           }
  213           if (expected.tsym == syms.classType.tsym) {
  214               Type result = attr.attribExpr(tree, env, expected);
  215               if (result.isErroneous())
  216                   return new Attribute.Error(expected);
  217               if (TreeInfo.name(tree) != names._class) {
  218                   log.error(tree.pos(), "annotation.value.must.be.class.literal");
  219                   return new Attribute.Error(expected);
  220               }
  221               return new Attribute.Class(types,
  222                                          (((JCFieldAccess) tree).selected).type);
  223           }
  224           if ((expected.tsym.flags() & Flags.ANNOTATION) != 0) {
  225               if (tree.getTag() != JCTree.ANNOTATION) {
  226                   log.error(tree.pos(), "annotation.value.must.be.annotation");
  227                   expected = syms.errorType;
  228               }
  229               return enterAnnotation((JCAnnotation)tree, expected, env);
  230           }
  231           if (expected.tag == TypeTags.ARRAY) { // should really be isArray()
  232               if (tree.getTag() != JCTree.NEWARRAY) {
  233                   tree = make.at(tree.pos).
  234                       NewArray(null, List.<JCExpression>nil(), List.of(tree));
  235               }
  236               JCNewArray na = (JCNewArray)tree;
  237               if (na.elemtype != null) {
  238                   log.error(na.elemtype.pos(), "new.not.allowed.in.annotation");
  239                   return new Attribute.Error(expected);
  240               }
  241               ListBuffer<Attribute> buf = new ListBuffer<Attribute>();
  242               for (List<JCExpression> l = na.elems; l.nonEmpty(); l=l.tail) {
  243                   buf.append(enterAttributeValue(types.elemtype(expected),
  244                                                  l.head,
  245                                                  env));
  246               }
  247               na.type = expected;
  248               return new Attribute.
  249                   Array(expected, buf.toArray(new Attribute[buf.length()]));
  250           }
  251           if (expected.tag == TypeTags.CLASS &&
  252               (expected.tsym.flags() & Flags.ENUM) != 0) {
  253               attr.attribExpr(tree, env, expected);
  254               Symbol sym = TreeInfo.symbol(tree);
  255               if (sym == null ||
  256                   TreeInfo.nonstaticSelect(tree) ||
  257                   sym.kind != Kinds.VAR ||
  258                   (sym.flags() & Flags.ENUM) == 0) {
  259                   log.error(tree.pos(), "enum.annotation.must.be.enum.constant");
  260                   return new Attribute.Error(expected);
  261               }
  262               VarSymbol enumerator = (VarSymbol) sym;
  263               return new Attribute.Enum(expected, enumerator);
  264           }
  265           if (!expected.isErroneous())
  266               log.error(tree.pos(), "annotation.value.not.allowable.type");
  267           return new Attribute.Error(attr.attribExpr(tree, env, expected));
  268       }
  269   }

Home » openjdk-7 » com.sun.tools » javac » comp » [javadoc | source]