001: /*
002: * Copyright 2003-2006 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package com.sun.tools.javac.comp;
027:
028: import com.sun.tools.javac.util.*;
029: import com.sun.tools.javac.code.*;
030: import com.sun.tools.javac.code.Symbol.*;
031: import com.sun.tools.javac.tree.*;
032: import com.sun.tools.javac.tree.JCTree.*;
033:
034: /** Enter annotations on symbols. Annotations accumulate in a queue,
035: * which is processed at the top level of any set of recursive calls
036: * requesting it be processed.
037: *
038: * <p><b>This is NOT part of any API supported by Sun Microsystems. If
039: * you write code that depends on this, you do so at your own risk.
040: * This code and its internal interfaces are subject to change or
041: * deletion without notice.</b>
042: */
043: @Version("@(#)Annotate.java 1.44 07/06/14")
044: public class Annotate {
045: protected static final Context.Key<Annotate> annotateKey = new Context.Key<Annotate>();
046:
047: public static Annotate instance(Context context) {
048: Annotate instance = context.get(annotateKey);
049: if (instance == null)
050: instance = new Annotate(context);
051: return instance;
052: }
053:
054: final Attr attr;
055: final TreeMaker make;
056: final Log log;
057: final Symtab syms;
058: final Name.Table names;
059: final Resolve rs;
060: final Types types;
061: final ConstFold cfolder;
062: final Check chk;
063:
064: protected Annotate(Context context) {
065: context.put(annotateKey, this );
066: attr = Attr.instance(context);
067: make = TreeMaker.instance(context);
068: log = Log.instance(context);
069: syms = Symtab.instance(context);
070: names = Name.Table.instance(context);
071: rs = Resolve.instance(context);
072: types = Types.instance(context);
073: cfolder = ConstFold.instance(context);
074: chk = Check.instance(context);
075: }
076:
077: /* ********************************************************************
078: * Queue maintenance
079: *********************************************************************/
080:
081: private int enterCount = 0;
082:
083: ListBuffer<Annotator> q = new ListBuffer<Annotator>();
084:
085: public void later(Annotator a) {
086: q.append(a);
087: }
088:
089: public void earlier(Annotator a) {
090: q.prepend(a);
091: }
092:
093: /** Called when the Enter phase starts. */
094: public void enterStart() {
095: enterCount++;
096: }
097:
098: /** Called after the Enter phase completes. */
099: public void enterDone() {
100: enterCount--;
101: flush();
102: }
103:
104: public void flush() {
105: if (enterCount != 0)
106: return;
107: enterCount++;
108: try {
109: while (q.nonEmpty())
110: q.next().enterAnnotation();
111: } finally {
112: enterCount--;
113: }
114: }
115:
116: /** A client that has annotations to add registers an annotator,
117: * the method it will use to add the annotation. There are no
118: * parameters; any needed data should be captured by the
119: * Annotator.
120: */
121: public interface Annotator {
122: void enterAnnotation();
123:
124: String toString();
125: }
126:
127: /* ********************************************************************
128: * Compute an attribute from its annotation.
129: *********************************************************************/
130:
131: /** Process a single compound annotation, returning its
132: * Attribute. Used from MemberEnter for attaching the attributes
133: * to the annotated symbol.
134: */
135: Attribute.Compound enterAnnotation(JCAnnotation a, 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
145: .<Pair<MethodSymbol, Attribute>> nil());
146: if ((a.type.tsym.flags() & Flags.ANNOTATION) == 0) {
147: log.error(a.annotationType.pos(), "not.annotation.type",
148: a.type.toString());
149: return new Attribute.Compound(a.type, List
150: .<Pair<MethodSymbol, Attribute>> nil());
151: }
152: List<JCExpression> args = a.args;
153: if (args.length() == 1 && args.head.getTag() != JCTree.ASSIGN) {
154: // special case: elided "value=" assumed
155: args.head = make.at(args.head.pos).Assign(
156: make.Ident(names.value), args.head);
157: }
158: ListBuffer<Pair<MethodSymbol, Attribute>> buf = new ListBuffer<Pair<MethodSymbol, Attribute>>();
159: for (List<JCExpression> tl = args; tl.nonEmpty(); tl = tl.tail) {
160: JCExpression t = tl.head;
161: if (t.getTag() != JCTree.ASSIGN) {
162: log.error(t.pos(),
163: "annotation.value.must.be.name.value");
164: continue;
165: }
166: JCAssign assign = (JCAssign) t;
167: if (assign.lhs.getTag() != JCTree.IDENT) {
168: log.error(t.pos(),
169: "annotation.value.must.be.name.value");
170: continue;
171: }
172: JCIdent left = (JCIdent) assign.lhs;
173: Symbol method = rs.resolveQualifiedMethod(left.pos(), env,
174: a.type, left.name, List.<Type> nil(), null);
175: left.sym = method;
176: left.type = method.type;
177: if (method.owner != a.type.tsym)
178: log.error(left.pos(), "no.annotation.member",
179: left.name, a.type);
180: Type result = method.type.getReturnType();
181: Attribute value = enterAttributeValue(result, assign.rhs,
182: env);
183: if (!method.type.isErroneous())
184: buf.append(new Pair<MethodSymbol, Attribute>(
185: (MethodSymbol) method, value));
186: }
187: return new Attribute.Compound(a.type, buf.toList());
188: }
189:
190: Attribute enterAttributeValue(Type expected, JCExpression tree,
191: Env<AttrContext> env) {
192: if (expected.isPrimitive()
193: || types.isSameType(expected, syms.stringType)) {
194: Type result = attr.attribExpr(tree, env, expected);
195: if (result.isErroneous())
196: return new Attribute.Error(expected);
197: if (result.constValue() == null) {
198: log.error(tree.pos(),
199: "attribute.value.must.be.constant");
200: return new Attribute.Error(expected);
201: }
202: result = cfolder.coerce(result, expected);
203: return new Attribute.Constant(expected, result.constValue());
204: }
205: if (expected.tsym == syms.classType.tsym) {
206: Type result = attr.attribExpr(tree, env, expected);
207: if (result.isErroneous())
208: return new Attribute.Error(expected);
209: if (TreeInfo.name(tree) != names._class) {
210: log.error(tree.pos(),
211: "annotation.value.must.be.class.literal");
212: return new Attribute.Error(expected);
213: }
214: return new Attribute.Class(types,
215: (((JCFieldAccess) tree).selected).type);
216: }
217: if ((expected.tsym.flags() & Flags.ANNOTATION) != 0) {
218: if (tree.getTag() != JCTree.ANNOTATION) {
219: log.error(tree.pos(),
220: "annotation.value.must.be.annotation");
221: expected = syms.errorType;
222: }
223: return enterAnnotation((JCAnnotation) tree, expected, env);
224: }
225: if (expected.tag == TypeTags.ARRAY) { // should really be isArray()
226: if (tree.getTag() != JCTree.NEWARRAY) {
227: tree = make.at(tree.pos).NewArray(null,
228: List.<JCExpression> nil(), List.of(tree));
229: }
230: JCNewArray na = (JCNewArray) tree;
231: if (na.elemtype != null) {
232: log.error(na.elemtype.pos(),
233: "new.not.allowed.in.annotation");
234: return new Attribute.Error(expected);
235: }
236: ListBuffer<Attribute> buf = new ListBuffer<Attribute>();
237: for (List<JCExpression> l = na.elems; l.nonEmpty(); l = l.tail) {
238: buf.append(enterAttributeValue(
239: types.elemtype(expected), l.head, env));
240: }
241: return new Attribute.Array(expected, buf
242: .toArray(new Attribute[buf.length()]));
243: }
244: if (expected.tag == TypeTags.CLASS
245: && (expected.tsym.flags() & Flags.ENUM) != 0) {
246: attr.attribExpr(tree, env, expected);
247: Symbol sym = TreeInfo.symbol(tree);
248: if (sym == null || TreeInfo.nonstaticSelect(tree)
249: || sym.kind != Kinds.VAR
250: || (sym.flags() & Flags.ENUM) == 0) {
251: log.error(tree.pos(),
252: "enum.annotation.must.be.enum.constant");
253: return new Attribute.Error(expected);
254: }
255: VarSymbol enumerator = (VarSymbol) sym;
256: return new Attribute.Enum(expected, enumerator);
257: }
258: if (!expected.isErroneous())
259: log
260: .error(tree.pos(),
261: "annotation.value.not.allowable.type");
262: return new Attribute.Error(attr.attribExpr(tree, env, expected));
263: }
264: }
|