Wed, 21 Sep 2011 21:56:53 -0700
7092965: javac should not close processorClassLoader before end of compilation
Reviewed-by: darcy
1 /*
2 * Copyright (c) 2005, 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.api;
28 import java.io.IOException;
29 import java.util.Map;
30 import javax.annotation.processing.ProcessingEnvironment;
31 import javax.lang.model.element.AnnotationMirror;
32 import javax.lang.model.element.AnnotationValue;
33 import javax.lang.model.element.Element;
34 import javax.lang.model.element.ExecutableElement;
35 import javax.lang.model.element.TypeElement;
36 import javax.lang.model.type.DeclaredType;
37 import javax.lang.model.type.TypeKind;
38 import javax.lang.model.type.TypeMirror;
39 import javax.tools.Diagnostic;
40 import javax.tools.JavaCompiler;
41 import javax.tools.JavaFileObject;
43 import com.sun.source.tree.CatchTree;
44 import com.sun.source.tree.CompilationUnitTree;
45 import com.sun.source.tree.Scope;
46 import com.sun.source.tree.Tree;
47 import com.sun.source.util.SourcePositions;
48 import com.sun.source.util.TreePath;
49 import com.sun.source.util.Trees;
50 import com.sun.tools.javac.code.Flags;
51 import com.sun.tools.javac.code.Symbol.ClassSymbol;
52 import com.sun.tools.javac.code.Symbol.TypeSymbol;
53 import com.sun.tools.javac.code.Symbol;
54 import com.sun.tools.javac.code.Type.UnionClassType;
55 import com.sun.tools.javac.comp.Attr;
56 import com.sun.tools.javac.comp.AttrContext;
57 import com.sun.tools.javac.comp.Enter;
58 import com.sun.tools.javac.comp.Env;
59 import com.sun.tools.javac.comp.MemberEnter;
60 import com.sun.tools.javac.comp.Resolve;
61 import com.sun.tools.javac.model.JavacElements;
62 import com.sun.tools.javac.processing.JavacProcessingEnvironment;
63 import com.sun.tools.javac.tree.JCTree.*;
64 import com.sun.tools.javac.tree.JCTree;
65 import com.sun.tools.javac.tree.TreeCopier;
66 import com.sun.tools.javac.tree.TreeInfo;
67 import com.sun.tools.javac.tree.TreeMaker;
68 import com.sun.tools.javac.util.Assert;
69 import com.sun.tools.javac.util.Context;
70 import com.sun.tools.javac.util.JCDiagnostic;
71 import com.sun.tools.javac.util.List;
72 import com.sun.tools.javac.util.Log;
73 import com.sun.tools.javac.util.Pair;
75 /**
76 * Provides an implementation of Trees.
77 *
78 * <p><b>This is NOT part of any supported API.
79 * If you write code that depends on this, you do so at your own
80 * risk. This code and its internal interfaces are subject to change
81 * or deletion without notice.</b></p>
82 *
83 * @author Peter von der Ahé
84 */
85 public class JavacTrees extends Trees {
87 // in a world of a single context per compilation, these would all be final
88 private Resolve resolve;
89 private Enter enter;
90 private Log log;
91 private MemberEnter memberEnter;
92 private Attr attr;
93 private TreeMaker treeMaker;
94 private JavacElements elements;
95 private JavacTaskImpl javacTaskImpl;
97 public static JavacTrees instance(JavaCompiler.CompilationTask task) {
98 if (!(task instanceof JavacTaskImpl))
99 throw new IllegalArgumentException();
100 return instance(((JavacTaskImpl)task).getContext());
101 }
103 public static JavacTrees instance(ProcessingEnvironment env) {
104 if (!(env instanceof JavacProcessingEnvironment))
105 throw new IllegalArgumentException();
106 return instance(((JavacProcessingEnvironment)env).getContext());
107 }
109 public static JavacTrees instance(Context context) {
110 JavacTrees instance = context.get(JavacTrees.class);
111 if (instance == null)
112 instance = new JavacTrees(context);
113 return instance;
114 }
116 private JavacTrees(Context context) {
117 context.put(JavacTrees.class, this);
118 init(context);
119 }
121 public void updateContext(Context context) {
122 init(context);
123 }
125 private void init(Context context) {
126 attr = Attr.instance(context);
127 enter = Enter.instance(context);
128 elements = JavacElements.instance(context);
129 log = Log.instance(context);
130 resolve = Resolve.instance(context);
131 treeMaker = TreeMaker.instance(context);
132 memberEnter = MemberEnter.instance(context);
133 javacTaskImpl = context.get(JavacTaskImpl.class);
134 }
136 public SourcePositions getSourcePositions() {
137 return new SourcePositions() {
138 public long getStartPosition(CompilationUnitTree file, Tree tree) {
139 return TreeInfo.getStartPos((JCTree) tree);
140 }
142 public long getEndPosition(CompilationUnitTree file, Tree tree) {
143 Map<JCTree,Integer> endPositions = ((JCCompilationUnit) file).endPositions;
144 return TreeInfo.getEndPos((JCTree) tree, endPositions);
145 }
146 };
147 }
149 public JCClassDecl getTree(TypeElement element) {
150 return (JCClassDecl) getTree((Element) element);
151 }
153 public JCMethodDecl getTree(ExecutableElement method) {
154 return (JCMethodDecl) getTree((Element) method);
155 }
157 public JCTree getTree(Element element) {
158 Symbol symbol = (Symbol) element;
159 TypeSymbol enclosing = symbol.enclClass();
160 Env<AttrContext> env = enter.getEnv(enclosing);
161 if (env == null)
162 return null;
163 JCClassDecl classNode = env.enclClass;
164 if (classNode != null) {
165 if (TreeInfo.symbolFor(classNode) == element)
166 return classNode;
167 for (JCTree node : classNode.getMembers())
168 if (TreeInfo.symbolFor(node) == element)
169 return node;
170 }
171 return null;
172 }
174 public JCTree getTree(Element e, AnnotationMirror a) {
175 return getTree(e, a, null);
176 }
178 public JCTree getTree(Element e, AnnotationMirror a, AnnotationValue v) {
179 Pair<JCTree, JCCompilationUnit> treeTopLevel = elements.getTreeAndTopLevel(e, a, v);
180 if (treeTopLevel == null)
181 return null;
182 return treeTopLevel.fst;
183 }
185 public TreePath getPath(CompilationUnitTree unit, Tree node) {
186 return TreePath.getPath(unit, node);
187 }
189 public TreePath getPath(Element e) {
190 return getPath(e, null, null);
191 }
193 public TreePath getPath(Element e, AnnotationMirror a) {
194 return getPath(e, a, null);
195 }
197 public TreePath getPath(Element e, AnnotationMirror a, AnnotationValue v) {
198 final Pair<JCTree, JCCompilationUnit> treeTopLevel = elements.getTreeAndTopLevel(e, a, v);
199 if (treeTopLevel == null)
200 return null;
201 return TreePath.getPath(treeTopLevel.snd, treeTopLevel.fst);
202 }
204 public Element getElement(TreePath path) {
205 JCTree tree = (JCTree) path.getLeaf();
206 Symbol sym = TreeInfo.symbolFor(tree);
207 if (sym == null && TreeInfo.isDeclaration(tree)) {
208 for (TreePath p = path; p != null; p = p.getParentPath()) {
209 JCTree t = (JCTree) p.getLeaf();
210 if (t.getTag() == JCTree.CLASSDEF) {
211 JCClassDecl ct = (JCClassDecl) t;
212 if (ct.sym != null) {
213 if ((ct.sym.flags_field & Flags.UNATTRIBUTED) != 0) {
214 attr.attribClass(ct.pos(), ct.sym);
215 sym = TreeInfo.symbolFor(tree);
216 }
217 break;
218 }
219 }
220 }
221 }
222 return sym;
223 }
225 public TypeMirror getTypeMirror(TreePath path) {
226 Tree t = path.getLeaf();
227 return ((JCTree)t).type;
228 }
230 public JavacScope getScope(TreePath path) {
231 return new JavacScope(getAttrContext(path));
232 }
234 public String getDocComment(TreePath path) {
235 CompilationUnitTree t = path.getCompilationUnit();
236 if (t instanceof JCTree.JCCompilationUnit) {
237 JCCompilationUnit cu = (JCCompilationUnit) t;
238 if (cu.docComments != null) {
239 return cu.docComments.get(path.getLeaf());
240 }
241 }
242 return null;
243 }
245 public boolean isAccessible(Scope scope, TypeElement type) {
246 if (scope instanceof JavacScope && type instanceof ClassSymbol) {
247 Env<AttrContext> env = ((JavacScope) scope).env;
248 return resolve.isAccessible(env, (ClassSymbol)type, true);
249 } else
250 return false;
251 }
253 public boolean isAccessible(Scope scope, Element member, DeclaredType type) {
254 if (scope instanceof JavacScope
255 && member instanceof Symbol
256 && type instanceof com.sun.tools.javac.code.Type) {
257 Env<AttrContext> env = ((JavacScope) scope).env;
258 return resolve.isAccessible(env, (com.sun.tools.javac.code.Type)type, (Symbol)member, true);
259 } else
260 return false;
261 }
263 private Env<AttrContext> getAttrContext(TreePath path) {
264 if (!(path.getLeaf() instanceof JCTree)) // implicit null-check
265 throw new IllegalArgumentException();
267 // if we're being invoked from a Tree API client via parse/enter/analyze,
268 // we need to make sure all the classes have been entered;
269 // if we're being invoked from JSR 199 or JSR 269, then the classes
270 // will already have been entered.
271 if (javacTaskImpl != null) {
272 try {
273 javacTaskImpl.enter(null);
274 } catch (IOException e) {
275 throw new Error("unexpected error while entering symbols: " + e);
276 }
277 }
280 JCCompilationUnit unit = (JCCompilationUnit) path.getCompilationUnit();
281 Copier copier = new Copier(treeMaker.forToplevel(unit));
283 Env<AttrContext> env = null;
284 JCMethodDecl method = null;
285 JCVariableDecl field = null;
287 List<Tree> l = List.nil();
288 TreePath p = path;
289 while (p != null) {
290 l = l.prepend(p.getLeaf());
291 p = p.getParentPath();
292 }
294 for ( ; l.nonEmpty(); l = l.tail) {
295 Tree tree = l.head;
296 switch (tree.getKind()) {
297 case COMPILATION_UNIT:
298 // System.err.println("COMP: " + ((JCCompilationUnit)tree).sourcefile);
299 env = enter.getTopLevelEnv((JCCompilationUnit)tree);
300 break;
301 case ANNOTATION_TYPE:
302 case CLASS:
303 case ENUM:
304 case INTERFACE:
305 // System.err.println("CLASS: " + ((JCClassDecl)tree).sym.getSimpleName());
306 env = enter.getClassEnv(((JCClassDecl)tree).sym);
307 break;
308 case METHOD:
309 // System.err.println("METHOD: " + ((JCMethodDecl)tree).sym.getSimpleName());
310 method = (JCMethodDecl)tree;
311 break;
312 case VARIABLE:
313 // System.err.println("FIELD: " + ((JCVariableDecl)tree).sym.getSimpleName());
314 field = (JCVariableDecl)tree;
315 break;
316 case BLOCK: {
317 // System.err.println("BLOCK: ");
318 if (method != null) {
319 try {
320 Assert.check(method.body == tree);
321 method.body = copier.copy((JCBlock)tree, (JCTree) path.getLeaf());
322 env = memberEnter.getMethodEnv(method, env);
323 env = attribStatToTree(method.body, env, copier.leafCopy);
324 } finally {
325 method.body = (JCBlock) tree;
326 }
327 } else {
328 JCBlock body = copier.copy((JCBlock)tree, (JCTree) path.getLeaf());
329 env = attribStatToTree(body, env, copier.leafCopy);
330 }
331 return env;
332 }
333 default:
334 // System.err.println("DEFAULT: " + tree.getKind());
335 if (field != null && field.getInitializer() == tree) {
336 env = memberEnter.getInitEnv(field, env);
337 JCExpression expr = copier.copy((JCExpression)tree, (JCTree) path.getLeaf());
338 env = attribExprToTree(expr, env, copier.leafCopy);
339 return env;
340 }
341 }
342 }
343 return (field != null) ? memberEnter.getInitEnv(field, env) : env;
344 }
346 private Env<AttrContext> attribStatToTree(JCTree stat, Env<AttrContext>env, JCTree tree) {
347 JavaFileObject prev = log.useSource(env.toplevel.sourcefile);
348 try {
349 return attr.attribStatToTree(stat, env, tree);
350 } finally {
351 log.useSource(prev);
352 }
353 }
355 private Env<AttrContext> attribExprToTree(JCExpression expr, Env<AttrContext>env, JCTree tree) {
356 JavaFileObject prev = log.useSource(env.toplevel.sourcefile);
357 try {
358 return attr.attribExprToTree(expr, env, tree);
359 } finally {
360 log.useSource(prev);
361 }
362 }
364 /**
365 * Makes a copy of a tree, noting the value resulting from copying a particular leaf.
366 **/
367 static class Copier extends TreeCopier<JCTree> {
368 JCTree leafCopy = null;
370 Copier(TreeMaker M) {
371 super(M);
372 }
374 @Override
375 public <T extends JCTree> T copy(T t, JCTree leaf) {
376 T t2 = super.copy(t, leaf);
377 if (t == leaf)
378 leafCopy = t2;
379 return t2;
380 }
381 }
383 /**
384 * Gets the original type from the ErrorType object.
385 * @param errorType The errorType for which we want to get the original type.
386 * @returns TypeMirror corresponding to the original type, replaced by the ErrorType.
387 * noType (type.tag == NONE) is returned if there is no original type.
388 */
389 public TypeMirror getOriginalType(javax.lang.model.type.ErrorType errorType) {
390 if (errorType instanceof com.sun.tools.javac.code.Type.ErrorType) {
391 return ((com.sun.tools.javac.code.Type.ErrorType)errorType).getOriginalType();
392 }
394 return com.sun.tools.javac.code.Type.noType;
395 }
397 /**
398 * Prints a message of the specified kind at the location of the
399 * tree within the provided compilation unit
400 *
401 * @param kind the kind of message
402 * @param msg the message, or an empty string if none
403 * @param t the tree to use as a position hint
404 * @param root the compilation unit that contains tree
405 */
406 public void printMessage(Diagnostic.Kind kind, CharSequence msg,
407 com.sun.source.tree.Tree t,
408 com.sun.source.tree.CompilationUnitTree root) {
409 JavaFileObject oldSource = null;
410 JavaFileObject newSource = null;
411 JCDiagnostic.DiagnosticPosition pos = null;
413 newSource = root.getSourceFile();
414 if (newSource != null) {
415 oldSource = log.useSource(newSource);
416 pos = ((JCTree) t).pos();
417 }
419 try {
420 switch (kind) {
421 case ERROR:
422 boolean prev = log.multipleErrors;
423 try {
424 log.error(pos, "proc.messager", msg.toString());
425 } finally {
426 log.multipleErrors = prev;
427 }
428 break;
430 case WARNING:
431 log.warning(pos, "proc.messager", msg.toString());
432 break;
434 case MANDATORY_WARNING:
435 log.mandatoryWarning(pos, "proc.messager", msg.toString());
436 break;
438 default:
439 log.note(pos, "proc.messager", msg.toString());
440 }
441 } finally {
442 if (oldSource != null)
443 log.useSource(oldSource);
444 }
445 }
447 @Override
448 public TypeMirror getLub(CatchTree tree) {
449 JCCatch ct = (JCCatch) tree;
450 JCVariableDecl v = ct.param;
451 if (v.type != null && v.type.getKind() == TypeKind.UNION) {
452 UnionClassType ut = (UnionClassType) v.type;
453 return ut.getLub();
454 } else {
455 return v.type;
456 }
457 }
458 }