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