1 /* 2 * Copyright (c) 2005, 2010, 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.model; 27 28 import java.lang.annotation.Annotation; 29 import java.lang.annotation.Inherited; 30 import java.util.Map; 31 import javax.lang.model.SourceVersion; 32 import javax.lang.model.element.*; 33 import javax.lang.model.type.DeclaredType; 34 import javax.lang.model.util.Elements; 35 import javax.tools.JavaFileObject; 36 import com.sun.tools.javac.code.*; 37 import com.sun.tools.javac.code.Symbol.*; 38 import com.sun.tools.javac.code.TypeTags; 39 import com.sun.tools.javac.comp.AttrContext; 40 import com.sun.tools.javac.comp.Enter; 41 import com.sun.tools.javac.comp.Env; 42 import com.sun.tools.javac.main.JavaCompiler; 43 import com.sun.tools.javac.processing.PrintingProcessor; 44 import com.sun.tools.javac.tree.JCTree; 45 import com.sun.tools.javac.tree.JCTree.*; 46 import com.sun.tools.javac.tree.TreeInfo; 47 import com.sun.tools.javac.tree.TreeScanner; 48 import com.sun.tools.javac.util.*; 49 import com.sun.tools.javac.util.Name; 50 51 import static javax.lang.model.util.ElementFilter.methodsIn; 52 53 /** 54 * Utility methods for operating on program elements. 55 * 56 * <p><b>This is NOT part of any supported API. 57 * If you write code that depends on this, you do so at your own 58 * risk. This code and its internal interfaces are subject to change 59 * or deletion without notice.</b></p> 60 */ 61 public class JavacElements implements Elements { 62 63 private JavaCompiler javaCompiler; 64 private Symtab syms; 65 private Names names; 66 private Types types; 67 private Enter enter; 68 69 public static JavacElements instance(Context context) { 70 JavacElements instance = context.get(JavacElements.class); 71 if (instance == null) 72 instance = new JavacElements(context); 73 return instance; 74 } 75 76 /** 77 * Public for use only by JavacProcessingEnvironment 78 */ 79 protected JavacElements(Context context) { 80 setContext(context); 81 } 82 83 /** 84 * Use a new context. May be called from outside to update 85 * internal state for a new annotation-processing round. 86 */ 87 public void setContext(Context context) { 88 context.put(JavacElements.class, this); 89 javaCompiler = JavaCompiler.instance(context); 90 syms = Symtab.instance(context); 91 names = Names.instance(context); 92 types = Types.instance(context); 93 enter = Enter.instance(context); 94 } 95 96 97 /** 98 * An internal-use utility that creates a reified annotation. 99 */ 100 public static <A extends Annotation> A getAnnotation(Symbol annotated, 101 Class<A> annoType) { 102 if (!annoType.isAnnotation()) 103 throw new IllegalArgumentException("Not an annotation type: " 104 + annoType); 105 String name = annoType.getName(); 106 for (Attribute.Compound anno : annotated.getAnnotationMirrors()) 107 if (name.equals(anno.type.tsym.flatName().toString())) 108 return AnnotationProxyMaker.generateAnnotation(anno, annoType); 109 return null; 110 } 111 112 /** 113 * An internal-use utility that creates a reified annotation. 114 * This overloaded version take annotation inheritance into account. 115 */ 116 public static <A extends Annotation> A getAnnotation(ClassSymbol annotated, 117 Class<A> annoType) { 118 boolean inherited = annoType.isAnnotationPresent(Inherited.class); 119 A result = null; 120 while (annotated.name != annotated.name.table.names.java_lang_Object) { 121 result = getAnnotation((Symbol)annotated, annoType); 122 if (result != null || !inherited) 123 break; 124 Type sup = annotated.getSuperclass(); 125 if (sup.tag != TypeTags.CLASS || sup.isErroneous()) 126 break; 127 annotated = (ClassSymbol) sup.tsym; 128 } 129 return result; 130 } 131 132 133 public PackageSymbol getPackageElement(CharSequence name) { 134 String strName = name.toString(); 135 if (strName.equals("")) 136 return syms.unnamedPackage; 137 return SourceVersion.isName(strName) 138 ? nameToSymbol(strName, PackageSymbol.class) 139 : null; 140 } 141 142 public ClassSymbol getTypeElement(CharSequence name) { 143 String strName = name.toString(); 144 return SourceVersion.isName(strName) 145 ? nameToSymbol(strName, ClassSymbol.class) 146 : null; 147 } 148 149 /** 150 * Returns a symbol given the type's or packages's canonical name, 151 * or null if the name isn't found. 152 */ 153 private <S extends Symbol> S nameToSymbol(String nameStr, Class<S> clazz) { 154 Name name = names.fromString(nameStr); 155 // First check cache. 156 Symbol sym = (clazz == ClassSymbol.class) 157 ? syms.classes.get(name) 158 : syms.packages.get(name); 159 160 try { 161 if (sym == null) 162 sym = javaCompiler.resolveIdent(nameStr); 163 164 sym.complete(); 165 166 return (sym.kind != Kinds.ERR && 167 sym.exists() && 168 clazz.isInstance(sym) && 169 name.equals(sym.getQualifiedName())) 170 ? clazz.cast(sym) 171 : null; 172 } catch (CompletionFailure e) { 173 return null; 174 } 175 } 176 177 public JavacSourcePosition getSourcePosition(Element e) { 178 Pair<JCTree, JCCompilationUnit> treeTop = getTreeAndTopLevel(e); 179 if (treeTop == null) 180 return null; 181 JCTree tree = treeTop.fst; 182 JCCompilationUnit toplevel = treeTop.snd; 183 JavaFileObject sourcefile = toplevel.sourcefile; 184 if (sourcefile == null) 185 return null; 186 return new JavacSourcePosition(sourcefile, tree.pos, toplevel.lineMap); 187 } 188 189 public JavacSourcePosition getSourcePosition(Element e, AnnotationMirror a) { 190 Pair<JCTree, JCCompilationUnit> treeTop = getTreeAndTopLevel(e); 191 if (treeTop == null) 192 return null; 193 JCTree tree = treeTop.fst; 194 JCCompilationUnit toplevel = treeTop.snd; 195 JavaFileObject sourcefile = toplevel.sourcefile; 196 if (sourcefile == null) 197 return null; 198 199 JCTree annoTree = matchAnnoToTree(a, e, tree); 200 if (annoTree == null) 201 return null; 202 return new JavacSourcePosition(sourcefile, annoTree.pos, 203 toplevel.lineMap); 204 } 205 206 public JavacSourcePosition getSourcePosition(Element e, AnnotationMirror a, 207 AnnotationValue v) { 208 // TODO: better accuracy in getSourcePosition(... AnnotationValue) 209 return getSourcePosition(e, a); 210 } 211 212 /** 213 * Returns the tree for an annotation given the annotated element 214 * and the element's own tree. Returns null if the tree cannot be found. 215 */ 216 private JCTree matchAnnoToTree(AnnotationMirror findme, 217 Element e, JCTree tree) { 218 Symbol sym = cast(Symbol.class, e); 219 class Vis extends JCTree.Visitor { 220 List<JCAnnotation> result = null; 221 public void visitTopLevel(JCCompilationUnit tree) { 222 result = tree.packageAnnotations; 223 } 224 public void visitClassDef(JCClassDecl tree) { 225 result = tree.mods.annotations; 226 } 227 public void visitMethodDef(JCMethodDecl tree) { 228 result = tree.mods.annotations; 229 } 230 public void visitVarDef(JCVariableDecl tree) { 231 result = tree.mods.annotations; 232 } 233 } 234 Vis vis = new Vis(); 235 tree.accept(vis); 236 if (vis.result == null) 237 return null; 238 return matchAnnoToTree(cast(Attribute.Compound.class, findme), 239 sym.getAnnotationMirrors(), 240 vis.result); 241 } 242 243 /** 244 * Returns the tree for an annotation given a list of annotations 245 * in which to search (recursively) and their corresponding trees. 246 * Returns null if the tree cannot be found. 247 */ 248 private JCTree matchAnnoToTree(Attribute.Compound findme, 249 List<Attribute.Compound> annos, 250 List<JCAnnotation> trees) { 251 for (Attribute.Compound anno : annos) { 252 for (JCAnnotation tree : trees) { 253 JCTree match = matchAnnoToTree(findme, anno, tree); 254 if (match != null) 255 return match; 256 } 257 } 258 return null; 259 } 260 261 /** 262 * Returns the tree for an annotation given an Attribute to 263 * search (recursively) and its corresponding tree. 264 * Returns null if the tree cannot be found. 265 */ 266 private JCTree matchAnnoToTree(final Attribute.Compound findme, 267 final Attribute attr, 268 final JCTree tree) { 269 if (attr == findme) 270 return (tree.type.tsym == findme.type.tsym) ? tree : null; 271 272 class Vis implements Attribute.Visitor { 273 JCTree result = null; 274 public void visitConstant(Attribute.Constant value) { 275 } 276 public void visitClass(Attribute.Class clazz) { 277 } 278 public void visitCompound(Attribute.Compound anno) { 279 for (Pair<MethodSymbol, Attribute> pair : anno.values) { 280 JCExpression expr = scanForAssign(pair.fst, tree); 281 if (expr != null) { 282 JCTree match = matchAnnoToTree(findme, pair.snd, expr); 283 if (match != null) { 284 result = match; 285 return; 286 } 287 } 288 } 289 } 290 public void visitArray(Attribute.Array array) { 291 if (tree.getTag() == JCTree.NEWARRAY && 292 types.elemtype(array.type).tsym == findme.type.tsym) { 293 List<JCExpression> elems = ((JCNewArray) tree).elems; 294 for (Attribute value : array.values) { 295 if (value == findme) { 296 result = elems.head; 297 return; 298 } 299 elems = elems.tail; 300 } 301 } 302 } 303 public void visitEnum(Attribute.Enum e) { 304 } 305 public void visitError(Attribute.Error e) { 306 } 307 } 308 Vis vis = new Vis(); 309 attr.accept(vis); 310 return vis.result; 311 } 312 313 /** 314 * Scans for a JCAssign node with a LHS matching a given 315 * symbol, and returns its RHS. Does not scan nested JCAnnotations. 316 */ 317 private JCExpression scanForAssign(final MethodSymbol sym, 318 final JCTree tree) { 319 class TS extends TreeScanner { 320 JCExpression result = null; 321 public void scan(JCTree t) { 322 if (t != null && result == null) 323 t.accept(this); 324 } 325 public void visitAnnotation(JCAnnotation t) { 326 if (t == tree) 327 scan(t.args); 328 } 329 public void visitAssign(JCAssign t) { 330 if (t.lhs.getTag() == JCTree.IDENT) { 331 JCIdent ident = (JCIdent) t.lhs; 332 if (ident.sym == sym) 333 result = t.rhs; 334 } 335 } 336 } 337 TS scanner = new TS(); 338 tree.accept(scanner); 339 return scanner.result; 340 } 341 342 /** 343 * Returns the tree node corresponding to this element, or null 344 * if none can be found. 345 */ 346 public JCTree getTree(Element e) { 347 Pair<JCTree, ?> treeTop = getTreeAndTopLevel(e); 348 return (treeTop != null) ? treeTop.fst : null; 349 } 350 351 public String getDocComment(Element e) { 352 // Our doc comment is contained in a map in our toplevel, 353 // indexed by our tree. Find our enter environment, which gives 354 // us our toplevel. It also gives us a tree that contains our 355 // tree: walk it to find our tree. This is painful. 356 Pair<JCTree, JCCompilationUnit> treeTop = getTreeAndTopLevel(e); 357 if (treeTop == null) 358 return null; 359 JCTree tree = treeTop.fst; 360 JCCompilationUnit toplevel = treeTop.snd; 361 if (toplevel.docComments == null) 362 return null; 363 return toplevel.docComments.get(tree); 364 } 365 366 public PackageElement getPackageOf(Element e) { 367 return cast(Symbol.class, e).packge(); 368 } 369 370 public boolean isDeprecated(Element e) { 371 Symbol sym = cast(Symbol.class, e); 372 return (sym.flags() & Flags.DEPRECATED) != 0; 373 } 374 375 public Name getBinaryName(TypeElement type) { 376 return cast(TypeSymbol.class, type).flatName(); 377 } 378 379 public Map<MethodSymbol, Attribute> getElementValuesWithDefaults( 380 AnnotationMirror a) { 381 Attribute.Compound anno = cast(Attribute.Compound.class, a); 382 DeclaredType annotype = a.getAnnotationType(); 383 Map<MethodSymbol, Attribute> valmap = anno.getElementValues(); 384 385 for (ExecutableElement ex : 386 methodsIn(annotype.asElement().getEnclosedElements())) { 387 MethodSymbol meth = (MethodSymbol) ex; 388 Attribute defaultValue = meth.getDefaultValue(); 389 if (defaultValue != null && !valmap.containsKey(meth)) { 390 valmap.put(meth, defaultValue); 391 } 392 } 393 return valmap; 394 } 395 396 /** 397 * {@inheritDoc} 398 */ 399 public FilteredMemberList getAllMembers(TypeElement element) { 400 Symbol sym = cast(Symbol.class, element); 401 Scope scope = sym.members().dupUnshared(); 402 List<Type> closure = types.closure(sym.asType()); 403 for (Type t : closure) 404 addMembers(scope, t); 405 return new FilteredMemberList(scope); 406 } 407 // where 408 private void addMembers(Scope scope, Type type) { 409 members: 410 for (Scope.Entry e = type.asElement().members().elems; e != null; e = e.sibling) { 411 Scope.Entry overrider = scope.lookup(e.sym.getSimpleName()); 412 while (overrider.scope != null) { 413 if (overrider.sym.kind == e.sym.kind 414 && (overrider.sym.flags() & Flags.SYNTHETIC) == 0) 415 { 416 if (overrider.sym.getKind() == ElementKind.METHOD 417 && overrides((ExecutableElement)overrider.sym, (ExecutableElement)e.sym, (TypeElement)type.asElement())) { 418 continue members; 419 } 420 } 421 overrider = overrider.next(); 422 } 423 boolean derived = e.sym.getEnclosingElement() != scope.owner; 424 ElementKind kind = e.sym.getKind(); 425 boolean initializer = kind == ElementKind.CONSTRUCTOR 426 || kind == ElementKind.INSTANCE_INIT 427 || kind == ElementKind.STATIC_INIT; 428 if (!derived || (!initializer && e.sym.isInheritedIn(scope.owner, types))) 429 scope.enter(e.sym); 430 } 431 } 432 433 /** 434 * Returns all annotations of an element, whether 435 * inherited or directly present. 436 * 437 * @param e the element being examined 438 * @return all annotations of the element 439 */ 440 public List<Attribute.Compound> getAllAnnotationMirrors(Element e) { 441 Symbol sym = cast(Symbol.class, e); 442 List<Attribute.Compound> annos = sym.getAnnotationMirrors(); 443 while (sym.getKind() == ElementKind.CLASS) { 444 Type sup = ((ClassSymbol) sym).getSuperclass(); 445 if (sup.tag != TypeTags.CLASS || sup.isErroneous() || 446 sup.tsym == syms.objectType.tsym) { 447 break; 448 } 449 sym = sup.tsym; 450 List<Attribute.Compound> oldAnnos = annos; 451 for (Attribute.Compound anno : sym.getAnnotationMirrors()) { 452 if (isInherited(anno.type) && 453 !containsAnnoOfType(oldAnnos, anno.type)) { 454 annos = annos.prepend(anno); 455 } 456 } 457 } 458 return annos; 459 } 460 461 /** 462 * Tests whether an annotation type is @Inherited. 463 */ 464 private boolean isInherited(Type annotype) { 465 for (Attribute.Compound anno : annotype.tsym.getAnnotationMirrors()) { 466 if (anno.type.tsym == syms.inheritedType.tsym) 467 return true; 468 } 469 return false; 470 } 471 472 /** 473 * Tests whether a list of annotations contains an annotation 474 * of a given type. 475 */ 476 private static boolean containsAnnoOfType(List<Attribute.Compound> annos, 477 Type type) { 478 for (Attribute.Compound anno : annos) { 479 if (anno.type.tsym == type.tsym) 480 return true; 481 } 482 return false; 483 } 484 485 public boolean hides(Element hiderEl, Element hideeEl) { 486 Symbol hider = cast(Symbol.class, hiderEl); 487 Symbol hidee = cast(Symbol.class, hideeEl); 488 489 // Fields only hide fields; methods only methods; types only types. 490 // Names must match. Nothing hides itself (just try it). 491 if (hider == hidee || 492 hider.kind != hidee.kind || 493 hider.name != hidee.name) { 494 return false; 495 } 496 497 // Only static methods can hide other methods. 498 // Methods only hide methods with matching signatures. 499 if (hider.kind == Kinds.MTH) { 500 if (!hider.isStatic() || 501 !types.isSubSignature(hider.type, hidee.type)) { 502 return false; 503 } 504 } 505 506 // Hider must be in a subclass of hidee's class. 507 // Note that if M1 hides M2, and M2 hides M3, and M3 is accessible 508 // in M1's class, then M1 and M2 both hide M3. 509 ClassSymbol hiderClass = hider.owner.enclClass(); 510 ClassSymbol hideeClass = hidee.owner.enclClass(); 511 if (hiderClass == null || hideeClass == null || 512 !hiderClass.isSubClass(hideeClass, types)) { 513 return false; 514 } 515 516 // Hidee must be accessible in hider's class. 517 // The method isInheritedIn is poorly named: it checks only access. 518 return hidee.isInheritedIn(hiderClass, types); 519 } 520 521 public boolean overrides(ExecutableElement riderEl, 522 ExecutableElement rideeEl, TypeElement typeEl) { 523 MethodSymbol rider = cast(MethodSymbol.class, riderEl); 524 MethodSymbol ridee = cast(MethodSymbol.class, rideeEl); 525 ClassSymbol origin = cast(ClassSymbol.class, typeEl); 526 527 return rider.name == ridee.name && 528 529 // not reflexive as per JLS 530 rider != ridee && 531 532 // we don't care if ridee is static, though that wouldn't 533 // compile 534 !rider.isStatic() && 535 536 // Symbol.overrides assumes the following 537 ridee.isMemberOf(origin, types) && 538 539 // check access and signatures; don't check return types 540 rider.overrides(ridee, origin, types, false); 541 } 542 543 public String getConstantExpression(Object value) { 544 return Constants.format(value); 545 } 546 547 /** 548 * Print a representation of the elements to the given writer in 549 * the specified order. The main purpose of this method is for 550 * diagnostics. The exact format of the output is <em>not</em> 551 * specified and is subject to change. 552 * 553 * @param w the writer to print the output to 554 * @param elements the elements to print 555 */ 556 public void printElements(java.io.Writer w, Element... elements) { 557 for (Element element : elements) 558 (new PrintingProcessor.PrintingElementVisitor(w, this)).visit(element).flush(); 559 } 560 561 public Name getName(CharSequence cs) { 562 return names.fromString(cs.toString()); 563 } 564 565 /** 566 * Returns the tree node and compilation unit corresponding to this 567 * element, or null if they can't be found. 568 */ 569 private Pair<JCTree, JCCompilationUnit> getTreeAndTopLevel(Element e) { 570 Symbol sym = cast(Symbol.class, e); 571 Env<AttrContext> enterEnv = getEnterEnv(sym); 572 if (enterEnv == null) 573 return null; 574 JCTree tree = TreeInfo.declarationFor(sym, enterEnv.tree); 575 if (tree == null || enterEnv.toplevel == null) 576 return null; 577 return new Pair<JCTree,JCCompilationUnit>(tree, enterEnv.toplevel); 578 } 579 580 /** 581 * Returns the best approximation for the tree node and compilation unit 582 * corresponding to the given element, annotation and value. 583 * If the element is null, null is returned. 584 * If the annotation is null or cannot be found, the tree node and 585 * compilation unit for the element is returned. 586 * If the annotation value is null or cannot be found, the tree node and 587 * compilation unit for the annotation is returned. 588 */ 589 public Pair<JCTree, JCCompilationUnit> getTreeAndTopLevel( 590 Element e, AnnotationMirror a, AnnotationValue v) { 591 if (e == null) 592 return null; 593 594 Pair<JCTree, JCCompilationUnit> elemTreeTop = getTreeAndTopLevel(e); 595 if (elemTreeTop == null) 596 return null; 597 598 if (a == null) 599 return elemTreeTop; 600 601 JCTree annoTree = matchAnnoToTree(a, e, elemTreeTop.fst); 602 if (annoTree == null) 603 return elemTreeTop; 604 605 // 6388543: if v != null, we should search within annoTree to find 606 // the tree matching v. For now, we ignore v and return the tree of 607 // the annotation. 608 return new Pair<JCTree, JCCompilationUnit>(annoTree, elemTreeTop.snd); 609 } 610 611 /** 612 * Returns a symbol's enter environment, or null if it has none. 613 */ 614 private Env<AttrContext> getEnterEnv(Symbol sym) { 615 // Get enclosing class of sym, or sym itself if it is a class 616 // or package. 617 TypeSymbol ts = (sym.kind != Kinds.PCK) 618 ? sym.enclClass() 619 : (PackageSymbol) sym; 620 return (ts != null) 621 ? enter.getEnv(ts) 622 : null; 623 } 624 625 /** 626 * Returns an object cast to the specified type. 627 * @throws NullPointerException if the object is {@code null} 628 * @throws IllegalArgumentException if the object is of the wrong type 629 */ 630 private static <T> T cast(Class<T> clazz, Object o) { 631 if (! clazz.isInstance(o)) 632 throw new IllegalArgumentException(o.toString()); 633 return clazz.cast(o); 634 } 635 }