JavacElements.java revision 3886:03f48cd283f5
1/* 2 * Copyright (c) 2005, 2017, 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 26package com.sun.tools.javac.model; 27 28import java.util.HashSet; 29import java.util.LinkedHashSet; 30import java.util.Map; 31import java.util.Set; 32import java.util.stream.Collectors; 33 34import javax.lang.model.AnnotatedConstruct; 35import javax.lang.model.SourceVersion; 36import javax.lang.model.element.*; 37import javax.lang.model.type.DeclaredType; 38import javax.lang.model.util.Elements; 39import javax.tools.JavaFileObject; 40import static javax.lang.model.util.ElementFilter.methodsIn; 41 42import com.sun.source.util.JavacTask; 43import com.sun.tools.javac.api.JavacTaskImpl; 44import com.sun.tools.javac.code.*; 45import com.sun.tools.javac.code.Attribute.Compound; 46import com.sun.tools.javac.code.Directive.ExportsDirective; 47import com.sun.tools.javac.code.Directive.ExportsFlag; 48import com.sun.tools.javac.code.Directive.OpensDirective; 49import com.sun.tools.javac.code.Directive.OpensFlag; 50import com.sun.tools.javac.code.Directive.RequiresDirective; 51import com.sun.tools.javac.code.Directive.RequiresFlag; 52import com.sun.tools.javac.code.Scope.WriteableScope; 53import com.sun.tools.javac.code.Symbol.*; 54import com.sun.tools.javac.comp.AttrContext; 55import com.sun.tools.javac.comp.Enter; 56import com.sun.tools.javac.comp.Env; 57import com.sun.tools.javac.main.JavaCompiler; 58import com.sun.tools.javac.processing.PrintingProcessor; 59import com.sun.tools.javac.tree.JCTree; 60import com.sun.tools.javac.tree.JCTree.*; 61import com.sun.tools.javac.tree.TreeInfo; 62import com.sun.tools.javac.tree.TreeScanner; 63import com.sun.tools.javac.util.*; 64import com.sun.tools.javac.util.DefinedBy.Api; 65import com.sun.tools.javac.util.Name; 66import static com.sun.tools.javac.code.Kinds.Kind.*; 67import static com.sun.tools.javac.code.Scope.LookupKind.NON_RECURSIVE; 68import static com.sun.tools.javac.code.TypeTag.CLASS; 69import com.sun.tools.javac.comp.Modules; 70import com.sun.tools.javac.comp.Resolve; 71import com.sun.tools.javac.comp.Resolve.RecoveryLoadClass; 72import com.sun.tools.javac.resources.CompilerProperties.Notes; 73import static com.sun.tools.javac.tree.JCTree.Tag.*; 74 75/** 76 * Utility methods for operating on program elements. 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 */ 83public class JavacElements implements Elements { 84 85 private final JavaCompiler javaCompiler; 86 private final Symtab syms; 87 private final Modules modules; 88 private final Names names; 89 private final Types types; 90 private final Enter enter; 91 private final Resolve resolve; 92 private final JavacTaskImpl javacTaskImpl; 93 private final Log log; 94 private final boolean allowModules; 95 96 public static JavacElements instance(Context context) { 97 JavacElements instance = context.get(JavacElements.class); 98 if (instance == null) 99 instance = new JavacElements(context); 100 return instance; 101 } 102 103 protected JavacElements(Context context) { 104 context.put(JavacElements.class, this); 105 javaCompiler = JavaCompiler.instance(context); 106 syms = Symtab.instance(context); 107 modules = Modules.instance(context); 108 names = Names.instance(context); 109 types = Types.instance(context); 110 enter = Enter.instance(context); 111 resolve = Resolve.instance(context); 112 JavacTask t = context.get(JavacTask.class); 113 javacTaskImpl = t instanceof JavacTaskImpl ? (JavacTaskImpl) t : null; 114 log = Log.instance(context); 115 Source source = Source.instance(context); 116 allowModules = source.allowModules(); 117 } 118 119 @Override @DefinedBy(Api.LANGUAGE_MODEL) 120 public ModuleSymbol getModuleElement(CharSequence name) { 121 ensureEntered("getModuleElement"); 122 if (modules.getDefaultModule() == syms.noModule) 123 return null; 124 String strName = name.toString(); 125 if (strName.equals("")) 126 return syms.unnamedModule; 127 return modules.getObservableModule(names.fromString(strName)); 128 } 129 130 @Override @DefinedBy(Api.LANGUAGE_MODEL) 131 public PackageSymbol getPackageElement(CharSequence name) { 132 return doGetPackageElement(null, name); 133 } 134 135 @Override @DefinedBy(Api.LANGUAGE_MODEL) 136 public PackageSymbol getPackageElement(ModuleElement module, CharSequence name) { 137 module.getClass(); 138 return doGetPackageElement(module, name); 139 } 140 141 private PackageSymbol doGetPackageElement(ModuleElement module, CharSequence name) { 142 ensureEntered("getPackageElement"); 143 if (name.length() == 0) 144 return syms.unnamedModule.unnamedPackage; 145 return doGetElement(module, "getPackageElement", name, PackageSymbol.class); 146 } 147 148 @Override @DefinedBy(Api.LANGUAGE_MODEL) 149 public ClassSymbol getTypeElement(CharSequence name) { 150 return doGetTypeElement(null, name); 151 } 152 153 @Override @DefinedBy(Api.LANGUAGE_MODEL) 154 public ClassSymbol getTypeElement(ModuleElement module, CharSequence name) { 155 module.getClass(); 156 157 return doGetTypeElement(module, name); 158 } 159 160 private ClassSymbol doGetTypeElement(ModuleElement module, CharSequence name) { 161 ensureEntered("getTypeElement"); 162 return doGetElement(module, "getTypeElement", name, ClassSymbol.class); 163 } 164 165 private <S extends Symbol> S doGetElement(ModuleElement module, String methodName, 166 CharSequence name, Class<S> clazz) { 167 String strName = name.toString(); 168 if (!SourceVersion.isName(strName)) { 169 return null; 170 } 171 if (module == null) { 172 return unboundNameToSymbol(methodName, strName, clazz); 173 } else { 174 return nameToSymbol((ModuleSymbol) module, strName, clazz); 175 } 176 } 177 178 private final Set<String> alreadyWarnedDuplicates = new HashSet<>(); 179 180 private <S extends Symbol> S unboundNameToSymbol(String methodName, 181 String nameStr, 182 Class<S> clazz) { 183 if (modules.getDefaultModule() == syms.noModule) { //not a modular mode: 184 return nameToSymbol(syms.noModule, nameStr, clazz); 185 } 186 187 RecoveryLoadClass prevRecoveryLoadClass = resolve.setRecoveryLoadClass((env, name) -> null); 188 try { 189 Set<S> found = new LinkedHashSet<>(); 190 191 for (ModuleSymbol msym : modules.allModules()) { 192 S sym = nameToSymbol(msym, nameStr, clazz); 193 194 if (sym != null) { 195 if (!allowModules || clazz == ClassSymbol.class || !sym.members().isEmpty()) { 196 //do not add packages without members: 197 found.add(sym); 198 } 199 } 200 } 201 202 if (found.size() == 1) { 203 return found.iterator().next(); 204 } else if (found.size() > 1) { 205 //more than one element found, produce a note: 206 if (alreadyWarnedDuplicates.add(methodName + ":" + nameStr)) { 207 String moduleNames = found.stream() 208 .map(s -> s.packge().modle) 209 .map(m -> m.toString()) 210 .collect(Collectors.joining(", ")); 211 log.note(Notes.MultipleElements(methodName, nameStr, moduleNames)); 212 } 213 return null; 214 } else { 215 //not found, or more than one element found: 216 return null; 217 } 218 } finally { 219 resolve.setRecoveryLoadClass(prevRecoveryLoadClass); 220 } 221 } 222 223 /** 224 * Returns a symbol given the type's or package's canonical name, 225 * or null if the name isn't found. 226 */ 227 private <S extends Symbol> S nameToSymbol(ModuleSymbol module, String nameStr, Class<S> clazz) { 228 Name name = names.fromString(nameStr); 229 // First check cache. 230 Symbol sym = (clazz == ClassSymbol.class) 231 ? syms.getClass(module, name) 232 : syms.lookupPackage(module, name); 233 234 try { 235 if (sym == null) 236 sym = javaCompiler.resolveIdent(module, nameStr); 237 238 sym.complete(); 239 240 return (sym.kind != ERR && 241 sym.exists() && 242 clazz.isInstance(sym) && 243 name.equals(sym.getQualifiedName())) 244 ? clazz.cast(sym) 245 : null; 246 } catch (CompletionFailure e) { 247 return null; 248 } 249 } 250 251 /** 252 * Returns the tree for an annotation given the annotated element 253 * and the element's own tree. Returns null if the tree cannot be found. 254 */ 255 private JCTree matchAnnoToTree(AnnotationMirror findme, 256 Element e, JCTree tree) { 257 Symbol sym = cast(Symbol.class, e); 258 class Vis extends JCTree.Visitor { 259 List<JCAnnotation> result = null; 260 public void visitPackageDef(JCPackageDecl tree) { 261 result = tree.annotations; 262 } 263 public void visitClassDef(JCClassDecl tree) { 264 result = tree.mods.annotations; 265 } 266 public void visitMethodDef(JCMethodDecl tree) { 267 result = tree.mods.annotations; 268 } 269 public void visitVarDef(JCVariableDecl tree) { 270 result = tree.mods.annotations; 271 } 272 @Override 273 public void visitTypeParameter(JCTypeParameter tree) { 274 result = tree.annotations; 275 } 276 } 277 Vis vis = new Vis(); 278 tree.accept(vis); 279 if (vis.result == null) 280 return null; 281 282 List<Attribute.Compound> annos = sym.getAnnotationMirrors(); 283 return matchAnnoToTree(cast(Attribute.Compound.class, findme), 284 annos, 285 vis.result); 286 } 287 288 /** 289 * Returns the tree for an annotation given a list of annotations 290 * in which to search (recursively) and their corresponding trees. 291 * Returns null if the tree cannot be found. 292 */ 293 private JCTree matchAnnoToTree(Attribute.Compound findme, 294 List<Attribute.Compound> annos, 295 List<JCAnnotation> trees) { 296 for (Attribute.Compound anno : annos) { 297 for (JCAnnotation tree : trees) { 298 JCTree match = matchAnnoToTree(findme, anno, tree); 299 if (match != null) 300 return match; 301 } 302 } 303 return null; 304 } 305 306 /** 307 * Returns the tree for an annotation given an Attribute to 308 * search (recursively) and its corresponding tree. 309 * Returns null if the tree cannot be found. 310 */ 311 private JCTree matchAnnoToTree(final Attribute.Compound findme, 312 final Attribute attr, 313 final JCTree tree) { 314 if (attr == findme) 315 return (tree.type.tsym == findme.type.tsym) ? tree : null; 316 317 class Vis implements Attribute.Visitor { 318 JCTree result = null; 319 public void visitConstant(Attribute.Constant value) { 320 } 321 public void visitClass(Attribute.Class clazz) { 322 } 323 public void visitCompound(Attribute.Compound anno) { 324 for (Pair<MethodSymbol, Attribute> pair : anno.values) { 325 JCExpression expr = scanForAssign(pair.fst, tree); 326 if (expr != null) { 327 JCTree match = matchAnnoToTree(findme, pair.snd, expr); 328 if (match != null) { 329 result = match; 330 return; 331 } 332 } 333 } 334 } 335 public void visitArray(Attribute.Array array) { 336 if (tree.hasTag(NEWARRAY) && 337 types.elemtype(array.type).tsym == findme.type.tsym) { 338 List<JCExpression> elems = ((JCNewArray) tree).elems; 339 for (Attribute value : array.values) { 340 if (value == findme) { 341 result = elems.head; 342 return; 343 } 344 elems = elems.tail; 345 } 346 } 347 } 348 public void visitEnum(Attribute.Enum e) { 349 } 350 public void visitError(Attribute.Error e) { 351 } 352 } 353 Vis vis = new Vis(); 354 attr.accept(vis); 355 return vis.result; 356 } 357 358 /** 359 * Scans for a JCAssign node with a LHS matching a given 360 * symbol, and returns its RHS. Does not scan nested JCAnnotations. 361 */ 362 private JCExpression scanForAssign(final MethodSymbol sym, 363 final JCTree tree) { 364 class TS extends TreeScanner { 365 JCExpression result = null; 366 public void scan(JCTree t) { 367 if (t != null && result == null) 368 t.accept(this); 369 } 370 public void visitAnnotation(JCAnnotation t) { 371 if (t == tree) 372 scan(t.args); 373 } 374 public void visitAssign(JCAssign t) { 375 if (t.lhs.hasTag(IDENT)) { 376 JCIdent ident = (JCIdent) t.lhs; 377 if (ident.sym == sym) 378 result = t.rhs; 379 } 380 } 381 } 382 TS scanner = new TS(); 383 tree.accept(scanner); 384 return scanner.result; 385 } 386 387 /** 388 * Returns the tree node corresponding to this element, or null 389 * if none can be found. 390 */ 391 public JCTree getTree(Element e) { 392 Pair<JCTree, ?> treeTop = getTreeAndTopLevel(e); 393 return (treeTop != null) ? treeTop.fst : null; 394 } 395 396 @DefinedBy(Api.LANGUAGE_MODEL) 397 public String getDocComment(Element e) { 398 // Our doc comment is contained in a map in our toplevel, 399 // indexed by our tree. Find our enter environment, which gives 400 // us our toplevel. It also gives us a tree that contains our 401 // tree: walk it to find our tree. This is painful. 402 Pair<JCTree, JCCompilationUnit> treeTop = getTreeAndTopLevel(e); 403 if (treeTop == null) 404 return null; 405 JCTree tree = treeTop.fst; 406 JCCompilationUnit toplevel = treeTop.snd; 407 if (toplevel.docComments == null) 408 return null; 409 return toplevel.docComments.getCommentText(tree); 410 } 411 412 @DefinedBy(Api.LANGUAGE_MODEL) 413 public PackageElement getPackageOf(Element e) { 414 return cast(Symbol.class, e).packge(); 415 } 416 417 @DefinedBy(Api.LANGUAGE_MODEL) 418 public ModuleElement getModuleOf(Element e) { 419 Symbol sym = cast(Symbol.class, e); 420 if (modules.getDefaultModule() == syms.noModule) 421 return null; 422 return (sym.kind == MDL) ? ((ModuleElement) e) : sym.packge().modle; 423 } 424 425 @DefinedBy(Api.LANGUAGE_MODEL) 426 public boolean isDeprecated(Element e) { 427 Symbol sym = cast(Symbol.class, e); 428 sym.complete(); 429 return sym.isDeprecated(); 430 } 431 432 @Override @DefinedBy(Api.LANGUAGE_MODEL) 433 public Origin getOrigin(Element e) { 434 Symbol sym = cast(Symbol.class, e); 435 if ((sym.flags() & Flags.GENERATEDCONSTR) != 0) 436 return Origin.MANDATED; 437 //TypeElement.getEnclosedElements does not return synthetic elements, 438 //and most synthetic elements are not read from the classfile anyway: 439 return Origin.EXPLICIT; 440 } 441 442 @Override @DefinedBy(Api.LANGUAGE_MODEL) 443 public Origin getOrigin(AnnotatedConstruct c, AnnotationMirror a) { 444 Compound ac = cast(Compound.class, a); 445 if (ac.isSynthesized()) 446 return Origin.MANDATED; 447 return Origin.EXPLICIT; 448 } 449 450 @Override @DefinedBy(Api.LANGUAGE_MODEL) 451 public Origin getOrigin(ModuleElement m, ModuleElement.Directive directive) { 452 switch (directive.getKind()) { 453 case REQUIRES: 454 RequiresDirective rd = cast(RequiresDirective.class, directive); 455 if (rd.flags.contains(RequiresFlag.MANDATED)) 456 return Origin.MANDATED; 457 if (rd.flags.contains(RequiresFlag.SYNTHETIC)) 458 return Origin.SYNTHETIC; 459 return Origin.EXPLICIT; 460 case EXPORTS: 461 ExportsDirective ed = cast(ExportsDirective.class, directive); 462 if (ed.flags.contains(ExportsFlag.MANDATED)) 463 return Origin.MANDATED; 464 if (ed.flags.contains(ExportsFlag.SYNTHETIC)) 465 return Origin.SYNTHETIC; 466 return Origin.EXPLICIT; 467 case OPENS: 468 OpensDirective od = cast(OpensDirective.class, directive); 469 if (od.flags.contains(OpensFlag.MANDATED)) 470 return Origin.MANDATED; 471 if (od.flags.contains(OpensFlag.SYNTHETIC)) 472 return Origin.SYNTHETIC; 473 return Origin.EXPLICIT; 474 } 475 return Origin.EXPLICIT; 476 } 477 478 @DefinedBy(Api.LANGUAGE_MODEL) 479 public Name getBinaryName(TypeElement type) { 480 return cast(TypeSymbol.class, type).flatName(); 481 } 482 483 @DefinedBy(Api.LANGUAGE_MODEL) 484 public Map<MethodSymbol, Attribute> getElementValuesWithDefaults( 485 AnnotationMirror a) { 486 Attribute.Compound anno = cast(Attribute.Compound.class, a); 487 DeclaredType annotype = a.getAnnotationType(); 488 Map<MethodSymbol, Attribute> valmap = anno.getElementValues(); 489 490 for (ExecutableElement ex : 491 methodsIn(annotype.asElement().getEnclosedElements())) { 492 MethodSymbol meth = (MethodSymbol) ex; 493 Attribute defaultValue = meth.getDefaultValue(); 494 if (defaultValue != null && !valmap.containsKey(meth)) { 495 valmap.put(meth, defaultValue); 496 } 497 } 498 return valmap; 499 } 500 501 /** 502 * {@inheritDoc} 503 */ 504 @DefinedBy(Api.LANGUAGE_MODEL) 505 public FilteredMemberList getAllMembers(TypeElement element) { 506 Symbol sym = cast(Symbol.class, element); 507 WriteableScope scope = sym.members().dupUnshared(); 508 List<Type> closure = types.closure(sym.asType()); 509 for (Type t : closure) 510 addMembers(scope, t); 511 return new FilteredMemberList(scope); 512 } 513 // where 514 private void addMembers(WriteableScope scope, Type type) { 515 members: 516 for (Symbol e : type.asElement().members().getSymbols(NON_RECURSIVE)) { 517 for (Symbol overrider : scope.getSymbolsByName(e.getSimpleName())) { 518 if (overrider.kind == e.kind && (overrider.flags() & Flags.SYNTHETIC) == 0) { 519 if (overrider.getKind() == ElementKind.METHOD && 520 overrides((ExecutableElement)overrider, (ExecutableElement)e, (TypeElement)type.asElement())) { 521 continue members; 522 } 523 } 524 } 525 boolean derived = e.getEnclosingElement() != scope.owner; 526 ElementKind kind = e.getKind(); 527 boolean initializer = kind == ElementKind.CONSTRUCTOR 528 || kind == ElementKind.INSTANCE_INIT 529 || kind == ElementKind.STATIC_INIT; 530 if (!derived || (!initializer && e.isInheritedIn(scope.owner, types))) 531 scope.enter(e); 532 } 533 } 534 535 /** 536 * Returns all annotations of an element, whether 537 * inherited or directly present. 538 * 539 * @param e the element being examined 540 * @return all annotations of the element 541 */ 542 @Override @DefinedBy(Api.LANGUAGE_MODEL) 543 public List<Attribute.Compound> getAllAnnotationMirrors(Element e) { 544 Symbol sym = cast(Symbol.class, e); 545 List<Attribute.Compound> annos = sym.getAnnotationMirrors(); 546 while (sym.getKind() == ElementKind.CLASS) { 547 Type sup = ((ClassSymbol) sym).getSuperclass(); 548 if (!sup.hasTag(CLASS) || sup.isErroneous() || 549 sup.tsym == syms.objectType.tsym) { 550 break; 551 } 552 sym = sup.tsym; 553 List<Attribute.Compound> oldAnnos = annos; 554 List<Attribute.Compound> newAnnos = sym.getAnnotationMirrors(); 555 for (Attribute.Compound anno : newAnnos) { 556 if (isInherited(anno.type) && 557 !containsAnnoOfType(oldAnnos, anno.type)) { 558 annos = annos.prepend(anno); 559 } 560 } 561 } 562 return annos; 563 } 564 565 /** 566 * Tests whether an annotation type is @Inherited. 567 */ 568 private boolean isInherited(Type annotype) { 569 return annotype.tsym.attribute(syms.inheritedType.tsym) != null; 570 } 571 572 /** 573 * Tests whether a list of annotations contains an annotation 574 * of a given type. 575 */ 576 private static boolean containsAnnoOfType(List<Attribute.Compound> annos, 577 Type type) { 578 for (Attribute.Compound anno : annos) { 579 if (anno.type.tsym == type.tsym) 580 return true; 581 } 582 return false; 583 } 584 585 @DefinedBy(Api.LANGUAGE_MODEL) 586 public boolean hides(Element hiderEl, Element hideeEl) { 587 Symbol hider = cast(Symbol.class, hiderEl); 588 Symbol hidee = cast(Symbol.class, hideeEl); 589 590 // Fields only hide fields; methods only methods; types only types. 591 // Names must match. Nothing hides itself (just try it). 592 if (hider == hidee || 593 hider.kind != hidee.kind || 594 hider.name != hidee.name) { 595 return false; 596 } 597 598 // Only static methods can hide other methods. 599 // Methods only hide methods with matching signatures. 600 if (hider.kind == MTH) { 601 if (!hider.isStatic() || 602 !types.isSubSignature(hider.type, hidee.type)) { 603 return false; 604 } 605 } 606 607 // Hider must be in a subclass of hidee's class. 608 // Note that if M1 hides M2, and M2 hides M3, and M3 is accessible 609 // in M1's class, then M1 and M2 both hide M3. 610 ClassSymbol hiderClass = hider.owner.enclClass(); 611 ClassSymbol hideeClass = hidee.owner.enclClass(); 612 if (hiderClass == null || hideeClass == null || 613 !hiderClass.isSubClass(hideeClass, types)) { 614 return false; 615 } 616 617 // Hidee must be accessible in hider's class. 618 // The method isInheritedIn is poorly named: it checks only access. 619 return hidee.isInheritedIn(hiderClass, types); 620 } 621 622 @DefinedBy(Api.LANGUAGE_MODEL) 623 public boolean overrides(ExecutableElement riderEl, 624 ExecutableElement rideeEl, TypeElement typeEl) { 625 MethodSymbol rider = cast(MethodSymbol.class, riderEl); 626 MethodSymbol ridee = cast(MethodSymbol.class, rideeEl); 627 ClassSymbol origin = cast(ClassSymbol.class, typeEl); 628 629 return rider.name == ridee.name && 630 631 // not reflexive as per JLS 632 rider != ridee && 633 634 // we don't care if ridee is static, though that wouldn't 635 // compile 636 !rider.isStatic() && 637 638 // Symbol.overrides assumes the following 639 ridee.isMemberOf(origin, types) && 640 641 // check access and signatures; don't check return types 642 rider.overrides(ridee, origin, types, false); 643 } 644 645 @DefinedBy(Api.LANGUAGE_MODEL) 646 public String getConstantExpression(Object value) { 647 return Constants.format(value); 648 } 649 650 /** 651 * Print a representation of the elements to the given writer in 652 * the specified order. The main purpose of this method is for 653 * diagnostics. The exact format of the output is <em>not</em> 654 * specified and is subject to change. 655 * 656 * @param w the writer to print the output to 657 * @param elements the elements to print 658 */ 659 @DefinedBy(Api.LANGUAGE_MODEL) 660 public void printElements(java.io.Writer w, Element... elements) { 661 for (Element element : elements) 662 (new PrintingProcessor.PrintingElementVisitor(w, this)).visit(element).flush(); 663 } 664 665 @DefinedBy(Api.LANGUAGE_MODEL) 666 public Name getName(CharSequence cs) { 667 return names.fromString(cs.toString()); 668 } 669 670 @Override @DefinedBy(Api.LANGUAGE_MODEL) 671 public boolean isFunctionalInterface(TypeElement element) { 672 if (element.getKind() != ElementKind.INTERFACE) 673 return false; 674 else { 675 TypeSymbol tsym = cast(TypeSymbol.class, element); 676 return types.isFunctionalInterface(tsym); 677 } 678 } 679 680 /** 681 * Returns the tree node and compilation unit corresponding to this 682 * element, or null if they can't be found. 683 */ 684 private Pair<JCTree, JCCompilationUnit> getTreeAndTopLevel(Element e) { 685 Symbol sym = cast(Symbol.class, e); 686 Env<AttrContext> enterEnv = getEnterEnv(sym); 687 if (enterEnv == null) 688 return null; 689 JCTree tree = TreeInfo.declarationFor(sym, enterEnv.tree); 690 if (tree == null || enterEnv.toplevel == null) 691 return null; 692 return new Pair<>(tree, enterEnv.toplevel); 693 } 694 695 /** 696 * Returns the best approximation for the tree node and compilation unit 697 * corresponding to the given element, annotation and value. 698 * If the element is null, null is returned. 699 * If the annotation is null or cannot be found, the tree node and 700 * compilation unit for the element is returned. 701 * If the annotation value is null or cannot be found, the tree node and 702 * compilation unit for the annotation is returned. 703 */ 704 public Pair<JCTree, JCCompilationUnit> getTreeAndTopLevel( 705 Element e, AnnotationMirror a, AnnotationValue v) { 706 if (e == null) 707 return null; 708 709 Pair<JCTree, JCCompilationUnit> elemTreeTop = getTreeAndTopLevel(e); 710 if (elemTreeTop == null) 711 return null; 712 713 if (a == null) 714 return elemTreeTop; 715 716 JCTree annoTree = matchAnnoToTree(a, e, elemTreeTop.fst); 717 if (annoTree == null) 718 return elemTreeTop; 719 720 // 6388543: if v != null, we should search within annoTree to find 721 // the tree matching v. For now, we ignore v and return the tree of 722 // the annotation. 723 return new Pair<>(annoTree, elemTreeTop.snd); 724 } 725 726 /** 727 * Returns a symbol's enter environment, or null if it has none. 728 */ 729 private Env<AttrContext> getEnterEnv(Symbol sym) { 730 // Get enclosing class of sym, or sym itself if it is a class 731 // package, or module. 732 TypeSymbol ts = null; 733 switch (sym.kind) { 734 case PCK: 735 ts = (PackageSymbol)sym; 736 break; 737 case MDL: 738 ts = (ModuleSymbol)sym; 739 break; 740 default: 741 ts = sym.enclClass(); 742 } 743 return (ts != null) 744 ? enter.getEnv(ts) 745 : null; 746 } 747 748 private void ensureEntered(String methodName) { 749 if (javacTaskImpl != null) { 750 javacTaskImpl.ensureEntered(); 751 } 752 if (!javaCompiler.isEnterDone()) { 753 throw new IllegalStateException("Cannot use Elements." + methodName + " before the TaskEvent.Kind.ENTER finished event."); 754 } 755 } 756 757 /** 758 * Returns an object cast to the specified type. 759 * @throws NullPointerException if the object is {@code null} 760 * @throws IllegalArgumentException if the object is of the wrong type 761 */ 762 private static <T> T cast(Class<T> clazz, Object o) { 763 if (! clazz.isInstance(o)) 764 throw new IllegalArgumentException(o.toString()); 765 return clazz.cast(o); 766 } 767} 768