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