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