Thu, 02 Aug 2012 18:23:21 +0100
7175538: Integrate efectively final check with DA/DU analysis
Summary: Allow generalized effectively-final analysis for all local variables
Reviewed-by: jjg, dlsmith
1 /*
2 * Copyright (c) 2003, 2011, 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 */
26 package com.sun.tools.javac.comp;
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.*;
34 import static com.sun.tools.javac.tree.JCTree.Tag.*;
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>();
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 }
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;
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 }
79 /* ********************************************************************
80 * Queue maintenance
81 *********************************************************************/
83 private int enterCount = 0;
85 ListBuffer<Annotator> q = new ListBuffer<Annotator>();
87 public void later(Annotator a) {
88 q.append(a);
89 }
91 public void earlier(Annotator a) {
92 q.prepend(a);
93 }
95 /** Called when the Enter phase starts. */
96 public void enterStart() {
97 enterCount++;
98 }
100 /** Called after the Enter phase completes. */
101 public void enterDone() {
102 enterCount--;
103 flush();
104 }
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 }
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 }
128 /* ********************************************************************
129 * Compute an attribute from its annotation.
130 *********************************************************************/
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 }
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 }