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