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