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