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 }