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