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