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