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 }