Thu, 30 Sep 2010 10:47:12 -0700
6988436: Cleanup javac option handling
Reviewed-by: darcy
1 /*
2 * Copyright (c) 2009, 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.code;
28 import javax.lang.model.element.ElementKind;
30 import com.sun.tools.javac.code.Symbol.VarSymbol;
31 import com.sun.tools.javac.tree.JCTree;
32 import com.sun.tools.javac.tree.TreeInfo;
33 import com.sun.tools.javac.tree.TreeScanner;
34 import com.sun.tools.javac.tree.JCTree.*;
35 import com.sun.tools.javac.util.Context;
36 import com.sun.tools.javac.util.List;
37 import com.sun.tools.javac.util.ListBuffer;
39 /**
40 * Contains operations specific to processing type annotations
41 */
42 public class TypeAnnotations {
43 private static final Context.Key<TypeAnnotations> key
44 = new Context.Key<TypeAnnotations>();
46 public static TypeAnnotations instance(Context context) {
47 TypeAnnotations instance = context.get(key);
48 if (instance == null)
49 instance = new TypeAnnotations(context);
50 return instance;
51 }
53 protected TypeAnnotations(Context context) {
54 context.put(key, this);
55 }
57 public void taFillAndLift(JCClassDecl tree, boolean visitBodies) {
58 new TypeAnnotationPositions().scan(tree);
59 new TypeAnnotationLift().scan(tree);
60 }
62 private static class TypeAnnotationPositions extends TreeScanner {
64 private ListBuffer<JCTree> frames = ListBuffer.lb();
65 private void push(JCTree t) { frames = frames.prepend(t); }
66 private JCTree pop() { return frames.next(); }
67 private JCTree peek2() { return frames.toList().tail.head; }
69 @Override
70 public void scan(JCTree tree) {
71 push(tree);
72 super.scan(tree);
73 pop();
74 }
76 private boolean inClass = false;
78 @Override
79 public void visitClassDef(JCClassDecl tree) {
80 if (!inClass) {
81 // Do not recurse into nested and inner classes since
82 // TransTypes.visitClassDef makes an invocation for each class
83 // separately.
84 inClass = true;
85 try {
86 super.visitClassDef(tree);
87 } finally {
88 inClass = false;
89 }
90 }
91 }
93 private TypeAnnotationPosition resolveFrame(JCTree tree, JCTree frame,
94 List<JCTree> path, TypeAnnotationPosition p) {
95 switch (frame.getKind()) {
96 case TYPE_CAST:
97 p.type = TargetType.TYPECAST;
98 p.pos = frame.pos;
99 return p;
101 case INSTANCE_OF:
102 p.type = TargetType.INSTANCEOF;
103 p.pos = frame.pos;
104 return p;
106 case NEW_CLASS:
107 p.type = TargetType.NEW;
108 p.pos = frame.pos;
109 return p;
111 case NEW_ARRAY:
112 p.type = TargetType.NEW;
113 p.pos = frame.pos;
114 return p;
116 case CLASS:
117 case INTERFACE:
118 case ENUM:
119 p.pos = frame.pos;
120 if (((JCClassDecl)frame).extending == tree) {
121 p.type = TargetType.CLASS_EXTENDS;
122 p.type_index = -1;
123 } else if (((JCClassDecl)frame).implementing.contains(tree)) {
124 p.type = TargetType.CLASS_EXTENDS;
125 p.type_index = ((JCClassDecl)frame).implementing.indexOf(tree);
126 } else if (((JCClassDecl)frame).typarams.contains(tree)) {
127 p.type = TargetType.CLASS_TYPE_PARAMETER;
128 p.parameter_index = ((JCClassDecl)frame).typarams.indexOf(tree);
129 } else
130 throw new AssertionError();
131 return p;
133 case METHOD: {
134 JCMethodDecl frameMethod = (JCMethodDecl)frame;
135 p.pos = frame.pos;
136 if (frameMethod.receiverAnnotations.contains(tree))
137 p.type = TargetType.METHOD_RECEIVER;
138 else if (frameMethod.thrown.contains(tree)) {
139 p.type = TargetType.THROWS;
140 p.type_index = frameMethod.thrown.indexOf(tree);
141 } else if (((JCMethodDecl)frame).restype == tree) {
142 p.type = TargetType.METHOD_RETURN_GENERIC_OR_ARRAY;
143 } else if (frameMethod.typarams.contains(tree)) {
144 p.type = TargetType.METHOD_TYPE_PARAMETER;
145 p.parameter_index = frameMethod.typarams.indexOf(tree);
146 } else
147 throw new AssertionError();
148 return p;
149 }
150 case MEMBER_SELECT: {
151 JCFieldAccess fieldFrame = (JCFieldAccess)frame;
152 if ("class".contentEquals(fieldFrame.name)) {
153 p.type = TargetType.CLASS_LITERAL;
154 p.pos = TreeInfo.innermostType(fieldFrame.selected).pos;
155 } else
156 throw new AssertionError();
157 return p;
158 }
159 case PARAMETERIZED_TYPE: {
160 TypeAnnotationPosition nextP;
161 if (((JCTypeApply)frame).clazz == tree)
162 nextP = p; // generic: RAW; noop
163 else if (((JCTypeApply)frame).arguments.contains(tree))
164 p.location = p.location.prepend(
165 ((JCTypeApply)frame).arguments.indexOf(tree));
166 else
167 throw new AssertionError();
169 List<JCTree> newPath = path.tail;
170 return resolveFrame(newPath.head, newPath.tail.head, newPath, p);
171 }
173 case ARRAY_TYPE: {
174 p.location = p.location.prepend(0);
175 List<JCTree> newPath = path.tail;
176 return resolveFrame(newPath.head, newPath.tail.head, newPath, p);
177 }
179 case TYPE_PARAMETER:
180 if (path.tail.tail.head.getTag() == JCTree.CLASSDEF) {
181 JCClassDecl clazz = (JCClassDecl)path.tail.tail.head;
182 p.type = TargetType.CLASS_TYPE_PARAMETER_BOUND;
183 p.parameter_index = clazz.typarams.indexOf(path.tail.head);
184 p.bound_index = ((JCTypeParameter)frame).bounds.indexOf(tree);
185 } else if (path.tail.tail.head.getTag() == JCTree.METHODDEF) {
186 JCMethodDecl method = (JCMethodDecl)path.tail.tail.head;
187 p.type = TargetType.METHOD_TYPE_PARAMETER_BOUND;
188 p.parameter_index = method.typarams.indexOf(path.tail.head);
189 p.bound_index = ((JCTypeParameter)frame).bounds.indexOf(tree);
190 } else
191 throw new AssertionError();
192 p.pos = frame.pos;
193 return p;
195 case VARIABLE:
196 VarSymbol v = ((JCVariableDecl)frame).sym;
197 p.pos = frame.pos;
198 switch (v.getKind()) {
199 case LOCAL_VARIABLE:
200 p.type = TargetType.LOCAL_VARIABLE; break;
201 case FIELD:
202 p.type = TargetType.FIELD_GENERIC_OR_ARRAY; break;
203 case PARAMETER:
204 p.type = TargetType.METHOD_PARAMETER_GENERIC_OR_ARRAY;
205 p.parameter_index = methodParamIndex(path, frame);
206 break;
207 default: throw new AssertionError();
208 }
209 return p;
211 case ANNOTATED_TYPE: {
212 List<JCTree> newPath = path.tail;
213 return resolveFrame(newPath.head, newPath.tail.head,
214 newPath, p);
215 }
217 case METHOD_INVOCATION: {
218 JCMethodInvocation invocation = (JCMethodInvocation)frame;
219 if (!invocation.typeargs.contains(tree))
220 throw new AssertionError("{" + tree + "} is not an argument in the invocation: " + invocation);
221 p.type = TargetType.METHOD_TYPE_ARGUMENT;
222 p.pos = invocation.pos;
223 p.type_index = invocation.typeargs.indexOf(tree);
224 return p;
225 }
227 case EXTENDS_WILDCARD:
228 case SUPER_WILDCARD: {
229 p.type = TargetType.WILDCARD_BOUND;
230 List<JCTree> newPath = path.tail;
232 TypeAnnotationPosition wildcard =
233 resolveFrame(newPath.head, newPath.tail.head, newPath,
234 new TypeAnnotationPosition());
235 if (!wildcard.location.isEmpty())
236 wildcard.type = wildcard.type.getGenericComplement();
237 p.wildcard_position = wildcard;
238 p.pos = frame.pos;
239 return p;
240 }
241 }
242 return p;
243 }
245 private void setTypeAnnotationPos(List<JCTypeAnnotation> annotations, TypeAnnotationPosition position) {
246 for (JCTypeAnnotation anno : annotations) {
247 anno.annotation_position = position;
248 anno.attribute_field.position = position;
249 }
250 }
252 @Override
253 public void visitNewArray(JCNewArray tree) {
254 findPosition(tree, tree, tree.annotations);
255 int dimAnnosCount = tree.dimAnnotations.size();
257 // handle annotations associated with dimentions
258 for (int i = 0; i < dimAnnosCount; ++i) {
259 TypeAnnotationPosition p = new TypeAnnotationPosition();
260 p.type = TargetType.NEW_GENERIC_OR_ARRAY;
261 p.pos = tree.pos;
262 p.location = p.location.append(i);
263 setTypeAnnotationPos(tree.dimAnnotations.get(i), p);
264 }
266 // handle "free" annotations
267 int i = dimAnnosCount == 0 ? 0 : dimAnnosCount - 1;
268 JCExpression elemType = tree.elemtype;
269 while (elemType != null) {
270 if (elemType.getTag() == JCTree.ANNOTATED_TYPE) {
271 JCAnnotatedType at = (JCAnnotatedType)elemType;
272 TypeAnnotationPosition p = new TypeAnnotationPosition();
273 p.type = TargetType.NEW_GENERIC_OR_ARRAY;
274 p.pos = tree.pos;
275 p.location = p.location.append(i);
276 setTypeAnnotationPos(at.annotations, p);
277 elemType = at.underlyingType;
278 } else if (elemType.getTag() == JCTree.TYPEARRAY) {
279 ++i;
280 elemType = ((JCArrayTypeTree)elemType).elemtype;
281 } else
282 break;
283 }
285 // find annotations locations of initializer elements
286 scan(tree.elems);
287 }
289 @Override
290 public void visitAnnotatedType(JCAnnotatedType tree) {
291 findPosition(tree, peek2(), tree.annotations);
292 super.visitAnnotatedType(tree);
293 }
295 @Override
296 public void visitMethodDef(JCMethodDecl tree) {
297 TypeAnnotationPosition p = new TypeAnnotationPosition();
298 p.type = TargetType.METHOD_RECEIVER;
299 setTypeAnnotationPos(tree.receiverAnnotations, p);
300 super.visitMethodDef(tree);
301 }
302 @Override
303 public void visitTypeParameter(JCTypeParameter tree) {
304 findPosition(tree, peek2(), tree.annotations);
305 super.visitTypeParameter(tree);
306 }
308 void findPosition(JCTree tree, JCTree frame, List<JCTypeAnnotation> annotations) {
309 if (!annotations.isEmpty()) {
310 TypeAnnotationPosition p =
311 resolveFrame(tree, frame, frames.toList(),
312 new TypeAnnotationPosition());
313 if (!p.location.isEmpty())
314 p.type = p.type.getGenericComplement();
315 setTypeAnnotationPos(annotations, p);
316 }
317 }
319 private int methodParamIndex(List<JCTree> path, JCTree param) {
320 List<JCTree> curr = path;
321 if (curr.head != param)
322 curr = path.tail;
323 JCMethodDecl method = (JCMethodDecl)curr.tail.head;
324 return method.params.indexOf(param);
325 }
326 }
328 private static class TypeAnnotationLift extends TreeScanner {
329 List<Attribute.TypeCompound> recordedTypeAnnotations = List.nil();
331 boolean isInner = false;
332 @Override
333 public void visitClassDef(JCClassDecl tree) {
334 if (isInner) {
335 // tree is an inner class tree. stop now.
336 // TransTypes.visitClassDef makes an invocation for each class
337 // separately.
338 return;
339 }
340 isInner = true;
341 List<Attribute.TypeCompound> prevTAs = recordedTypeAnnotations;
342 recordedTypeAnnotations = List.nil();
343 try {
344 super.visitClassDef(tree);
345 } finally {
346 tree.sym.typeAnnotations = tree.sym.typeAnnotations.appendList(recordedTypeAnnotations);
347 recordedTypeAnnotations = prevTAs;
348 }
349 }
351 @Override
352 public void visitMethodDef(JCMethodDecl tree) {
353 List<Attribute.TypeCompound> prevTAs = recordedTypeAnnotations;
354 recordedTypeAnnotations = List.nil();
355 try {
356 super.visitMethodDef(tree);
357 } finally {
358 tree.sym.typeAnnotations = tree.sym.typeAnnotations.appendList(recordedTypeAnnotations);
359 recordedTypeAnnotations = prevTAs;
360 }
361 }
363 @Override
364 public void visitVarDef(JCVariableDecl tree) {
365 List<Attribute.TypeCompound> prevTAs = recordedTypeAnnotations;
366 recordedTypeAnnotations = List.nil();
367 ElementKind kind = tree.sym.getKind();
368 if (kind == ElementKind.LOCAL_VARIABLE && tree.mods.annotations.nonEmpty()) {
369 // need to lift the annotations
370 TypeAnnotationPosition position = new TypeAnnotationPosition();
371 position.pos = tree.pos;
372 position.type = TargetType.LOCAL_VARIABLE;
373 for (Attribute.Compound attribute : tree.sym.attributes_field) {
374 Attribute.TypeCompound tc =
375 new Attribute.TypeCompound(attribute.type, attribute.values, position);
376 recordedTypeAnnotations = recordedTypeAnnotations.append(tc);
377 }
378 }
379 try {
380 super.visitVarDef(tree);
381 } finally {
382 if (kind.isField() || kind == ElementKind.LOCAL_VARIABLE)
383 tree.sym.typeAnnotations = tree.sym.typeAnnotations.appendList(recordedTypeAnnotations);
384 recordedTypeAnnotations = kind.isField() ? prevTAs : prevTAs.appendList(recordedTypeAnnotations);
385 }
386 }
388 @Override
389 public void visitApply(JCMethodInvocation tree) {
390 scan(tree.meth);
391 scan(tree.typeargs);
392 scan(tree.args);
393 }
395 public void visitAnnotation(JCAnnotation tree) {
396 if (tree instanceof JCTypeAnnotation)
397 recordedTypeAnnotations = recordedTypeAnnotations.append(((JCTypeAnnotation)tree).attribute_field);
398 super.visitAnnotation(tree);
399 }
400 }
402 }