View Javadoc
1   /*
2    * Copyright (c) 2000, 2013, 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.javadoc;
27  
28  import java.lang.reflect.Modifier;
29  import java.util.*;
30  
31  import javax.tools.JavaFileManager;
32  
33  import com.sun.javadoc.*;
34  import com.sun.source.util.JavacTask;
35  import com.sun.source.util.TreePath;
36  import com.sun.tools.doclint.DocLint;
37  import com.sun.tools.javac.api.BasicJavacTask;
38  import com.sun.tools.javac.code.*;
39  import com.sun.tools.javac.code.Symbol.*;
40  import com.sun.tools.javac.code.Type.ClassType;
41  import com.sun.tools.javac.comp.Check;
42  import com.sun.tools.javac.file.JavacFileManager;
43  import com.sun.tools.javac.tree.JCTree;
44  import com.sun.tools.javac.tree.JCTree.*;
45  import com.sun.tools.javac.util.Context;
46  import com.sun.tools.javac.util.Names;
47  
48  /**
49   * Holds the environment for a run of javadoc.
50   * Holds only the information needed throughout the
51   * run and not the compiler info that could be GC'ed
52   * or ported.
53   *
54   *  <p><b>This is NOT part of any supported API.
55   *  If you write code that depends on this, you do so at your own risk.
56   *  This code and its internal interfaces are subject to change or
57   *  deletion without notice.</b>
58   *
59   * @since 1.4
60   * @author Robert Field
61   * @author Neal Gafter (rewrite)
62   * @author Scott Seligman (generics)
63   */
64  public class DocEnv {
65      protected static final Context.Key<DocEnv> docEnvKey =
66          new Context.Key<DocEnv>();
67  
68      public static DocEnv instance(Context context) {
69          DocEnv instance = context.get(docEnvKey);
70          if (instance == null)
71              instance = new DocEnv(context);
72          return instance;
73      }
74  
75      private Messager messager;
76  
77      DocLocale doclocale;
78  
79      /** Predefined symbols known to the compiler. */
80      Symtab syms;
81  
82      /** Referenced directly in RootDocImpl. */
83      JavadocClassReader reader;
84  
85      /** Javadoc's own version of the compiler's enter phase. */
86      JavadocEnter enter;
87  
88      /** The name table. */
89      Names names;
90  
91      /** The encoding name. */
92      private String encoding;
93  
94      final Symbol externalizableSym;
95  
96      /** Access filter (public, protected, ...).  */
97      protected ModifierFilter showAccess;
98  
99      /** True if we are using a sentence BreakIterator. */
100     boolean breakiterator;
101 
102     /**
103      * True if we do not want to print any notifications at all.
104      */
105     boolean quiet = false;
106 
107     Check chk;
108     Types types;
109     JavaFileManager fileManager;
110     Context context;
111     DocLint doclint;
112 
113     WeakHashMap<JCTree, TreePath> treePaths = new WeakHashMap<JCTree, TreePath>();
114 
115     /** Allow documenting from class files? */
116     boolean docClasses = false;
117 
118     /** Does the doclet only expect pre-1.5 doclet API? */
119     protected boolean legacyDoclet = true;
120 
121     /**
122      * Set this to true if you would like to not emit any errors, warnings and
123      * notices.
124      */
125     private boolean silent = false;
126 
127     /**
128      * The source language version.
129      */
130     protected Source source;
131 
132     /**
133      * Constructor
134      *
135      * @param context      Context for this javadoc instance.
136      */
137     protected DocEnv(Context context) {
138         context.put(docEnvKey, this);
139         this.context = context;
140 
141         messager = Messager.instance0(context);
142         syms = Symtab.instance(context);
143         reader = JavadocClassReader.instance0(context);
144         enter = JavadocEnter.instance0(context);
145         names = Names.instance(context);
146         externalizableSym = reader.enterClass(names.fromString("java.io.Externalizable"));
147         chk = Check.instance(context);
148         types = Types.instance(context);
149         fileManager = context.get(JavaFileManager.class);
150         if (fileManager instanceof JavacFileManager) {
151             ((JavacFileManager)fileManager).setSymbolFileEnabled(false);
152         }
153 
154         // Default.  Should normally be reset with setLocale.
155         this.doclocale = new DocLocale(this, "", breakiterator);
156         source = Source.instance(context);
157     }
158 
159     public void setSilent(boolean silent) {
160         this.silent = silent;
161     }
162 
163     /**
164      * Look up ClassDoc by qualified name.
165      */
166     public ClassDocImpl lookupClass(String name) {
167         ClassSymbol c = getClassSymbol(name);
168         if (c != null) {
169             return getClassDoc(c);
170         } else {
171             return null;
172         }
173     }
174 
175     /**
176      * Load ClassDoc by qualified name.
177      */
178     public ClassDocImpl loadClass(String name) {
179         try {
180             ClassSymbol c = reader.loadClass(names.fromString(name));
181             return getClassDoc(c);
182         } catch (CompletionFailure ex) {
183             chk.completionError(null, ex);
184             return null;
185         }
186     }
187 
188     /**
189      * Look up PackageDoc by qualified name.
190      */
191     public PackageDocImpl lookupPackage(String name) {
192         //### Jing alleges that class check is needed
193         //### to avoid a compiler bug.  Most likely
194         //### instead a dummy created for error recovery.
195         //### Should investigate this.
196         PackageSymbol p = syms.packages.get(names.fromString(name));
197         ClassSymbol c = getClassSymbol(name);
198         if (p != null && c == null) {
199             return getPackageDoc(p);
200         } else {
201             return null;
202         }
203     }
204         // where
205         /** Retrieve class symbol by fully-qualified name.
206          */
207         ClassSymbol getClassSymbol(String name) {
208             // Name may contain nested class qualification.
209             // Generate candidate flatnames with successively shorter
210             // package qualifiers and longer nested class qualifiers.
211             int nameLen = name.length();
212             char[] nameChars = name.toCharArray();
213             int idx = name.length();
214             for (;;) {
215                 ClassSymbol s = syms.classes.get(names.fromChars(nameChars, 0, nameLen));
216                 if (s != null)
217                     return s; // found it!
218                 idx = name.substring(0, idx).lastIndexOf('.');
219                 if (idx < 0) break;
220                 nameChars[idx] = '$';
221             }
222             return null;
223         }
224 
225     /**
226      * Set the locale.
227      */
228     public void setLocale(String localeName) {
229         // create locale specifics
230         doclocale = new DocLocale(this, localeName, breakiterator);
231         // update Messager if locale has changed.
232         messager.setLocale(doclocale.locale);
233     }
234 
235     /** Check whether this member should be documented. */
236     public boolean shouldDocument(VarSymbol sym) {
237         long mod = sym.flags();
238 
239         if ((mod & Flags.SYNTHETIC) != 0) {
240             return false;
241         }
242 
243         return showAccess.checkModifier(translateModifiers(mod));
244     }
245 
246     /** Check whether this member should be documented. */
247     public boolean shouldDocument(MethodSymbol sym) {
248         long mod = sym.flags();
249 
250         if ((mod & Flags.SYNTHETIC) != 0) {
251             return false;
252         }
253 
254         return showAccess.checkModifier(translateModifiers(mod));
255     }
256 
257     /** check whether this class should be documented. */
258     public boolean shouldDocument(ClassSymbol sym) {
259         return
260             (sym.flags_field&Flags.SYNTHETIC) == 0 && // no synthetics
261             (docClasses || getClassDoc(sym).tree != null) &&
262             isVisible(sym);
263     }
264 
265     //### Comment below is inaccurate wrt modifier filter testing
266     /**
267      * Check the visibility if this is an nested class.
268      * if this is not a nested class, return true.
269      * if this is an static visible nested class,
270      *    return true.
271      * if this is an visible nested class
272      *    if the outer class is visible return true.
273      *    else return false.
274      * IMPORTANT: This also allows, static nested classes
275      * to be defined inside an nested class, which is not
276      * allowed by the compiler. So such an test case will
277      * not reach upto this method itself, but if compiler
278      * allows it, then that will go through.
279      */
280     protected boolean isVisible(ClassSymbol sym) {
281         long mod = sym.flags_field;
282         if (!showAccess.checkModifier(translateModifiers(mod))) {
283             return false;
284         }
285         ClassSymbol encl = sym.owner.enclClass();
286         return (encl == null || (mod & Flags.STATIC) != 0 || isVisible(encl));
287     }
288 
289     //---------------- print forwarders ----------------//
290 
291     /**
292      * Print error message, increment error count.
293      *
294      * @param msg message to print.
295      */
296     public void printError(String msg) {
297         if (silent)
298             return;
299         messager.printError(msg);
300     }
301 
302     /**
303      * Print error message, increment error count.
304      *
305      * @param key selects message from resource
306      */
307     public void error(DocImpl doc, String key) {
308         if (silent)
309             return;
310         messager.error(doc==null ? null : doc.position(), key);
311     }
312 
313     /**
314      * Print error message, increment error count.
315      *
316      * @param key selects message from resource
317      */
318     public void error(SourcePosition pos, String key) {
319         if (silent)
320             return;
321         messager.error(pos, key);
322     }
323 
324     /**
325      * Print error message, increment error count.
326      *
327      * @param msg message to print.
328      */
329     public void printError(SourcePosition pos, String msg) {
330         if (silent)
331             return;
332         messager.printError(pos, msg);
333     }
334 
335     /**
336      * Print error message, increment error count.
337      *
338      * @param key selects message from resource
339      * @param a1 first argument
340      */
341     public void error(DocImpl doc, String key, String a1) {
342         if (silent)
343             return;
344         messager.error(doc==null ? null : doc.position(), key, a1);
345     }
346 
347     /**
348      * Print error message, increment error count.
349      *
350      * @param key selects message from resource
351      * @param a1 first argument
352      * @param a2 second argument
353      */
354     public void error(DocImpl doc, String key, String a1, String a2) {
355         if (silent)
356             return;
357         messager.error(doc==null ? null : doc.position(), key, a1, a2);
358     }
359 
360     /**
361      * Print error message, increment error count.
362      *
363      * @param key selects message from resource
364      * @param a1 first argument
365      * @param a2 second argument
366      * @param a3 third argument
367      */
368     public void error(DocImpl doc, String key, String a1, String a2, String a3) {
369         if (silent)
370             return;
371         messager.error(doc==null ? null : doc.position(), key, a1, a2, a3);
372     }
373 
374     /**
375      * Print warning message, increment warning count.
376      *
377      * @param msg message to print.
378      */
379     public void printWarning(String msg) {
380         if (silent)
381             return;
382         messager.printWarning(msg);
383     }
384 
385     /**
386      * Print warning message, increment warning count.
387      *
388      * @param key selects message from resource
389      */
390     public void warning(DocImpl doc, String key) {
391         if (silent)
392             return;
393         messager.warning(doc==null ? null : doc.position(), key);
394     }
395 
396     /**
397      * Print warning message, increment warning count.
398      *
399      * @param msg message to print.
400      */
401     public void printWarning(SourcePosition pos, String msg) {
402         if (silent)
403             return;
404         messager.printWarning(pos, msg);
405     }
406 
407     /**
408      * Print warning message, increment warning count.
409      *
410      * @param key selects message from resource
411      * @param a1 first argument
412      */
413     public void warning(DocImpl doc, String key, String a1) {
414         if (silent)
415             return;
416         // suppress messages that have (probably) been covered by doclint
417         if (doclint != null && doc != null && key.startsWith("tag"))
418             return;
419         messager.warning(doc==null ? null : doc.position(), key, a1);
420     }
421 
422     /**
423      * Print warning message, increment warning count.
424      *
425      * @param key selects message from resource
426      * @param a1 first argument
427      * @param a2 second argument
428      */
429     public void warning(DocImpl doc, String key, String a1, String a2) {
430         if (silent)
431             return;
432         messager.warning(doc==null ? null : doc.position(), key, a1, a2);
433     }
434 
435     /**
436      * Print warning message, increment warning count.
437      *
438      * @param key selects message from resource
439      * @param a1 first argument
440      * @param a2 second argument
441      * @param a3 third argument
442      */
443     public void warning(DocImpl doc, String key, String a1, String a2, String a3) {
444         if (silent)
445             return;
446         messager.warning(doc==null ? null : doc.position(), key, a1, a2, a3);
447     }
448 
449     /**
450      * Print warning message, increment warning count.
451      *
452      * @param key selects message from resource
453      * @param a1 first argument
454      * @param a2 second argument
455      * @param a3 third argument
456      */
457     public void warning(DocImpl doc, String key, String a1, String a2, String a3,
458                         String a4) {
459         if (silent)
460             return;
461         messager.warning(doc==null ? null : doc.position(), key, a1, a2, a3, a4);
462     }
463 
464     /**
465      * Print a message.
466      *
467      * @param msg message to print.
468      */
469     public void printNotice(String msg) {
470         if (silent || quiet)
471             return;
472         messager.printNotice(msg);
473     }
474 
475 
476     /**
477      * Print a message.
478      *
479      * @param key selects message from resource
480      */
481     public void notice(String key) {
482         if (silent || quiet)
483             return;
484         messager.notice(key);
485     }
486 
487     /**
488      * Print a message.
489      *
490      * @param msg message to print.
491      */
492     public void printNotice(SourcePosition pos, String msg) {
493         if (silent || quiet)
494             return;
495         messager.printNotice(pos, msg);
496     }
497 
498     /**
499      * Print a message.
500      *
501      * @param key selects message from resource
502      * @param a1 first argument
503      */
504     public void notice(String key, String a1) {
505         if (silent || quiet)
506             return;
507         messager.notice(key, a1);
508     }
509 
510     /**
511      * Print a message.
512      *
513      * @param key selects message from resource
514      * @param a1 first argument
515      * @param a2 second argument
516      */
517     public void notice(String key, String a1, String a2) {
518         if (silent || quiet)
519             return;
520         messager.notice(key, a1, a2);
521     }
522 
523     /**
524      * Print a message.
525      *
526      * @param key selects message from resource
527      * @param a1 first argument
528      * @param a2 second argument
529      * @param a3 third argument
530      */
531     public void notice(String key, String a1, String a2, String a3) {
532         if (silent || quiet)
533             return;
534         messager.notice(key, a1, a2, a3);
535     }
536 
537     /**
538      * Exit, reporting errors and warnings.
539      */
540     public void exit() {
541         // Messager should be replaced by a more general
542         // compilation environment.  This can probably
543         // subsume DocEnv as well.
544         messager.exit();
545     }
546 
547     protected Map<PackageSymbol, PackageDocImpl> packageMap =
548             new HashMap<PackageSymbol, PackageDocImpl>();
549     /**
550      * Return the PackageDoc of this package symbol.
551      */
552     public PackageDocImpl getPackageDoc(PackageSymbol pack) {
553         PackageDocImpl result = packageMap.get(pack);
554         if (result != null) return result;
555         result = new PackageDocImpl(this, pack);
556         packageMap.put(pack, result);
557         return result;
558     }
559 
560     /**
561      * Create the PackageDoc (or a subtype) for a package symbol.
562      */
563     void makePackageDoc(PackageSymbol pack, TreePath treePath) {
564         PackageDocImpl result = packageMap.get(pack);
565         if (result != null) {
566             if (treePath != null) result.setTreePath(treePath);
567         } else {
568             result = new PackageDocImpl(this, pack, treePath);
569             packageMap.put(pack, result);
570         }
571     }
572 
573 
574     protected Map<ClassSymbol, ClassDocImpl> classMap =
575             new HashMap<ClassSymbol, ClassDocImpl>();
576     /**
577      * Return the ClassDoc (or a subtype) of this class symbol.
578      */
579     public ClassDocImpl getClassDoc(ClassSymbol clazz) {
580         ClassDocImpl result = classMap.get(clazz);
581         if (result != null) return result;
582         if (isAnnotationType(clazz)) {
583             result = new AnnotationTypeDocImpl(this, clazz);
584         } else {
585             result = new ClassDocImpl(this, clazz);
586         }
587         classMap.put(clazz, result);
588         return result;
589     }
590 
591     /**
592      * Create the ClassDoc (or a subtype) for a class symbol.
593      */
594     protected void makeClassDoc(ClassSymbol clazz, TreePath treePath) {
595         ClassDocImpl result = classMap.get(clazz);
596         if (result != null) {
597             if (treePath != null) result.setTreePath(treePath);
598             return;
599         }
600         if (isAnnotationType((JCClassDecl) treePath.getLeaf())) {   // flags of clazz may not yet be set
601             result = new AnnotationTypeDocImpl(this, clazz, treePath);
602         } else {
603             result = new ClassDocImpl(this, clazz, treePath);
604         }
605         classMap.put(clazz, result);
606     }
607 
608     protected static boolean isAnnotationType(ClassSymbol clazz) {
609         return ClassDocImpl.isAnnotationType(clazz);
610     }
611 
612     protected static boolean isAnnotationType(JCClassDecl tree) {
613         return (tree.mods.flags & Flags.ANNOTATION) != 0;
614     }
615 
616     protected Map<VarSymbol, FieldDocImpl> fieldMap =
617             new HashMap<VarSymbol, FieldDocImpl>();
618     /**
619      * Return the FieldDoc of this var symbol.
620      */
621     public FieldDocImpl getFieldDoc(VarSymbol var) {
622         FieldDocImpl result = fieldMap.get(var);
623         if (result != null) return result;
624         result = new FieldDocImpl(this, var);
625         fieldMap.put(var, result);
626         return result;
627     }
628     /**
629      * Create a FieldDoc for a var symbol.
630      */
631     protected void makeFieldDoc(VarSymbol var, TreePath treePath) {
632         FieldDocImpl result = fieldMap.get(var);
633         if (result != null) {
634             if (treePath != null) result.setTreePath(treePath);
635         } else {
636             result = new FieldDocImpl(this, var, treePath);
637             fieldMap.put(var, result);
638         }
639     }
640 
641     protected Map<MethodSymbol, ExecutableMemberDocImpl> methodMap =
642             new HashMap<MethodSymbol, ExecutableMemberDocImpl>();
643     /**
644      * Create a MethodDoc for this MethodSymbol.
645      * Should be called only on symbols representing methods.
646      */
647     protected void makeMethodDoc(MethodSymbol meth, TreePath treePath) {
648         MethodDocImpl result = (MethodDocImpl)methodMap.get(meth);
649         if (result != null) {
650             if (treePath != null) result.setTreePath(treePath);
651         } else {
652             result = new MethodDocImpl(this, meth, treePath);
653             methodMap.put(meth, result);
654         }
655     }
656 
657     /**
658      * Return the MethodDoc for a MethodSymbol.
659      * Should be called only on symbols representing methods.
660      */
661     public MethodDocImpl getMethodDoc(MethodSymbol meth) {
662         assert !meth.isConstructor() : "not expecting a constructor symbol";
663         MethodDocImpl result = (MethodDocImpl)methodMap.get(meth);
664         if (result != null) return result;
665         result = new MethodDocImpl(this, meth);
666         methodMap.put(meth, result);
667         return result;
668     }
669 
670     /**
671      * Create the ConstructorDoc for a MethodSymbol.
672      * Should be called only on symbols representing constructors.
673      */
674     protected void makeConstructorDoc(MethodSymbol meth, TreePath treePath) {
675         ConstructorDocImpl result = (ConstructorDocImpl)methodMap.get(meth);
676         if (result != null) {
677             if (treePath != null) result.setTreePath(treePath);
678         } else {
679             result = new ConstructorDocImpl(this, meth, treePath);
680             methodMap.put(meth, result);
681         }
682     }
683 
684     /**
685      * Return the ConstructorDoc for a MethodSymbol.
686      * Should be called only on symbols representing constructors.
687      */
688     public ConstructorDocImpl getConstructorDoc(MethodSymbol meth) {
689         assert meth.isConstructor() : "expecting a constructor symbol";
690         ConstructorDocImpl result = (ConstructorDocImpl)methodMap.get(meth);
691         if (result != null) return result;
692         result = new ConstructorDocImpl(this, meth);
693         methodMap.put(meth, result);
694         return result;
695     }
696 
697     /**
698      * Create the AnnotationTypeElementDoc for a MethodSymbol.
699      * Should be called only on symbols representing annotation type elements.
700      */
701     protected void makeAnnotationTypeElementDoc(MethodSymbol meth, TreePath treePath) {
702         AnnotationTypeElementDocImpl result =
703             (AnnotationTypeElementDocImpl)methodMap.get(meth);
704         if (result != null) {
705             if (treePath != null) result.setTreePath(treePath);
706         } else {
707             result =
708                 new AnnotationTypeElementDocImpl(this, meth, treePath);
709             methodMap.put(meth, result);
710         }
711     }
712 
713     /**
714      * Return the AnnotationTypeElementDoc for a MethodSymbol.
715      * Should be called only on symbols representing annotation type elements.
716      */
717     public AnnotationTypeElementDocImpl getAnnotationTypeElementDoc(
718             MethodSymbol meth) {
719 
720         AnnotationTypeElementDocImpl result =
721             (AnnotationTypeElementDocImpl)methodMap.get(meth);
722         if (result != null) return result;
723         result = new AnnotationTypeElementDocImpl(this, meth);
724         methodMap.put(meth, result);
725         return result;
726     }
727 
728 //  private Map<ClassType, ParameterizedTypeImpl> parameterizedTypeMap =
729 //          new HashMap<ClassType, ParameterizedTypeImpl>();
730     /**
731      * Return the ParameterizedType of this instantiation.
732 //   * ### Could use Type.sameTypeAs() instead of equality matching in hashmap
733 //   * ### to avoid some duplication.
734      */
735     ParameterizedTypeImpl getParameterizedType(ClassType t) {
736         return new ParameterizedTypeImpl(this, t);
737 //      ParameterizedTypeImpl result = parameterizedTypeMap.get(t);
738 //      if (result != null) return result;
739 //      result = new ParameterizedTypeImpl(this, t);
740 //      parameterizedTypeMap.put(t, result);
741 //      return result;
742     }
743 
744     TreePath getTreePath(JCCompilationUnit tree) {
745         TreePath p = treePaths.get(tree);
746         if (p == null)
747             treePaths.put(tree, p = new TreePath(tree));
748         return p;
749     }
750 
751     TreePath getTreePath(JCCompilationUnit toplevel, JCClassDecl tree) {
752         TreePath p = treePaths.get(tree);
753         if (p == null)
754             treePaths.put(tree, p = new TreePath(getTreePath(toplevel), tree));
755         return p;
756     }
757 
758     TreePath getTreePath(JCCompilationUnit toplevel, JCClassDecl cdecl, JCTree tree) {
759         return new TreePath(getTreePath(toplevel, cdecl), tree);
760     }
761 
762     /**
763      * Set the encoding.
764      */
765     public void setEncoding(String encoding) {
766         this.encoding = encoding;
767     }
768 
769     /**
770      * Get the encoding.
771      */
772     public String getEncoding() {
773         return encoding;
774     }
775 
776     /**
777      * Convert modifier bits from private coding used by
778      * the compiler to that of java.lang.reflect.Modifier.
779      */
780     static int translateModifiers(long flags) {
781         int result = 0;
782         if ((flags & Flags.ABSTRACT) != 0)
783             result |= Modifier.ABSTRACT;
784         if ((flags & Flags.FINAL) != 0)
785             result |= Modifier.FINAL;
786         if ((flags & Flags.INTERFACE) != 0)
787             result |= Modifier.INTERFACE;
788         if ((flags & Flags.NATIVE) != 0)
789             result |= Modifier.NATIVE;
790         if ((flags & Flags.PRIVATE) != 0)
791             result |= Modifier.PRIVATE;
792         if ((flags & Flags.PROTECTED) != 0)
793             result |= Modifier.PROTECTED;
794         if ((flags & Flags.PUBLIC) != 0)
795             result |= Modifier.PUBLIC;
796         if ((flags & Flags.STATIC) != 0)
797             result |= Modifier.STATIC;
798         if ((flags & Flags.SYNCHRONIZED) != 0)
799             result |= Modifier.SYNCHRONIZED;
800         if ((flags & Flags.TRANSIENT) != 0)
801             result |= Modifier.TRANSIENT;
802         if ((flags & Flags.VOLATILE) != 0)
803             result |= Modifier.VOLATILE;
804         return result;
805     }
806 
807     void initDoclint(Collection<String> opts, Collection<String> customTagNames) {
808         ArrayList<String> doclintOpts = new ArrayList<String>();
809 
810         for (String opt: opts) {
811             doclintOpts.add(opt == null ? DocLint.XMSGS_OPTION : DocLint.XMSGS_CUSTOM_PREFIX + opt);
812         }
813 
814         if (doclintOpts.isEmpty()) {
815             doclintOpts.add(DocLint.XMSGS_OPTION);
816         } else if (doclintOpts.size() == 1
817                 && doclintOpts.get(0).equals(DocLint.XMSGS_CUSTOM_PREFIX + "none")) {
818             return;
819         }
820 
821         String sep = "";
822         StringBuilder customTags = new StringBuilder();
823         for (String customTag : customTagNames) {
824             customTags.append(sep);
825             customTags.append(customTag);
826             sep = DocLint.TAGS_SEPARATOR;
827         }
828         doclintOpts.add(DocLint.XCUSTOM_TAGS_PREFIX + customTags.toString());
829 
830         JavacTask t = BasicJavacTask.instance(context);
831         doclint = new DocLint();
832         // standard doclet normally generates H1, H2
833         doclintOpts.add(DocLint.XIMPLICIT_HEADERS + "2");
834         doclint.init(t, doclintOpts.toArray(new String[doclintOpts.size()]), false);
835     }
836 
837     boolean showTagMessages() {
838         return (doclint == null);
839     }
840 }