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