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 import static com.sun.tools.javac.tree.JCTree.Tag.*; 35 36 /** Enter annotations on symbols. Annotations accumulate in a queue, 37 * which is processed at the top level of any set of recursive calls 38 * requesting it be processed. 39 * 40 * <p><b>This is NOT part of any supported API. 41 * If you write code that depends on this, you do so at your own risk. 42 * This code and its internal interfaces are subject to change or 43 * deletion without notice.</b> 44 */ 45 public class Annotate { 46 protected static final Context.Key<Annotate> annotateKey = 47 new Context.Key<Annotate>(); 48 49 public static Annotate instance(Context context) { 50 Annotate instance = context.get(annotateKey); 51 if (instance == null) 52 instance = new Annotate(context); 53 return instance; 54 } 55 56 final Attr attr; 57 final TreeMaker make; 58 final Log log; 59 final Symtab syms; 60 final Names names; 61 final Resolve rs; 62 final Types types; 63 final ConstFold cfolder; 64 final Check chk; 65 66 protected Annotate(Context context) { 67 context.put(annotateKey, this); 68 attr = Attr.instance(context); 69 make = TreeMaker.instance(context); 70 log = Log.instance(context); 71 syms = Symtab.instance(context); 72 names = Names.instance(context); 73 rs = Resolve.instance(context); 74 types = Types.instance(context); 75 cfolder = ConstFold.instance(context); 76 chk = Check.instance(context); 77 } 78 79 /* ******************************************************************** 80 * Queue maintenance 81 *********************************************************************/ 82 83 private int enterCount = 0; 84 85 ListBuffer<Annotator> q = new ListBuffer<Annotator>(); 86 87 public void later(Annotator a) { 88 q.append(a); 89 } 90 91 public void earlier(Annotator a) { 92 q.prepend(a); 93 } 94 95 /** Called when the Enter phase starts. */ 96 public void enterStart() { 97 enterCount++; 98 } 99 100 /** Called after the Enter phase completes. */ 101 public void enterDone() { 102 enterCount--; 103 flush(); 104 } 105 106 public void flush() { 107 if (enterCount != 0) return; 108 enterCount++; 109 try { 110 while (q.nonEmpty()) 111 q.next().enterAnnotation(); 112 } finally { 113 enterCount--; 114 } 115 } 116 117 /** A client that has annotations to add registers an annotator, 118 * the method it will use to add the annotation. There are no 119 * parameters; any needed data should be captured by the 120 * Annotator. 121 */ 122 public interface Annotator { 123 void enterAnnotation(); 124 String toString(); 125 } 126 127 128 /* ******************************************************************** 129 * Compute an attribute from its annotation. 130 *********************************************************************/ 131 132 /** Process a single compound annotation, returning its 133 * Attribute. Used from MemberEnter for attaching the attributes 134 * to the annotated symbol. 135 */ 136 Attribute.Compound enterAnnotation(JCAnnotation a, 137 Type expected, 138 Env<AttrContext> env) { 139 // The annotation might have had its type attributed (but not checked) 140 // by attr.attribAnnotationTypes during MemberEnter, in which case we do not 141 // need to do it again. 142 Type at = (a.annotationType.type != null ? a.annotationType.type 143 : attr.attribType(a.annotationType, env)); 144 a.type = chk.checkType(a.annotationType.pos(), at, expected); 145 if (a.type.isErroneous()) 146 return new Attribute.Compound(a.type, List.<Pair<MethodSymbol,Attribute>>nil()); 147 if ((a.type.tsym.flags() & Flags.ANNOTATION) == 0) { 148 log.error(a.annotationType.pos(), 149 "not.annotation.type", a.type.toString()); 150 return new Attribute.Compound(a.type, List.<Pair<MethodSymbol,Attribute>>nil()); 151 } 152 List<JCExpression> args = a.args; 153 if (args.length() == 1 && !args.head.hasTag(ASSIGN)) { 154 // special case: elided "value=" assumed 155 args.head = make.at(args.head.pos). 156 Assign(make.Ident(names.value), args.head); 157 } 158 ListBuffer<Pair<MethodSymbol,Attribute>> buf = 159 new ListBuffer<Pair<MethodSymbol,Attribute>>(); 160 for (List<JCExpression> tl = args; tl.nonEmpty(); tl = tl.tail) { 161 JCExpression t = tl.head; 162 if (!t.hasTag(ASSIGN)) { 163 log.error(t.pos(), "annotation.value.must.be.name.value"); 164 continue; 165 } 166 JCAssign assign = (JCAssign)t; 167 if (!assign.lhs.hasTag(IDENT)) { 168 log.error(t.pos(), "annotation.value.must.be.name.value"); 169 continue; 170 } 171 JCIdent left = (JCIdent)assign.lhs; 172 Symbol method = rs.resolveQualifiedMethod(left.pos(), 173 env, 174 a.type, 175 left.name, 176 List.<Type>nil(), 177 null); 178 left.sym = method; 179 left.type = method.type; 180 if (method.owner != a.type.tsym) 181 log.error(left.pos(), "no.annotation.member", left.name, a.type); 182 Type result = method.type.getReturnType(); 183 Attribute value = enterAttributeValue(result, assign.rhs, env); 184 if (!method.type.isErroneous()) 185 buf.append(new Pair<MethodSymbol,Attribute> 186 ((MethodSymbol)method, value)); 187 t.type = result; 188 } 189 return new Attribute.Compound(a.type, buf.toList()); 190 } 191 192 Attribute enterAttributeValue(Type expected, 193 JCExpression tree, 194 Env<AttrContext> env) { 195 //first, try completing the attribution value sym - if a completion 196 //error is thrown, we should recover gracefully, and display an 197 //ordinary resolution diagnostic. 198 try { 199 expected.tsym.complete(); 200 } catch(CompletionFailure e) { 201 log.error(tree.pos(), "cant.resolve", Kinds.kindName(e.sym), e.sym); 202 return new Attribute.Error(expected); 203 } 204 if (expected.isPrimitive() || types.isSameType(expected, syms.stringType)) { 205 Type result = attr.attribExpr(tree, env, expected); 206 if (result.isErroneous()) 207 return new Attribute.Error(expected); 208 if (result.constValue() == null) { 209 log.error(tree.pos(), "attribute.value.must.be.constant"); 210 return new Attribute.Error(expected); 211 } 212 result = cfolder.coerce(result, expected); 213 return new Attribute.Constant(expected, result.constValue()); 214 } 215 if (expected.tsym == syms.classType.tsym) { 216 Type result = attr.attribExpr(tree, env, expected); 217 if (result.isErroneous()) 218 return new Attribute.Error(expected); 219 if (TreeInfo.name(tree) != names._class) { 220 log.error(tree.pos(), "annotation.value.must.be.class.literal"); 221 return new Attribute.Error(expected); 222 } 223 return new Attribute.Class(types, 224 (((JCFieldAccess) tree).selected).type); 225 } 226 if ((expected.tsym.flags() & Flags.ANNOTATION) != 0) { 227 if (!tree.hasTag(ANNOTATION)) { 228 log.error(tree.pos(), "annotation.value.must.be.annotation"); 229 expected = syms.errorType; 230 } 231 return enterAnnotation((JCAnnotation)tree, expected, env); 232 } 233 if (expected.tag == TypeTags.ARRAY) { // should really be isArray() 234 if (!tree.hasTag(NEWARRAY)) { 235 tree = make.at(tree.pos). 236 NewArray(null, List.<JCExpression>nil(), List.of(tree)); 237 } 238 JCNewArray na = (JCNewArray)tree; 239 if (na.elemtype != null) { 240 log.error(na.elemtype.pos(), "new.not.allowed.in.annotation"); 241 return new Attribute.Error(expected); 242 } 243 ListBuffer<Attribute> buf = new ListBuffer<Attribute>(); 244 for (List<JCExpression> l = na.elems; l.nonEmpty(); l=l.tail) { 245 buf.append(enterAttributeValue(types.elemtype(expected), 246 l.head, 247 env)); 248 } 249 na.type = expected; 250 return new Attribute. 251 Array(expected, buf.toArray(new Attribute[buf.length()])); 252 } 253 if (expected.tag == TypeTags.CLASS && 254 (expected.tsym.flags() & Flags.ENUM) != 0) { 255 attr.attribExpr(tree, env, expected); 256 Symbol sym = TreeInfo.symbol(tree); 257 if (sym == null || 258 TreeInfo.nonstaticSelect(tree) || 259 sym.kind != Kinds.VAR || 260 (sym.flags() & Flags.ENUM) == 0) { 261 log.error(tree.pos(), "enum.annotation.must.be.enum.constant"); 262 return new Attribute.Error(expected); 263 } 264 VarSymbol enumerator = (VarSymbol) sym; 265 return new Attribute.Enum(expected, enumerator); 266 } 267 if (!expected.isErroneous()) 268 log.error(tree.pos(), "annotation.value.not.allowable.type"); 269 return new Attribute.Error(attr.attribExpr(tree, env, expected)); 270 } 271 }