JavacElements.java revision 3886:03f48cd283f5
1/*
2 * Copyright (c) 2005, 2017, 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
26package com.sun.tools.javac.model;
27
28import java.util.HashSet;
29import java.util.LinkedHashSet;
30import java.util.Map;
31import java.util.Set;
32import java.util.stream.Collectors;
33
34import javax.lang.model.AnnotatedConstruct;
35import javax.lang.model.SourceVersion;
36import javax.lang.model.element.*;
37import javax.lang.model.type.DeclaredType;
38import javax.lang.model.util.Elements;
39import javax.tools.JavaFileObject;
40import static javax.lang.model.util.ElementFilter.methodsIn;
41
42import com.sun.source.util.JavacTask;
43import com.sun.tools.javac.api.JavacTaskImpl;
44import com.sun.tools.javac.code.*;
45import com.sun.tools.javac.code.Attribute.Compound;
46import com.sun.tools.javac.code.Directive.ExportsDirective;
47import com.sun.tools.javac.code.Directive.ExportsFlag;
48import com.sun.tools.javac.code.Directive.OpensDirective;
49import com.sun.tools.javac.code.Directive.OpensFlag;
50import com.sun.tools.javac.code.Directive.RequiresDirective;
51import com.sun.tools.javac.code.Directive.RequiresFlag;
52import com.sun.tools.javac.code.Scope.WriteableScope;
53import com.sun.tools.javac.code.Symbol.*;
54import com.sun.tools.javac.comp.AttrContext;
55import com.sun.tools.javac.comp.Enter;
56import com.sun.tools.javac.comp.Env;
57import com.sun.tools.javac.main.JavaCompiler;
58import com.sun.tools.javac.processing.PrintingProcessor;
59import com.sun.tools.javac.tree.JCTree;
60import com.sun.tools.javac.tree.JCTree.*;
61import com.sun.tools.javac.tree.TreeInfo;
62import com.sun.tools.javac.tree.TreeScanner;
63import com.sun.tools.javac.util.*;
64import com.sun.tools.javac.util.DefinedBy.Api;
65import com.sun.tools.javac.util.Name;
66import static com.sun.tools.javac.code.Kinds.Kind.*;
67import static com.sun.tools.javac.code.Scope.LookupKind.NON_RECURSIVE;
68import static com.sun.tools.javac.code.TypeTag.CLASS;
69import com.sun.tools.javac.comp.Modules;
70import com.sun.tools.javac.comp.Resolve;
71import com.sun.tools.javac.comp.Resolve.RecoveryLoadClass;
72import com.sun.tools.javac.resources.CompilerProperties.Notes;
73import static com.sun.tools.javac.tree.JCTree.Tag.*;
74
75/**
76 * Utility methods for operating on program elements.
77 *
78 * <p><b>This is NOT part of any supported API.
79 * If you write code that depends on this, you do so at your own
80 * risk.  This code and its internal interfaces are subject to change
81 * or deletion without notice.</b></p>
82 */
83public class JavacElements implements Elements {
84
85    private final JavaCompiler javaCompiler;
86    private final Symtab syms;
87    private final Modules modules;
88    private final Names names;
89    private final Types types;
90    private final Enter enter;
91    private final Resolve resolve;
92    private final JavacTaskImpl javacTaskImpl;
93    private final Log log;
94    private final boolean allowModules;
95
96    public static JavacElements instance(Context context) {
97        JavacElements instance = context.get(JavacElements.class);
98        if (instance == null)
99            instance = new JavacElements(context);
100        return instance;
101    }
102
103    protected JavacElements(Context context) {
104        context.put(JavacElements.class, this);
105        javaCompiler = JavaCompiler.instance(context);
106        syms = Symtab.instance(context);
107        modules = Modules.instance(context);
108        names = Names.instance(context);
109        types = Types.instance(context);
110        enter = Enter.instance(context);
111        resolve = Resolve.instance(context);
112        JavacTask t = context.get(JavacTask.class);
113        javacTaskImpl = t instanceof JavacTaskImpl ? (JavacTaskImpl) t : null;
114        log = Log.instance(context);
115        Source source = Source.instance(context);
116        allowModules = source.allowModules();
117    }
118
119    @Override @DefinedBy(Api.LANGUAGE_MODEL)
120    public ModuleSymbol getModuleElement(CharSequence name) {
121        ensureEntered("getModuleElement");
122        if (modules.getDefaultModule() == syms.noModule)
123            return null;
124        String strName = name.toString();
125        if (strName.equals(""))
126            return syms.unnamedModule;
127        return modules.getObservableModule(names.fromString(strName));
128    }
129
130    @Override @DefinedBy(Api.LANGUAGE_MODEL)
131    public PackageSymbol getPackageElement(CharSequence name) {
132        return doGetPackageElement(null, name);
133    }
134
135    @Override @DefinedBy(Api.LANGUAGE_MODEL)
136    public PackageSymbol getPackageElement(ModuleElement module, CharSequence name) {
137        module.getClass();
138        return doGetPackageElement(module, name);
139    }
140
141    private PackageSymbol doGetPackageElement(ModuleElement module, CharSequence name) {
142        ensureEntered("getPackageElement");
143        if (name.length() == 0)
144            return syms.unnamedModule.unnamedPackage;
145        return doGetElement(module, "getPackageElement", name, PackageSymbol.class);
146    }
147
148    @Override @DefinedBy(Api.LANGUAGE_MODEL)
149    public ClassSymbol getTypeElement(CharSequence name) {
150        return doGetTypeElement(null, name);
151    }
152
153    @Override @DefinedBy(Api.LANGUAGE_MODEL)
154    public ClassSymbol getTypeElement(ModuleElement module, CharSequence name) {
155        module.getClass();
156
157        return doGetTypeElement(module, name);
158    }
159
160    private ClassSymbol doGetTypeElement(ModuleElement module, CharSequence name) {
161        ensureEntered("getTypeElement");
162        return doGetElement(module, "getTypeElement", name, ClassSymbol.class);
163    }
164
165    private <S extends Symbol> S doGetElement(ModuleElement module, String methodName,
166                                              CharSequence name, Class<S> clazz) {
167        String strName = name.toString();
168        if (!SourceVersion.isName(strName)) {
169            return null;
170        }
171        if (module == null) {
172            return unboundNameToSymbol(methodName, strName, clazz);
173        } else {
174            return nameToSymbol((ModuleSymbol) module, strName, clazz);
175        }
176    }
177
178    private final Set<String> alreadyWarnedDuplicates = new HashSet<>();
179
180    private <S extends Symbol> S unboundNameToSymbol(String methodName,
181                                                     String nameStr,
182                                                     Class<S> clazz) {
183        if (modules.getDefaultModule() == syms.noModule) { //not a modular mode:
184            return nameToSymbol(syms.noModule, nameStr, clazz);
185        }
186
187        RecoveryLoadClass prevRecoveryLoadClass = resolve.setRecoveryLoadClass((env, name) -> null);
188        try {
189            Set<S> found = new LinkedHashSet<>();
190
191            for (ModuleSymbol msym : modules.allModules()) {
192                S sym = nameToSymbol(msym, nameStr, clazz);
193
194                if (sym != null) {
195                    if (!allowModules || clazz == ClassSymbol.class || !sym.members().isEmpty()) {
196                        //do not add packages without members:
197                        found.add(sym);
198                    }
199                }
200            }
201
202            if (found.size() == 1) {
203                return found.iterator().next();
204            } else if (found.size() > 1) {
205                //more than one element found, produce a note:
206                if (alreadyWarnedDuplicates.add(methodName + ":" + nameStr)) {
207                    String moduleNames = found.stream()
208                                              .map(s -> s.packge().modle)
209                                              .map(m -> m.toString())
210                                              .collect(Collectors.joining(", "));
211                    log.note(Notes.MultipleElements(methodName, nameStr, moduleNames));
212                }
213                return null;
214            } else {
215                //not found, or more than one element found:
216                return null;
217            }
218        } finally {
219            resolve.setRecoveryLoadClass(prevRecoveryLoadClass);
220        }
221    }
222
223    /**
224     * Returns a symbol given the type's or package's canonical name,
225     * or null if the name isn't found.
226     */
227    private <S extends Symbol> S nameToSymbol(ModuleSymbol module, String nameStr, Class<S> clazz) {
228        Name name = names.fromString(nameStr);
229        // First check cache.
230        Symbol sym = (clazz == ClassSymbol.class)
231                    ? syms.getClass(module, name)
232                    : syms.lookupPackage(module, name);
233
234        try {
235            if (sym == null)
236                sym = javaCompiler.resolveIdent(module, nameStr);
237
238            sym.complete();
239
240            return (sym.kind != ERR &&
241                    sym.exists() &&
242                    clazz.isInstance(sym) &&
243                    name.equals(sym.getQualifiedName()))
244                ? clazz.cast(sym)
245                : null;
246        } catch (CompletionFailure e) {
247            return null;
248        }
249    }
250
251    /**
252     * Returns the tree for an annotation given the annotated element
253     * and the element's own tree.  Returns null if the tree cannot be found.
254     */
255    private JCTree matchAnnoToTree(AnnotationMirror findme,
256                                   Element e, JCTree tree) {
257        Symbol sym = cast(Symbol.class, e);
258        class Vis extends JCTree.Visitor {
259            List<JCAnnotation> result = null;
260            public void visitPackageDef(JCPackageDecl tree) {
261                result = tree.annotations;
262            }
263            public void visitClassDef(JCClassDecl tree) {
264                result = tree.mods.annotations;
265            }
266            public void visitMethodDef(JCMethodDecl tree) {
267                result = tree.mods.annotations;
268            }
269            public void visitVarDef(JCVariableDecl tree) {
270                result = tree.mods.annotations;
271            }
272            @Override
273            public void visitTypeParameter(JCTypeParameter tree) {
274                result = tree.annotations;
275            }
276        }
277        Vis vis = new Vis();
278        tree.accept(vis);
279        if (vis.result == null)
280            return null;
281
282        List<Attribute.Compound> annos = sym.getAnnotationMirrors();
283        return matchAnnoToTree(cast(Attribute.Compound.class, findme),
284                               annos,
285                               vis.result);
286    }
287
288    /**
289     * Returns the tree for an annotation given a list of annotations
290     * in which to search (recursively) and their corresponding trees.
291     * Returns null if the tree cannot be found.
292     */
293    private JCTree matchAnnoToTree(Attribute.Compound findme,
294                                   List<Attribute.Compound> annos,
295                                   List<JCAnnotation> trees) {
296        for (Attribute.Compound anno : annos) {
297            for (JCAnnotation tree : trees) {
298                JCTree match = matchAnnoToTree(findme, anno, tree);
299                if (match != null)
300                    return match;
301            }
302        }
303        return null;
304    }
305
306    /**
307     * Returns the tree for an annotation given an Attribute to
308     * search (recursively) and its corresponding tree.
309     * Returns null if the tree cannot be found.
310     */
311    private JCTree matchAnnoToTree(final Attribute.Compound findme,
312                                   final Attribute attr,
313                                   final JCTree tree) {
314        if (attr == findme)
315            return (tree.type.tsym == findme.type.tsym) ? tree : null;
316
317        class Vis implements Attribute.Visitor {
318            JCTree result = null;
319            public void visitConstant(Attribute.Constant value) {
320            }
321            public void visitClass(Attribute.Class clazz) {
322            }
323            public void visitCompound(Attribute.Compound anno) {
324                for (Pair<MethodSymbol, Attribute> pair : anno.values) {
325                    JCExpression expr = scanForAssign(pair.fst, tree);
326                    if (expr != null) {
327                        JCTree match = matchAnnoToTree(findme, pair.snd, expr);
328                        if (match != null) {
329                            result = match;
330                            return;
331                        }
332                    }
333                }
334            }
335            public void visitArray(Attribute.Array array) {
336                if (tree.hasTag(NEWARRAY) &&
337                        types.elemtype(array.type).tsym == findme.type.tsym) {
338                    List<JCExpression> elems = ((JCNewArray) tree).elems;
339                    for (Attribute value : array.values) {
340                        if (value == findme) {
341                            result = elems.head;
342                            return;
343                        }
344                        elems = elems.tail;
345                    }
346                }
347            }
348            public void visitEnum(Attribute.Enum e) {
349            }
350            public void visitError(Attribute.Error e) {
351            }
352        }
353        Vis vis = new Vis();
354        attr.accept(vis);
355        return vis.result;
356    }
357
358    /**
359     * Scans for a JCAssign node with a LHS matching a given
360     * symbol, and returns its RHS.  Does not scan nested JCAnnotations.
361     */
362    private JCExpression scanForAssign(final MethodSymbol sym,
363                                       final JCTree tree) {
364        class TS extends TreeScanner {
365            JCExpression result = null;
366            public void scan(JCTree t) {
367                if (t != null && result == null)
368                    t.accept(this);
369            }
370            public void visitAnnotation(JCAnnotation t) {
371                if (t == tree)
372                    scan(t.args);
373            }
374            public void visitAssign(JCAssign t) {
375                if (t.lhs.hasTag(IDENT)) {
376                    JCIdent ident = (JCIdent) t.lhs;
377                    if (ident.sym == sym)
378                        result = t.rhs;
379                }
380            }
381        }
382        TS scanner = new TS();
383        tree.accept(scanner);
384        return scanner.result;
385    }
386
387    /**
388     * Returns the tree node corresponding to this element, or null
389     * if none can be found.
390     */
391    public JCTree getTree(Element e) {
392        Pair<JCTree, ?> treeTop = getTreeAndTopLevel(e);
393        return (treeTop != null) ? treeTop.fst : null;
394    }
395
396    @DefinedBy(Api.LANGUAGE_MODEL)
397    public String getDocComment(Element e) {
398        // Our doc comment is contained in a map in our toplevel,
399        // indexed by our tree.  Find our enter environment, which gives
400        // us our toplevel.  It also gives us a tree that contains our
401        // tree:  walk it to find our tree.  This is painful.
402        Pair<JCTree, JCCompilationUnit> treeTop = getTreeAndTopLevel(e);
403        if (treeTop == null)
404            return null;
405        JCTree tree = treeTop.fst;
406        JCCompilationUnit toplevel = treeTop.snd;
407        if (toplevel.docComments == null)
408            return null;
409        return toplevel.docComments.getCommentText(tree);
410    }
411
412    @DefinedBy(Api.LANGUAGE_MODEL)
413    public PackageElement getPackageOf(Element e) {
414        return cast(Symbol.class, e).packge();
415    }
416
417    @DefinedBy(Api.LANGUAGE_MODEL)
418    public ModuleElement getModuleOf(Element e) {
419        Symbol sym = cast(Symbol.class, e);
420        if (modules.getDefaultModule() == syms.noModule)
421            return null;
422        return (sym.kind == MDL) ? ((ModuleElement) e) : sym.packge().modle;
423    }
424
425    @DefinedBy(Api.LANGUAGE_MODEL)
426    public boolean isDeprecated(Element e) {
427        Symbol sym = cast(Symbol.class, e);
428        sym.complete();
429        return sym.isDeprecated();
430    }
431
432    @Override @DefinedBy(Api.LANGUAGE_MODEL)
433    public Origin getOrigin(Element e) {
434        Symbol sym = cast(Symbol.class, e);
435        if ((sym.flags() & Flags.GENERATEDCONSTR) != 0)
436            return Origin.MANDATED;
437        //TypeElement.getEnclosedElements does not return synthetic elements,
438        //and most synthetic elements are not read from the classfile anyway:
439        return Origin.EXPLICIT;
440    }
441
442    @Override @DefinedBy(Api.LANGUAGE_MODEL)
443    public Origin getOrigin(AnnotatedConstruct c, AnnotationMirror a) {
444        Compound ac = cast(Compound.class, a);
445        if (ac.isSynthesized())
446            return Origin.MANDATED;
447        return Origin.EXPLICIT;
448    }
449
450    @Override @DefinedBy(Api.LANGUAGE_MODEL)
451    public Origin getOrigin(ModuleElement m, ModuleElement.Directive directive) {
452        switch (directive.getKind()) {
453            case REQUIRES:
454                RequiresDirective rd = cast(RequiresDirective.class, directive);
455                if (rd.flags.contains(RequiresFlag.MANDATED))
456                    return Origin.MANDATED;
457                if (rd.flags.contains(RequiresFlag.SYNTHETIC))
458                    return Origin.SYNTHETIC;
459                return Origin.EXPLICIT;
460            case EXPORTS:
461                ExportsDirective ed = cast(ExportsDirective.class, directive);
462                if (ed.flags.contains(ExportsFlag.MANDATED))
463                    return Origin.MANDATED;
464                if (ed.flags.contains(ExportsFlag.SYNTHETIC))
465                    return Origin.SYNTHETIC;
466                return Origin.EXPLICIT;
467            case OPENS:
468                OpensDirective od = cast(OpensDirective.class, directive);
469                if (od.flags.contains(OpensFlag.MANDATED))
470                    return Origin.MANDATED;
471                if (od.flags.contains(OpensFlag.SYNTHETIC))
472                    return Origin.SYNTHETIC;
473                return Origin.EXPLICIT;
474        }
475        return Origin.EXPLICIT;
476    }
477
478    @DefinedBy(Api.LANGUAGE_MODEL)
479    public Name getBinaryName(TypeElement type) {
480        return cast(TypeSymbol.class, type).flatName();
481    }
482
483    @DefinedBy(Api.LANGUAGE_MODEL)
484    public Map<MethodSymbol, Attribute> getElementValuesWithDefaults(
485                                                        AnnotationMirror a) {
486        Attribute.Compound anno = cast(Attribute.Compound.class, a);
487        DeclaredType annotype = a.getAnnotationType();
488        Map<MethodSymbol, Attribute> valmap = anno.getElementValues();
489
490        for (ExecutableElement ex :
491                 methodsIn(annotype.asElement().getEnclosedElements())) {
492            MethodSymbol meth = (MethodSymbol) ex;
493            Attribute defaultValue = meth.getDefaultValue();
494            if (defaultValue != null && !valmap.containsKey(meth)) {
495                valmap.put(meth, defaultValue);
496            }
497        }
498        return valmap;
499    }
500
501    /**
502     * {@inheritDoc}
503     */
504    @DefinedBy(Api.LANGUAGE_MODEL)
505    public FilteredMemberList getAllMembers(TypeElement element) {
506        Symbol sym = cast(Symbol.class, element);
507        WriteableScope scope = sym.members().dupUnshared();
508        List<Type> closure = types.closure(sym.asType());
509        for (Type t : closure)
510            addMembers(scope, t);
511        return new FilteredMemberList(scope);
512    }
513    // where
514        private void addMembers(WriteableScope scope, Type type) {
515            members:
516            for (Symbol e : type.asElement().members().getSymbols(NON_RECURSIVE)) {
517                for (Symbol overrider : scope.getSymbolsByName(e.getSimpleName())) {
518                    if (overrider.kind == e.kind && (overrider.flags() & Flags.SYNTHETIC) == 0) {
519                        if (overrider.getKind() == ElementKind.METHOD &&
520                                overrides((ExecutableElement)overrider, (ExecutableElement)e, (TypeElement)type.asElement())) {
521                            continue members;
522                        }
523                    }
524                }
525                boolean derived = e.getEnclosingElement() != scope.owner;
526                ElementKind kind = e.getKind();
527                boolean initializer = kind == ElementKind.CONSTRUCTOR
528                    || kind == ElementKind.INSTANCE_INIT
529                    || kind == ElementKind.STATIC_INIT;
530                if (!derived || (!initializer && e.isInheritedIn(scope.owner, types)))
531                    scope.enter(e);
532            }
533        }
534
535    /**
536     * Returns all annotations of an element, whether
537     * inherited or directly present.
538     *
539     * @param e  the element being examined
540     * @return all annotations of the element
541     */
542    @Override @DefinedBy(Api.LANGUAGE_MODEL)
543    public List<Attribute.Compound> getAllAnnotationMirrors(Element e) {
544        Symbol sym = cast(Symbol.class, e);
545        List<Attribute.Compound> annos = sym.getAnnotationMirrors();
546        while (sym.getKind() == ElementKind.CLASS) {
547            Type sup = ((ClassSymbol) sym).getSuperclass();
548            if (!sup.hasTag(CLASS) || sup.isErroneous() ||
549                    sup.tsym == syms.objectType.tsym) {
550                break;
551            }
552            sym = sup.tsym;
553            List<Attribute.Compound> oldAnnos = annos;
554            List<Attribute.Compound> newAnnos = sym.getAnnotationMirrors();
555            for (Attribute.Compound anno : newAnnos) {
556                if (isInherited(anno.type) &&
557                        !containsAnnoOfType(oldAnnos, anno.type)) {
558                    annos = annos.prepend(anno);
559                }
560            }
561        }
562        return annos;
563    }
564
565    /**
566     * Tests whether an annotation type is @Inherited.
567     */
568    private boolean isInherited(Type annotype) {
569        return annotype.tsym.attribute(syms.inheritedType.tsym) != null;
570    }
571
572    /**
573     * Tests whether a list of annotations contains an annotation
574     * of a given type.
575     */
576    private static boolean containsAnnoOfType(List<Attribute.Compound> annos,
577                                              Type type) {
578        for (Attribute.Compound anno : annos) {
579            if (anno.type.tsym == type.tsym)
580                return true;
581        }
582        return false;
583    }
584
585    @DefinedBy(Api.LANGUAGE_MODEL)
586    public boolean hides(Element hiderEl, Element hideeEl) {
587        Symbol hider = cast(Symbol.class, hiderEl);
588        Symbol hidee = cast(Symbol.class, hideeEl);
589
590        // Fields only hide fields; methods only methods; types only types.
591        // Names must match.  Nothing hides itself (just try it).
592        if (hider == hidee ||
593                hider.kind != hidee.kind ||
594                hider.name != hidee.name) {
595            return false;
596        }
597
598        // Only static methods can hide other methods.
599        // Methods only hide methods with matching signatures.
600        if (hider.kind == MTH) {
601            if (!hider.isStatic() ||
602                        !types.isSubSignature(hider.type, hidee.type)) {
603                return false;
604            }
605        }
606
607        // Hider must be in a subclass of hidee's class.
608        // Note that if M1 hides M2, and M2 hides M3, and M3 is accessible
609        // in M1's class, then M1 and M2 both hide M3.
610        ClassSymbol hiderClass = hider.owner.enclClass();
611        ClassSymbol hideeClass = hidee.owner.enclClass();
612        if (hiderClass == null || hideeClass == null ||
613                !hiderClass.isSubClass(hideeClass, types)) {
614            return false;
615        }
616
617        // Hidee must be accessible in hider's class.
618        // The method isInheritedIn is poorly named:  it checks only access.
619        return hidee.isInheritedIn(hiderClass, types);
620    }
621
622    @DefinedBy(Api.LANGUAGE_MODEL)
623    public boolean overrides(ExecutableElement riderEl,
624                             ExecutableElement rideeEl, TypeElement typeEl) {
625        MethodSymbol rider = cast(MethodSymbol.class, riderEl);
626        MethodSymbol ridee = cast(MethodSymbol.class, rideeEl);
627        ClassSymbol origin = cast(ClassSymbol.class, typeEl);
628
629        return rider.name == ridee.name &&
630
631               // not reflexive as per JLS
632               rider != ridee &&
633
634               // we don't care if ridee is static, though that wouldn't
635               // compile
636               !rider.isStatic() &&
637
638               // Symbol.overrides assumes the following
639               ridee.isMemberOf(origin, types) &&
640
641               // check access and signatures; don't check return types
642               rider.overrides(ridee, origin, types, false);
643    }
644
645    @DefinedBy(Api.LANGUAGE_MODEL)
646    public String getConstantExpression(Object value) {
647        return Constants.format(value);
648    }
649
650    /**
651     * Print a representation of the elements to the given writer in
652     * the specified order.  The main purpose of this method is for
653     * diagnostics.  The exact format of the output is <em>not</em>
654     * specified and is subject to change.
655     *
656     * @param w the writer to print the output to
657     * @param elements the elements to print
658     */
659    @DefinedBy(Api.LANGUAGE_MODEL)
660    public void printElements(java.io.Writer w, Element... elements) {
661        for (Element element : elements)
662            (new PrintingProcessor.PrintingElementVisitor(w, this)).visit(element).flush();
663    }
664
665    @DefinedBy(Api.LANGUAGE_MODEL)
666    public Name getName(CharSequence cs) {
667        return names.fromString(cs.toString());
668    }
669
670    @Override @DefinedBy(Api.LANGUAGE_MODEL)
671    public boolean isFunctionalInterface(TypeElement element) {
672        if (element.getKind() != ElementKind.INTERFACE)
673            return false;
674        else {
675            TypeSymbol tsym = cast(TypeSymbol.class, element);
676            return types.isFunctionalInterface(tsym);
677        }
678    }
679
680    /**
681     * Returns the tree node and compilation unit corresponding to this
682     * element, or null if they can't be found.
683     */
684    private Pair<JCTree, JCCompilationUnit> getTreeAndTopLevel(Element e) {
685        Symbol sym = cast(Symbol.class, e);
686        Env<AttrContext> enterEnv = getEnterEnv(sym);
687        if (enterEnv == null)
688            return null;
689        JCTree tree = TreeInfo.declarationFor(sym, enterEnv.tree);
690        if (tree == null || enterEnv.toplevel == null)
691            return null;
692        return new Pair<>(tree, enterEnv.toplevel);
693    }
694
695    /**
696     * Returns the best approximation for the tree node and compilation unit
697     * corresponding to the given element, annotation and value.
698     * If the element is null, null is returned.
699     * If the annotation is null or cannot be found, the tree node and
700     * compilation unit for the element is returned.
701     * If the annotation value is null or cannot be found, the tree node and
702     * compilation unit for the annotation is returned.
703     */
704    public Pair<JCTree, JCCompilationUnit> getTreeAndTopLevel(
705                      Element e, AnnotationMirror a, AnnotationValue v) {
706        if (e == null)
707            return null;
708
709        Pair<JCTree, JCCompilationUnit> elemTreeTop = getTreeAndTopLevel(e);
710        if (elemTreeTop == null)
711            return null;
712
713        if (a == null)
714            return elemTreeTop;
715
716        JCTree annoTree = matchAnnoToTree(a, e, elemTreeTop.fst);
717        if (annoTree == null)
718            return elemTreeTop;
719
720        // 6388543: if v != null, we should search within annoTree to find
721        // the tree matching v. For now, we ignore v and return the tree of
722        // the annotation.
723        return new Pair<>(annoTree, elemTreeTop.snd);
724    }
725
726    /**
727     * Returns a symbol's enter environment, or null if it has none.
728     */
729    private Env<AttrContext> getEnterEnv(Symbol sym) {
730        // Get enclosing class of sym, or sym itself if it is a class
731        // package, or module.
732        TypeSymbol ts = null;
733        switch (sym.kind) {
734            case PCK:
735                ts = (PackageSymbol)sym;
736                break;
737            case MDL:
738                ts = (ModuleSymbol)sym;
739                break;
740            default:
741                ts = sym.enclClass();
742        }
743        return (ts != null)
744                ? enter.getEnv(ts)
745                : null;
746    }
747
748    private void ensureEntered(String methodName) {
749        if (javacTaskImpl != null) {
750            javacTaskImpl.ensureEntered();
751        }
752        if (!javaCompiler.isEnterDone()) {
753            throw new IllegalStateException("Cannot use Elements." + methodName + " before the TaskEvent.Kind.ENTER finished event.");
754        }
755    }
756
757    /**
758     * Returns an object cast to the specified type.
759     * @throws NullPointerException if the object is {@code null}
760     * @throws IllegalArgumentException if the object is of the wrong type
761     */
762    private static <T> T cast(Class<T> clazz, Object o) {
763        if (! clazz.isInstance(o))
764            throw new IllegalArgumentException(o.toString());
765        return clazz.cast(o);
766    }
767}
768