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 */ 25 26 package com.sun.tools.javac.api; 27 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; 42 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; 74 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 { 86 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; 96 97 public static JavacTrees instance(JavaCompiler.CompilationTask task) { 98 if (!(task instanceof JavacTaskImpl)) 99 throw new IllegalArgumentException(); 100 return instance(((JavacTaskImpl)task).getContext()); 101 } 102 103 public static JavacTrees instance(ProcessingEnvironment env) { 104 if (!(env instanceof JavacProcessingEnvironment)) 105 throw new IllegalArgumentException(); 106 return instance(((JavacProcessingEnvironment)env).getContext()); 107 } 108 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 } 115 116 private JavacTrees(Context context) { 117 context.put(JavacTrees.class, this); 118 init(context); 119 } 120 121 public void updateContext(Context context) { 122 init(context); 123 } 124 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 } 135 136 public SourcePositions getSourcePositions() { 137 return new SourcePositions() { 138 public long getStartPosition(CompilationUnitTree file, Tree tree) { 139 return TreeInfo.getStartPos((JCTree) tree); 140 } 141 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 } 148 149 public JCClassDecl getTree(TypeElement element) { 150 return (JCClassDecl) getTree((Element) element); 151 } 152 153 public JCMethodDecl getTree(ExecutableElement method) { 154 return (JCMethodDecl) getTree((Element) method); 155 } 156 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 } 173 174 public JCTree getTree(Element e, AnnotationMirror a) { 175 return getTree(e, a, null); 176 } 177 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 } 184 185 public TreePath getPath(CompilationUnitTree unit, Tree node) { 186 return TreePath.getPath(unit, node); 187 } 188 189 public TreePath getPath(Element e) { 190 return getPath(e, null, null); 191 } 192 193 public TreePath getPath(Element e, AnnotationMirror a) { 194 return getPath(e, a, null); 195 } 196 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 } 203 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 } 224 225 public TypeMirror getTypeMirror(TreePath path) { 226 Tree t = path.getLeaf(); 227 return ((JCTree)t).type; 228 } 229 230 public JavacScope getScope(TreePath path) { 231 return new JavacScope(getAttrContext(path)); 232 } 233 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 } 244 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 } 252 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 } 262 263 private Env<AttrContext> getAttrContext(TreePath path) { 264 if (!(path.getLeaf() instanceof JCTree)) // implicit null-check 265 throw new IllegalArgumentException(); 266 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 } 278 279 280 JCCompilationUnit unit = (JCCompilationUnit) path.getCompilationUnit(); 281 Copier copier = new Copier(treeMaker.forToplevel(unit)); 282 283 Env<AttrContext> env = null; 284 JCMethodDecl method = null; 285 JCVariableDecl field = null; 286 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 } 293 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 } 345 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 } 354 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 } 363 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; 369 370 Copier(TreeMaker M) { 371 super(M); 372 } 373 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 } 382 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 } 393 394 return com.sun.tools.javac.code.Type.noType; 395 } 396 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; 412 413 newSource = root.getSourceFile(); 414 if (newSource != null) { 415 oldSource = log.useSource(newSource); 416 pos = ((JCTree) t).pos(); 417 } 418 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; 429 430 case WARNING: 431 log.warning(pos, "proc.messager", msg.toString()); 432 break; 433 434 case MANDATORY_WARNING: 435 log.mandatoryWarning(pos, "proc.messager", msg.toString()); 436 break; 437 438 default: 439 log.note(pos, "proc.messager", msg.toString()); 440 } 441 } finally { 442 if (oldSource != null) 443 log.useSource(oldSource); 444 } 445 } 446 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 }