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.Tag.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.Tag.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.Tag.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.Tag.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.Tag.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 }