DocEnv.java revision 3896:8e4dbcb99277
1104477Ssam/*
2104477Ssam * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
3104477Ssam * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4139749Simp *
5104477Ssam * This code is free software; you can redistribute it and/or modify it
6104477Ssam * under the terms of the GNU General Public License version 2 only, as
7104477Ssam * published by the Free Software Foundation.  Oracle designates this
8104477Ssam * particular file as subject to the "Classpath" exception as provided
9104477Ssam * by Oracle in the LICENSE file that accompanied this code.
10104477Ssam *
11104477Ssam * This code is distributed in the hope that it will be useful, but WITHOUT
12104477Ssam * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13104477Ssam * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14104477Ssam * version 2 for more details (a copy is included in the LICENSE file that
15104477Ssam * accompanied this code).
16104477Ssam *
17104477Ssam * You should have received a copy of the GNU General Public License version
18104477Ssam * 2 along with this work; if not, write to the Free Software Foundation,
19104477Ssam * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20104477Ssam *
21104477Ssam * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22104477Ssam * or visit www.oracle.com if you need additional information or have any
23104477Ssam * questions.
24104477Ssam */
25104477Ssam
26104477Ssampackage com.sun.tools.javadoc.main;
27104477Ssam
28104477Ssamimport java.lang.reflect.Modifier;
29104477Ssamimport java.util.*;
30104477Ssam
31104477Ssamimport javax.tools.JavaFileManager;
32104477Ssam
33104477Ssamimport com.sun.javadoc.*;
34104477Ssamimport com.sun.source.tree.CompilationUnitTree;
35104477Ssamimport com.sun.source.util.JavacTask;
36104477Ssamimport com.sun.source.util.TreePath;
37104477Ssamimport com.sun.tools.doclint.DocLint;
38104477Ssamimport com.sun.tools.javac.api.BasicJavacTask;
39104477Ssamimport com.sun.tools.javac.code.*;
40104477Ssamimport com.sun.tools.javac.code.Symbol.*;
41104477Ssamimport com.sun.tools.javac.code.Symbol.ClassSymbol;
42104477Ssamimport com.sun.tools.javac.code.Symbol.CompletionFailure;
43104477Ssamimport com.sun.tools.javac.code.Symbol.MethodSymbol;
44104477Ssamimport com.sun.tools.javac.code.Symbol.PackageSymbol;
45104477Ssamimport com.sun.tools.javac.code.Symbol.VarSymbol;
46104477Ssamimport com.sun.tools.javac.code.Type.ClassType;
47104477Ssamimport com.sun.tools.javac.comp.Check;
48104477Ssamimport com.sun.tools.javac.comp.Enter;
49104477Ssamimport com.sun.tools.javac.file.JavacFileManager;
50104477Ssamimport com.sun.tools.javac.tree.JCTree;
51104477Ssamimport com.sun.tools.javac.tree.JCTree.JCClassDecl;
52104477Ssamimport com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
53104477Ssamimport com.sun.tools.javac.tree.JCTree.JCPackageDecl;
54104477Ssamimport com.sun.tools.javac.util.Context;
55104477Ssamimport com.sun.tools.javac.util.Convert;
56104477Ssamimport com.sun.tools.javac.util.Name;
57104477Ssamimport com.sun.tools.javac.util.Names;
58104477Ssam
59104477Ssam/**
60104477Ssam * Holds the environment for a run of javadoc.
61104477Ssam * Holds only the information needed throughout the
62104477Ssam * run and not the compiler info that could be GC'ed
63104477Ssam * or ported.
64104477Ssam *
65104477Ssam *  <p><b>This is NOT part of any supported API.
66104477Ssam *  If you write code that depends on this, you do so at your own risk.
67104477Ssam *  This code and its internal interfaces are subject to change or
68104477Ssam *  deletion without notice.</b>
69104477Ssam *
70120915Ssam * @since 1.4
71120915Ssam * @author Robert Field
72104477Ssam * @author Neal Gafter (rewrite)
73104477Ssam * @author Scott Seligman (generics)
74104477Ssam */
75104477Ssam@Deprecated
76104477Ssampublic class DocEnv {
77104477Ssam    protected static final Context.Key<DocEnv> docEnvKey = new Context.Key<>();
78104477Ssam
79104477Ssam    public static DocEnv instance(Context context) {
80104477Ssam        DocEnv instance = context.get(docEnvKey);
81104477Ssam        if (instance == null)
82104477Ssam            instance = new DocEnv(context);
83104477Ssam        return instance;
84213091Sgonzo    }
85213091Sgonzo
86104477Ssam    DocLocale doclocale;
87104477Ssam
88104477Ssam    private final Messager messager;
89104477Ssam
90104477Ssam    /** Predefined symbols known to the compiler. */
91104477Ssam    final Symtab syms;
92104477Ssam
93104477Ssam    /** Referenced directly in RootDocImpl. */
94104477Ssam    private final ClassFinder finder;
95104477Ssam
96104477Ssam    /** Javadoc's own version of the compiler's enter phase. */
97104477Ssam    final Enter enter;
98104477Ssam
99104477Ssam    /** The name table. */
100104477Ssam    private final Names names;
101104477Ssam
102213091Sgonzo    /** The encoding name. */
103104477Ssam    private String encoding;
104104477Ssam
105104477Ssam    final Symbol externalizableSym;
106136526Ssam
107158705Spjd    /** Access filter (public, protected, ...).  */
108120915Ssam    protected ModifierFilter showAccess;
109104477Ssam
110104477Ssam    /** True if we are using a sentence BreakIterator. */
111104477Ssam    boolean breakiterator;
112104477Ssam
113104477Ssam    /**
114104477Ssam     * True if we do not want to print any notifications at all.
115104477Ssam     */
116104477Ssam    boolean quiet = false;
117104477Ssam
118104477Ssam    Check chk;
119104477Ssam    Types types;
120104477Ssam    JavaFileManager fileManager;
121104477Ssam    Context context;
122104477Ssam    DocLint doclint;
123104477Ssam    JavaScriptScanner javaScriptScanner;
124104477Ssam
125104477Ssam    WeakHashMap<JCTree, TreePath> treePaths = new WeakHashMap<>();
126104477Ssam
127104477Ssam    /** Allow documenting from class files? */
128104477Ssam    boolean docClasses = false;
129104477Ssam
130104477Ssam    /** Does the doclet only expect pre-1.5 doclet API? */
131104477Ssam    protected boolean legacyDoclet = true;
132104477Ssam
133104477Ssam    /**
134104477Ssam     * Set this to true if you would like to not emit any errors, warnings and
135104477Ssam     * notices.
136104477Ssam     */
137104477Ssam    private boolean silent = false;
138104477Ssam
139104477Ssam    /**
140104477Ssam     * The source language version.
141104477Ssam     */
142104477Ssam    protected Source source;
143104477Ssam
144104477Ssam    /**
145140480Ssam     * Constructor
146104477Ssam     *
147104477Ssam     * @param context      Context for this javadoc instance.
148104477Ssam     */
149104477Ssam    protected DocEnv(Context context) {
150104477Ssam        context.put(docEnvKey, this);
151104477Ssam        this.context = context;
152213091Sgonzo
153213091Sgonzo        messager = Messager.instance0(context);
154213091Sgonzo        syms = Symtab.instance(context);
155213091Sgonzo        finder = JavadocClassFinder.instance(context);
156213091Sgonzo        enter = JavadocEnter.instance(context);
157213091Sgonzo        names = Names.instance(context);
158213091Sgonzo        externalizableSym = syms.enterClass(syms.java_base, names.fromString("java.io.Externalizable"));
159213091Sgonzo        chk = Check.instance(context);
160213091Sgonzo        types = Types.instance(context);
161104477Ssam        fileManager = context.get(JavaFileManager.class);
162104477Ssam        if (fileManager instanceof JavacFileManager) {
163136526Ssam            ((JavacFileManager)fileManager).setSymbolFileEnabled(false);
164136526Ssam        }
165104477Ssam
166104477Ssam        // Default.  Should normally be reset with setLocale.
167104477Ssam        this.doclocale = new DocLocale(this, "", breakiterator);
168104477Ssam        source = Source.instance(context);
169120915Ssam    }
170120915Ssam
171120915Ssam    public void setSilent(boolean silent) {
172104477Ssam        this.silent = silent;
173104477Ssam    }
174104477Ssam
175104477Ssam    /**
176112124Ssam     * Look up ClassDoc by qualified name.
177112124Ssam     */
178112124Ssam    public ClassDocImpl lookupClass(String name) {
179104477Ssam        ClassSymbol c = getClassSymbol(name);
180104477Ssam        if (c != null) {
181104477Ssam            return getClassDoc(c);
182104477Ssam        } else {
183104477Ssam            return null;
184104477Ssam        }
185104477Ssam    }
186104477Ssam
187167755Ssam    /**
188167755Ssam     * Load ClassDoc by qualified name.
189167755Ssam     */
190104477Ssam    public ClassDocImpl loadClass(String name) {
191104477Ssam        try {
192104477Ssam            Name nameImpl = names.fromString(name);
193104477Ssam            ModuleSymbol mod = syms.inferModule(Convert.packagePart(nameImpl));
194104477Ssam            ClassSymbol c = finder.loadClass(mod != null ? mod : syms.errModule, nameImpl);
195104477Ssam            return getClassDoc(c);
196104477Ssam        } catch (CompletionFailure ex) {
197104477Ssam            chk.completionError(null, ex);
198104477Ssam            return null;
199104477Ssam        }
200104477Ssam    }
201104477Ssam
202104477Ssam    /**
203104477Ssam     * Look up PackageDoc by qualified name.
204104477Ssam     */
205104477Ssam    public PackageDocImpl lookupPackage(String name) {
206104477Ssam        //### Jing alleges that class check is needed
207104477Ssam        //### to avoid a compiler bug.  Most likely
208104477Ssam        //### instead a dummy created for error recovery.
209104477Ssam        //### Should investigate this.
210104477Ssam        Name nameImpl = names.fromString(name);
211104477Ssam        ModuleSymbol mod = syms.inferModule(nameImpl);
212104477Ssam        PackageSymbol p = mod != null ? syms.getPackage(mod, nameImpl) : null;
213104477Ssam        ClassSymbol c = getClassSymbol(name);
214104477Ssam        if (p != null && c == null) {
215104477Ssam            return getPackageDoc(p);
216104477Ssam        } else {
217104477Ssam            return null;
218104477Ssam        }
219104477Ssam    }
220104477Ssam        // where
221104477Ssam        /** Retrieve class symbol by fully-qualified name.
222104477Ssam         */
223104477Ssam        ClassSymbol getClassSymbol(String name) {
224104477Ssam            // Name may contain nested class qualification.
225104477Ssam            // Generate candidate flatnames with successively shorter
226104477Ssam            // package qualifiers and longer nested class qualifiers.
227104477Ssam            int nameLen = name.length();
228104477Ssam            char[] nameChars = name.toCharArray();
229104477Ssam            int idx = name.length();
230104477Ssam            for (;;) {
231104477Ssam                Name nameImpl = names.fromChars(nameChars, 0, nameLen);
232104477Ssam                ModuleSymbol mod = syms.inferModule(Convert.packagePart(nameImpl));
233104477Ssam                ClassSymbol s = mod != null ? syms.getClass(mod, nameImpl) : null;
234104477Ssam                if (s != null)
235104477Ssam                    return s; // found it!
236104477Ssam                idx = name.substring(0, idx).lastIndexOf('.');
237104477Ssam                if (idx < 0) break;
238104477Ssam                nameChars[idx] = '$';
239104477Ssam            }
240104477Ssam            return null;
241104477Ssam        }
242104477Ssam
243104477Ssam    /**
244104477Ssam     * Set the locale.
245104477Ssam     */
246104477Ssam    public void setLocale(String localeName) {
247104477Ssam        // create locale specifics
248104477Ssam        doclocale = new DocLocale(this, localeName, breakiterator);
249104477Ssam        // update Messager if locale has changed.
250104477Ssam        messager.setLocale(doclocale.locale);
251104477Ssam    }
252104477Ssam
253104477Ssam    /** Check whether this member should be documented. */
254104477Ssam    public boolean shouldDocument(VarSymbol sym) {
255104477Ssam        long mod = sym.flags();
256104477Ssam
257104477Ssam        if ((mod & Flags.SYNTHETIC) != 0) {
258104477Ssam            return false;
259104477Ssam        }
260104477Ssam
261104477Ssam        return showAccess.checkModifier(translateModifiers(mod));
262104477Ssam    }
263104477Ssam
264104477Ssam    /** Check whether this member should be documented. */
265104477Ssam    public boolean shouldDocument(MethodSymbol sym) {
266104477Ssam        long mod = sym.flags();
267104477Ssam
268104477Ssam        if ((mod & Flags.SYNTHETIC) != 0) {
269104477Ssam            return false;
270104477Ssam        }
271104477Ssam
272104477Ssam        return showAccess.checkModifier(translateModifiers(mod));
273120915Ssam    }
274104477Ssam
275104477Ssam    /** check whether this class should be documented. */
276104477Ssam    public boolean shouldDocument(ClassSymbol sym) {
277104477Ssam        return
278104477Ssam            (sym.flags_field&Flags.SYNTHETIC) == 0 && // no synthetics
279104477Ssam            (docClasses || getClassDoc(sym).tree != null) &&
280104477Ssam            isVisible(sym);
281104477Ssam    }
282104477Ssam
283104477Ssam    //### Comment below is inaccurate wrt modifier filter testing
284104477Ssam    /**
285104477Ssam     * Check the visibility if this is an nested class.
286104477Ssam     * if this is not a nested class, return true.
287104477Ssam     * if this is an static visible nested class,
288104477Ssam     *    return true.
289104477Ssam     * if this is an visible nested class
290104477Ssam     *    if the outer class is visible return true.
291104477Ssam     *    else return false.
292104477Ssam     * IMPORTANT: This also allows, static nested classes
293104477Ssam     * to be defined inside an nested class, which is not
294104477Ssam     * allowed by the compiler. So such an test case will
295104477Ssam     * not reach upto this method itself, but if compiler
296104477Ssam     * allows it, then that will go through.
297104477Ssam     */
298104477Ssam    protected boolean isVisible(ClassSymbol sym) {
299104477Ssam        long mod = sym.flags_field;
300104477Ssam        if (!showAccess.checkModifier(translateModifiers(mod))) {
301104477Ssam            return false;
302104477Ssam        }
303104477Ssam        ClassSymbol encl = sym.owner.enclClass();
304104477Ssam        return (encl == null || (mod & Flags.STATIC) != 0 || isVisible(encl));
305104477Ssam    }
306104477Ssam
307104477Ssam    //---------------- print forwarders ----------------//
308104477Ssam
309104477Ssam    /**
310104477Ssam     * Print error message, increment error count.
311104477Ssam     *
312104477Ssam     * @param msg message to print.
313104477Ssam     */
314104477Ssam    public void printError(String msg) {
315104477Ssam        if (silent)
316104477Ssam            return;
317104477Ssam        messager.printError(msg);
318104477Ssam    }
319104477Ssam
320104477Ssam    /**
321104477Ssam     * Print error message, increment error count.
322104477Ssam     *
323104477Ssam     * @param key selects message from resource
324104477Ssam     */
325104477Ssam    public void error(DocImpl doc, String key) {
326104477Ssam        if (silent)
327104477Ssam            return;
328104477Ssam        messager.error(doc==null ? null : doc.position(), key);
329104477Ssam    }
330104477Ssam
331104477Ssam    /**
332104477Ssam     * Print error message, increment error count.
333104477Ssam     *
334104477Ssam     * @param key selects message from resource
335104477Ssam     */
336104477Ssam    public void error(SourcePosition pos, String key) {
337104477Ssam        if (silent)
338104477Ssam            return;
339104477Ssam        messager.error(pos, key);
340104477Ssam    }
341104477Ssam
342104477Ssam    /**
343104477Ssam     * Print error message, increment error count.
344104477Ssam     *
345104477Ssam     * @param msg message to print.
346104477Ssam     */
347104477Ssam    public void printError(SourcePosition pos, String msg) {
348104477Ssam        if (silent)
349104477Ssam            return;
350104477Ssam        messager.printError(pos, msg);
351104477Ssam    }
352104477Ssam
353104477Ssam    /**
354104477Ssam     * Print error message, increment error count.
355104477Ssam     *
356104477Ssam     * @param key selects message from resource
357104477Ssam     * @param a1 first argument
358104477Ssam     */
359104477Ssam    public void error(DocImpl doc, String key, String a1) {
360104477Ssam        if (silent)
361104477Ssam            return;
362104477Ssam        messager.error(doc==null ? null : doc.position(), key, a1);
363104477Ssam    }
364
365    /**
366     * Print error message, increment error count.
367     *
368     * @param key selects message from resource
369     * @param a1 first argument
370     * @param a2 second argument
371     */
372    public void error(DocImpl doc, String key, String a1, String a2) {
373        if (silent)
374            return;
375        messager.error(doc==null ? null : doc.position(), key, a1, a2);
376    }
377
378    /**
379     * Print error message, increment error count.
380     *
381     * @param key selects message from resource
382     * @param a1 first argument
383     * @param a2 second argument
384     * @param a3 third argument
385     */
386    public void error(DocImpl doc, String key, String a1, String a2, String a3) {
387        if (silent)
388            return;
389        messager.error(doc==null ? null : doc.position(), key, a1, a2, a3);
390    }
391
392    /**
393     * Print warning message, increment warning count.
394     *
395     * @param msg message to print.
396     */
397    public void printWarning(String msg) {
398        if (silent)
399            return;
400        messager.printWarning(msg);
401    }
402
403    /**
404     * Print warning message, increment warning count.
405     *
406     * @param key selects message from resource
407     */
408    public void warning(DocImpl doc, String key) {
409        if (silent)
410            return;
411        messager.warning(doc==null ? null : doc.position(), key);
412    }
413
414    /**
415     * Print warning message, increment warning count.
416     *
417     * @param msg message to print.
418     */
419    public void printWarning(SourcePosition pos, String msg) {
420        if (silent)
421            return;
422        messager.printWarning(pos, msg);
423    }
424
425    /**
426     * Print warning message, increment warning count.
427     *
428     * @param key selects message from resource
429     * @param a1 first argument
430     */
431    public void warning(DocImpl doc, String key, String a1) {
432        if (silent)
433            return;
434        // suppress messages that have (probably) been covered by doclint
435        if (doclint != null && doc != null && key.startsWith("tag"))
436            return;
437        messager.warning(doc==null ? null : doc.position(), key, a1);
438    }
439
440    /**
441     * Print warning message, increment warning count.
442     *
443     * @param key selects message from resource
444     * @param a1 first argument
445     * @param a2 second argument
446     */
447    public void warning(DocImpl doc, String key, String a1, String a2) {
448        if (silent)
449            return;
450        messager.warning(doc==null ? null : doc.position(), key, a1, a2);
451    }
452
453    /**
454     * Print warning message, increment warning count.
455     *
456     * @param key selects message from resource
457     * @param a1 first argument
458     * @param a2 second argument
459     * @param a3 third argument
460     */
461    public void warning(DocImpl doc, String key, String a1, String a2, String a3) {
462        if (silent)
463            return;
464        messager.warning(doc==null ? null : doc.position(), key, a1, a2, a3);
465    }
466
467    /**
468     * Print warning message, increment warning count.
469     *
470     * @param key selects message from resource
471     * @param a1 first argument
472     * @param a2 second argument
473     * @param a3 third argument
474     */
475    public void warning(DocImpl doc, String key, String a1, String a2, String a3,
476                        String a4) {
477        if (silent)
478            return;
479        messager.warning(doc==null ? null : doc.position(), key, a1, a2, a3, a4);
480    }
481
482    /**
483     * Print a message.
484     *
485     * @param msg message to print.
486     */
487    public void printNotice(String msg) {
488        if (silent || quiet)
489            return;
490        messager.printNotice(msg);
491    }
492
493
494    /**
495     * Print a message.
496     *
497     * @param key selects message from resource
498     */
499    public void notice(String key) {
500        if (silent || quiet)
501            return;
502        messager.notice(key);
503    }
504
505    /**
506     * Print a message.
507     *
508     * @param msg message to print.
509     */
510    public void printNotice(SourcePosition pos, String msg) {
511        if (silent || quiet)
512            return;
513        messager.printNotice(pos, msg);
514    }
515
516    /**
517     * Print a message.
518     *
519     * @param key selects message from resource
520     * @param a1 first argument
521     */
522    public void notice(String key, String a1) {
523        if (silent || quiet)
524            return;
525        messager.notice(key, a1);
526    }
527
528    /**
529     * Print a message.
530     *
531     * @param key selects message from resource
532     * @param a1 first argument
533     * @param a2 second argument
534     */
535    public void notice(String key, String a1, String a2) {
536        if (silent || quiet)
537            return;
538        messager.notice(key, a1, a2);
539    }
540
541    /**
542     * Print a message.
543     *
544     * @param key selects message from resource
545     * @param a1 first argument
546     * @param a2 second argument
547     * @param a3 third argument
548     */
549    public void notice(String key, String a1, String a2, String a3) {
550        if (silent || quiet)
551            return;
552        messager.notice(key, a1, a2, a3);
553    }
554
555    /**
556     * Exit, reporting errors and warnings.
557     */
558    public void exit() {
559        // Messager should be replaced by a more general
560        // compilation environment.  This can probably
561        // subsume DocEnv as well.
562        messager.exit();
563    }
564
565    protected Map<PackageSymbol, PackageDocImpl> packageMap = new HashMap<>();
566    /**
567     * Return the PackageDoc of this package symbol.
568     */
569    public PackageDocImpl getPackageDoc(PackageSymbol pack) {
570        PackageDocImpl result = packageMap.get(pack);
571        if (result != null) return result;
572        result = new PackageDocImpl(this, pack);
573        packageMap.put(pack, result);
574        return result;
575    }
576
577    /**
578     * Create the PackageDoc (or a subtype) for a package symbol.
579     */
580    void makePackageDoc(PackageSymbol pack, TreePath treePath) {
581        PackageDocImpl result = packageMap.get(pack);
582        if (result != null) {
583            if (treePath != null) result.setTreePath(treePath);
584        } else {
585            result = new PackageDocImpl(this, pack, treePath);
586            packageMap.put(pack, result);
587        }
588    }
589
590
591    protected Map<ClassSymbol, ClassDocImpl> classMap = new HashMap<>();
592    /**
593     * Return the ClassDoc (or a subtype) of this class symbol.
594     */
595    public ClassDocImpl getClassDoc(ClassSymbol clazz) {
596        ClassDocImpl result = classMap.get(clazz);
597        if (result != null) return result;
598        if (isAnnotationType(clazz)) {
599            result = new AnnotationTypeDocImpl(this, clazz);
600        } else {
601            result = new ClassDocImpl(this, clazz);
602        }
603        classMap.put(clazz, result);
604        return result;
605    }
606
607    /**
608     * Create the ClassDoc (or a subtype) for a class symbol.
609     */
610    protected void makeClassDoc(ClassSymbol clazz, TreePath treePath) {
611        ClassDocImpl result = classMap.get(clazz);
612        if (result != null) {
613            if (treePath != null) result.setTreePath(treePath);
614            return;
615        }
616        if (isAnnotationType((JCClassDecl) treePath.getLeaf())) {   // flags of clazz may not yet be set
617            result = new AnnotationTypeDocImpl(this, clazz, treePath);
618        } else {
619            result = new ClassDocImpl(this, clazz, treePath);
620        }
621        classMap.put(clazz, result);
622    }
623
624    protected static boolean isAnnotationType(ClassSymbol clazz) {
625        return ClassDocImpl.isAnnotationType(clazz);
626    }
627
628    protected static boolean isAnnotationType(JCClassDecl tree) {
629        return (tree.mods.flags & Flags.ANNOTATION) != 0;
630    }
631
632    protected Map<VarSymbol, FieldDocImpl> fieldMap = new HashMap<>();
633    /**
634     * Return the FieldDoc of this var symbol.
635     */
636    public FieldDocImpl getFieldDoc(VarSymbol var) {
637        FieldDocImpl result = fieldMap.get(var);
638        if (result != null) return result;
639        result = new FieldDocImpl(this, var);
640        fieldMap.put(var, result);
641        return result;
642    }
643    /**
644     * Create a FieldDoc for a var symbol.
645     */
646    protected void makeFieldDoc(VarSymbol var, TreePath treePath) {
647        FieldDocImpl result = fieldMap.get(var);
648        if (result != null) {
649            if (treePath != null) result.setTreePath(treePath);
650        } else {
651            result = new FieldDocImpl(this, var, treePath);
652            fieldMap.put(var, result);
653        }
654    }
655
656    protected Map<MethodSymbol, ExecutableMemberDocImpl> methodMap = new HashMap<>();
657    /**
658     * Create a MethodDoc for this MethodSymbol.
659     * Should be called only on symbols representing methods.
660     */
661    protected void makeMethodDoc(MethodSymbol meth, TreePath treePath) {
662        MethodDocImpl result = (MethodDocImpl)methodMap.get(meth);
663        if (result != null) {
664            if (treePath != null) result.setTreePath(treePath);
665        } else {
666            result = new MethodDocImpl(this, meth, treePath);
667            methodMap.put(meth, result);
668        }
669    }
670
671    /**
672     * Return the MethodDoc for a MethodSymbol.
673     * Should be called only on symbols representing methods.
674     */
675    public MethodDocImpl getMethodDoc(MethodSymbol meth) {
676        assert !meth.isConstructor() : "not expecting a constructor symbol";
677        MethodDocImpl result = (MethodDocImpl)methodMap.get(meth);
678        if (result != null) return result;
679        result = new MethodDocImpl(this, meth);
680        methodMap.put(meth, result);
681        return result;
682    }
683
684    /**
685     * Create the ConstructorDoc for a MethodSymbol.
686     * Should be called only on symbols representing constructors.
687     */
688    protected void makeConstructorDoc(MethodSymbol meth, TreePath treePath) {
689        ConstructorDocImpl result = (ConstructorDocImpl)methodMap.get(meth);
690        if (result != null) {
691            if (treePath != null) result.setTreePath(treePath);
692        } else {
693            result = new ConstructorDocImpl(this, meth, treePath);
694            methodMap.put(meth, result);
695        }
696    }
697
698    /**
699     * Return the ConstructorDoc for a MethodSymbol.
700     * Should be called only on symbols representing constructors.
701     */
702    public ConstructorDocImpl getConstructorDoc(MethodSymbol meth) {
703        assert meth.isConstructor() : "expecting a constructor symbol";
704        ConstructorDocImpl result = (ConstructorDocImpl)methodMap.get(meth);
705        if (result != null) return result;
706        result = new ConstructorDocImpl(this, meth);
707        methodMap.put(meth, result);
708        return result;
709    }
710
711    /**
712     * Create the AnnotationTypeElementDoc for a MethodSymbol.
713     * Should be called only on symbols representing annotation type elements.
714     */
715    protected void makeAnnotationTypeElementDoc(MethodSymbol meth, TreePath treePath) {
716        AnnotationTypeElementDocImpl result =
717            (AnnotationTypeElementDocImpl)methodMap.get(meth);
718        if (result != null) {
719            if (treePath != null) result.setTreePath(treePath);
720        } else {
721            result =
722                new AnnotationTypeElementDocImpl(this, meth, treePath);
723            methodMap.put(meth, result);
724        }
725    }
726
727    /**
728     * Return the AnnotationTypeElementDoc for a MethodSymbol.
729     * Should be called only on symbols representing annotation type elements.
730     */
731    public AnnotationTypeElementDocImpl getAnnotationTypeElementDoc(
732            MethodSymbol meth) {
733
734        AnnotationTypeElementDocImpl result =
735            (AnnotationTypeElementDocImpl)methodMap.get(meth);
736        if (result != null) return result;
737        result = new AnnotationTypeElementDocImpl(this, meth);
738        methodMap.put(meth, result);
739        return result;
740    }
741
742//  private Map<ClassType, ParameterizedTypeImpl> parameterizedTypeMap =
743//          new HashMap<ClassType, ParameterizedTypeImpl>();
744    /**
745     * Return the ParameterizedType of this instantiation.
746//   * ### Could use Type.sameTypeAs() instead of equality matching in hashmap
747//   * ### to avoid some duplication.
748     */
749    ParameterizedTypeImpl getParameterizedType(ClassType t) {
750        return new ParameterizedTypeImpl(this, t);
751//      ParameterizedTypeImpl result = parameterizedTypeMap.get(t);
752//      if (result != null) return result;
753//      result = new ParameterizedTypeImpl(this, t);
754//      parameterizedTypeMap.put(t, result);
755//      return result;
756    }
757
758    TreePath getTreePath(JCCompilationUnit tree) {
759        TreePath p = treePaths.get(tree);
760        if (p == null)
761            treePaths.put(tree, p = new TreePath(tree));
762        return p;
763    }
764
765    TreePath getTreePath(JCCompilationUnit toplevel, JCPackageDecl tree) {
766        TreePath p = treePaths.get(tree);
767        if (p == null)
768            treePaths.put(tree, p = new TreePath(getTreePath(toplevel), tree));
769        return p;
770    }
771
772    TreePath getTreePath(JCCompilationUnit toplevel, JCClassDecl tree) {
773        TreePath p = treePaths.get(tree);
774        if (p == null)
775            treePaths.put(tree, p = new TreePath(getTreePath(toplevel), tree));
776        return p;
777    }
778
779    TreePath getTreePath(JCCompilationUnit toplevel, JCClassDecl cdecl, JCTree tree) {
780        return new TreePath(getTreePath(toplevel, cdecl), tree);
781    }
782
783    /**
784     * Set the encoding.
785     */
786    public void setEncoding(String encoding) {
787        this.encoding = encoding;
788    }
789
790    /**
791     * Get the encoding.
792     */
793    public String getEncoding() {
794        return encoding;
795    }
796
797    /**
798     * Convert modifier bits from private coding used by
799     * the compiler to that of java.lang.reflect.Modifier.
800     */
801    static int translateModifiers(long flags) {
802        int result = 0;
803        if ((flags & Flags.ABSTRACT) != 0)
804            result |= Modifier.ABSTRACT;
805        if ((flags & Flags.FINAL) != 0)
806            result |= Modifier.FINAL;
807        if ((flags & Flags.INTERFACE) != 0)
808            result |= Modifier.INTERFACE;
809        if ((flags & Flags.NATIVE) != 0)
810            result |= Modifier.NATIVE;
811        if ((flags & Flags.PRIVATE) != 0)
812            result |= Modifier.PRIVATE;
813        if ((flags & Flags.PROTECTED) != 0)
814            result |= Modifier.PROTECTED;
815        if ((flags & Flags.PUBLIC) != 0)
816            result |= Modifier.PUBLIC;
817        if ((flags & Flags.STATIC) != 0)
818            result |= Modifier.STATIC;
819        if ((flags & Flags.SYNCHRONIZED) != 0)
820            result |= Modifier.SYNCHRONIZED;
821        if ((flags & Flags.TRANSIENT) != 0)
822            result |= Modifier.TRANSIENT;
823        if ((flags & Flags.VOLATILE) != 0)
824            result |= Modifier.VOLATILE;
825        return result;
826    }
827
828    void initDoclint(Collection<String> opts, Collection<String> customTagNames, String htmlVersion) {
829        ArrayList<String> doclintOpts = new ArrayList<>();
830        boolean msgOptionSeen = false;
831
832        for (String opt : opts) {
833            if (opt.startsWith(DocLint.XMSGS_OPTION)) {
834                if (opt.equals(DocLint.XMSGS_CUSTOM_PREFIX + "none"))
835                    return;
836                msgOptionSeen = true;
837            }
838            doclintOpts.add(opt);
839        }
840
841        if (!msgOptionSeen) {
842            doclintOpts.add(DocLint.XMSGS_OPTION);
843        }
844
845        String sep = "";
846        StringBuilder customTags = new StringBuilder();
847        for (String customTag : customTagNames) {
848            customTags.append(sep);
849            customTags.append(customTag);
850            sep = DocLint.SEPARATOR;
851        }
852        doclintOpts.add(DocLint.XCUSTOM_TAGS_PREFIX + customTags.toString());
853        doclintOpts.add(DocLint.XHTML_VERSION_PREFIX + htmlVersion);
854
855        JavacTask t = BasicJavacTask.instance(context);
856        doclint = new DocLint();
857        // standard doclet normally generates H1, H2
858        doclintOpts.add(DocLint.XIMPLICIT_HEADERS + "2");
859        doclint.init(t, doclintOpts.toArray(new String[doclintOpts.size()]), false);
860    }
861
862    JavaScriptScanner initJavaScriptScanner(boolean allowScriptInComments) {
863        if (allowScriptInComments) {
864            javaScriptScanner = null;
865        } else {
866            javaScriptScanner = new JavaScriptScanner();
867        }
868        return javaScriptScanner;
869    }
870
871    boolean showTagMessages() {
872        return (doclint == null);
873    }
874
875    Map<CompilationUnitTree, Boolean> shouldCheck = new HashMap<>();
876
877    boolean shouldCheck(CompilationUnitTree unit) {
878        return shouldCheck.computeIfAbsent(unit, doclint :: shouldCheck);
879    }
880}
881