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