001: /*
002: * Copyright 2000-2006 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package com.sun.tools.javadoc;
027:
028: import java.util.*;
029: import java.lang.reflect.Modifier;
030:
031: import com.sun.javadoc.*;
032:
033: import com.sun.tools.javac.code.*;
034: import com.sun.tools.javac.code.Symbol.*;
035: import com.sun.tools.javac.code.Type.ClassType;
036: import com.sun.tools.javac.code.Type.TypeVar;
037: import com.sun.tools.javac.comp.Attr;
038: import com.sun.tools.javac.comp.Check;
039: import com.sun.tools.javac.tree.JCTree.*;
040: import com.sun.tools.javac.util.Context;
041: import com.sun.tools.javac.util.List;
042: import com.sun.tools.javac.util.Name;
043: import com.sun.tools.javac.util.Position;
044:
045: /**
046: * Holds the environment for a run of javadoc.
047: * Holds only the information needed throughout the
048: * run and not the compiler info that could be GC'ed
049: * or ported.
050: *
051: * @since 1.4
052: * @author Robert Field
053: * @author Neal Gafter (rewrite)
054: * @author Scott Seligman (generics)
055: */
056: public class DocEnv {
057: protected static final Context.Key<DocEnv> docEnvKey = new Context.Key<DocEnv>();
058:
059: public static DocEnv instance(Context context) {
060: DocEnv instance = context.get(docEnvKey);
061: if (instance == null)
062: instance = new DocEnv(context);
063: return instance;
064: }
065:
066: private Messager messager;
067:
068: DocLocale doclocale;
069:
070: /** Predefined symbols known to the compiler. */
071: Symtab syms;
072:
073: /** Referenced directly in RootDocImpl. */
074: JavadocClassReader reader;
075:
076: /** The compiler's attribution phase (needed to evaluate
077: * constant initializers). */
078: Attr attr;
079:
080: /** Javadoc's own version of the compiler's enter phase. */
081: JavadocEnter enter;
082:
083: /** The name table. */
084: Name.Table names;
085:
086: /** The encoding name. */
087: private String encoding;
088:
089: final Symbol externalizableSym;
090:
091: /** Access filter (public, protected, ...). */
092: ModifierFilter showAccess;
093:
094: private ClassDocImpl runtimeException;
095:
096: /** True if we are using a sentence BreakIterator. */
097: boolean breakiterator;
098:
099: /**
100: * True if we do not want to print any notifications at all.
101: */
102: boolean quiet = false;
103:
104: Check chk;
105: Types types;
106:
107: /** Allow documenting from class files? */
108: boolean docClasses = false;
109:
110: /** Does the doclet only expect pre-1.5 doclet API? */
111: boolean legacyDoclet = true;
112:
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;
118:
119: /**
120: * Constructor
121: *
122: * @param context Context for this javadoc instance.
123: */
124: private DocEnv(Context context) {
125: context.put(docEnvKey, this );
126:
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 = Name.Table.instance(context);
133: externalizableSym = reader.enterClass(names
134: .fromString("java.io.Externalizable"));
135: chk = Check.instance(context);
136: types = Types.instance(context);
137:
138: // Default. Should normally be reset with setLocale.
139: this .doclocale = new DocLocale(this , "", breakiterator);
140: }
141:
142: public void setSilent(boolean silent) {
143: this .silent = silent;
144: }
145:
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: }
157:
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: }
170:
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:
188: // where
189: /** Retrieve class symbol by fully-qualified name.
190: */
191: ClassSymbol getClassSymbol(String name) {
192: // Name may contain nested class qualification.
193: // Generate candidate flatnames with successively shorter
194: // package qualifiers and longer nested class qualifiers.
195: int nameLen = name.length();
196: char[] nameChars = name.toCharArray();
197: int idx = name.length();
198: for (;;) {
199: ClassSymbol s = syms.classes.get(names.fromChars(nameChars,
200: 0, nameLen));
201: if (s != null)
202: return s; // found it!
203: idx = name.substring(0, idx).lastIndexOf('.');
204: if (idx < 0)
205: break;
206: nameChars[idx] = '$';
207: }
208: return null;
209: }
210:
211: /**
212: * Set the locale.
213: */
214: public void setLocale(String localeName) {
215: // create locale specifics
216: doclocale = new DocLocale(this , localeName, breakiterator);
217: // reset Messager if locale has changed.
218: messager.reset();
219: }
220:
221: /** Check whether this member should be documented. */
222: public boolean shouldDocument(VarSymbol sym) {
223: long mod = sym.flags();
224:
225: if ((mod & Flags.SYNTHETIC) != 0) {
226: return false;
227: }
228:
229: return showAccess.checkModifier(translateModifiers(mod));
230: }
231:
232: /** Check whether this member should be documented. */
233: public boolean shouldDocument(MethodSymbol sym) {
234: long mod = sym.flags();
235:
236: if ((mod & Flags.SYNTHETIC) != 0) {
237: return false;
238: }
239:
240: return showAccess.checkModifier(translateModifiers(mod));
241: }
242:
243: /** check whether this class should be documented. */
244: public boolean shouldDocument(ClassSymbol sym) {
245: return (sym.flags_field & Flags.SYNTHETIC) == 0
246: && // no synthetics
247: (docClasses || getClassDoc(sym).tree != null)
248: && isVisible(sym);
249: }
250:
251: //### Comment below is inaccurate wrt modifier filter testing
252: /**
253: * Check the visibility if this is an nested class.
254: * if this is not a nested class, return true.
255: * if this is an static visible nested class,
256: * return true.
257: * if this is an visible nested class
258: * if the outer class is visible return true.
259: * else return false.
260: * IMPORTANT: This also allows, static nested classes
261: * to be defined inside an nested class, which is not
262: * allowed by the compiler. So such an test case will
263: * not reach upto this method itself, but if compiler
264: * allows it, then that will go through.
265: */
266: protected boolean isVisible(ClassSymbol sym) {
267: long mod = sym.flags_field;
268: if (!showAccess.checkModifier(translateModifiers(mod))) {
269: return false;
270: }
271: ClassSymbol encl = sym.owner.enclClass();
272: return (encl == null || (mod & Flags.STATIC) != 0 || isVisible(encl));
273: }
274:
275: //---------------- print forwarders ----------------//
276:
277: /**
278: * Print error message, increment error count.
279: *
280: * @param msg message to print.
281: */
282: public void printError(String msg) {
283: if (silent)
284: return;
285: messager.printError(msg);
286: }
287:
288: /**
289: * Print error message, increment error count.
290: *
291: * @param key selects message from resource
292: */
293: public void error(DocImpl doc, String key) {
294: if (silent)
295: return;
296: messager.error(doc == null ? null : doc.position(), key);
297: }
298:
299: /**
300: * Print error message, increment error count.
301: *
302: * @param key selects message from resource
303: */
304: public void error(SourcePosition pos, String key) {
305: if (silent)
306: return;
307: messager.error(pos, key);
308: }
309:
310: /**
311: * Print error message, increment error count.
312: *
313: * @param msg message to print.
314: */
315: public void printError(SourcePosition pos, String msg) {
316: if (silent)
317: return;
318: messager.printError(pos, msg);
319: }
320:
321: /**
322: * Print error message, increment error count.
323: *
324: * @param key selects message from resource
325: * @param a1 first argument
326: */
327: public void error(DocImpl doc, String key, String a1) {
328: if (silent)
329: return;
330: messager.error(doc == null ? null : doc.position(), key, a1);
331: }
332:
333: /**
334: * Print error message, increment error count.
335: *
336: * @param key selects message from resource
337: * @param a1 first argument
338: * @param a2 second argument
339: */
340: public void error(DocImpl doc, String key, String a1, String a2) {
341: if (silent)
342: return;
343: messager
344: .error(doc == null ? null : doc.position(), key, a1, a2);
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: * @param a3 third argument
354: */
355: public void error(DocImpl doc, String key, String a1, String a2,
356: String a3) {
357: if (silent)
358: return;
359: messager.error(doc == null ? null : doc.position(), key, a1,
360: a2, a3);
361: }
362:
363: /**
364: * Print warning message, increment warning count.
365: *
366: * @param msg message to print.
367: */
368: public void printWarning(String msg) {
369: if (silent)
370: return;
371: messager.printWarning(msg);
372: }
373:
374: /**
375: * Print warning message, increment warning count.
376: *
377: * @param key selects message from resource
378: */
379: public void warning(DocImpl doc, String key) {
380: if (silent)
381: return;
382: messager.warning(doc == null ? null : doc.position(), key);
383: }
384:
385: /**
386: * Print warning message, increment warning count.
387: *
388: * @param msg message to print.
389: */
390: public void printWarning(SourcePosition pos, String msg) {
391: if (silent)
392: return;
393: messager.printWarning(pos, msg);
394: }
395:
396: /**
397: * Print warning message, increment warning count.
398: *
399: * @param key selects message from resource
400: * @param a1 first argument
401: */
402: public void warning(DocImpl doc, String key, String a1) {
403: if (silent)
404: return;
405: messager.warning(doc == null ? null : doc.position(), key, a1);
406: }
407:
408: /**
409: * Print warning message, increment warning count.
410: *
411: * @param key selects message from resource
412: * @param a1 first argument
413: * @param a2 second argument
414: */
415: public void warning(DocImpl doc, String key, String a1, String a2) {
416: if (silent)
417: return;
418: messager.warning(doc == null ? null : doc.position(), key, a1,
419: a2);
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: * @param a3 third argument
429: */
430: public void warning(DocImpl doc, String key, String a1, String a2,
431: String a3) {
432: if (silent)
433: return;
434: messager.warning(doc == null ? null : doc.position(), key, a1,
435: a2, a3);
436: }
437:
438: /**
439: * Print warning message, increment warning count.
440: *
441: * @param key selects message from resource
442: * @param a1 first argument
443: * @param a2 second argument
444: * @param a3 third argument
445: */
446: public void warning(DocImpl doc, String key, String a1, String a2,
447: String a3, String a4) {
448: if (silent)
449: return;
450: messager.warning(doc == null ? null : doc.position(), key, a1,
451: a2, a3, a4);
452: }
453:
454: /**
455: * Print a message.
456: *
457: * @param msg message to print.
458: */
459: public void printNotice(String msg) {
460: if (silent || quiet)
461: return;
462: messager.printNotice(msg);
463: }
464:
465: /**
466: * Print a message.
467: *
468: * @param key selects message from resource
469: */
470: public void notice(String key) {
471: if (silent || quiet)
472: return;
473: messager.notice(key);
474: }
475:
476: /**
477: * Print a message.
478: *
479: * @param msg message to print.
480: */
481: public void printNotice(SourcePosition pos, String msg) {
482: if (silent || quiet)
483: return;
484: messager.printNotice(pos, msg);
485: }
486:
487: /**
488: * Print a message.
489: *
490: * @param key selects message from resource
491: * @param a1 first argument
492: */
493: public void notice(String key, String a1) {
494: if (silent || quiet)
495: return;
496: messager.notice(key, a1);
497: }
498:
499: /**
500: * Print a message.
501: *
502: * @param key selects message from resource
503: * @param a1 first argument
504: * @param a2 second argument
505: */
506: public void notice(String key, String a1, String a2) {
507: if (silent || quiet)
508: return;
509: messager.notice(key, a1, a2);
510: }
511:
512: /**
513: * Print a message.
514: *
515: * @param key selects message from resource
516: * @param a1 first argument
517: * @param a2 second argument
518: * @param a3 third argument
519: */
520: public void notice(String key, String a1, String a2, String a3) {
521: if (silent || quiet)
522: return;
523: messager.notice(key, a1, a2, a3);
524: }
525:
526: /**
527: * Exit, reporting errors and warnings.
528: */
529: public void exit() {
530: // Messager should be replaced by a more general
531: // compilation environment. This can probably
532: // subsume DocEnv as well.
533: messager.exit();
534: }
535:
536: private Map<PackageSymbol, PackageDocImpl> packageMap = new HashMap<PackageSymbol, PackageDocImpl>();
537:
538: /**
539: * Return the PackageDoc of this package symbol.
540: */
541: public PackageDocImpl getPackageDoc(PackageSymbol pack) {
542: PackageDocImpl result = packageMap.get(pack);
543: if (result != null)
544: return result;
545: result = new PackageDocImpl(this , pack);
546: packageMap.put(pack, result);
547: return result;
548: }
549:
550: /**
551: * Create the PackageDoc (or a subtype) for a package symbol.
552: */
553: void makePackageDoc(PackageSymbol pack, String docComment,
554: JCCompilationUnit tree) {
555: PackageDocImpl result = packageMap.get(pack);
556: if (result != null) {
557: if (docComment != null)
558: result.setRawCommentText(docComment);
559: if (tree != null)
560: result.setTree(tree);
561: } else {
562: result = new PackageDocImpl(this , pack, docComment, tree);
563: packageMap.put(pack, result);
564: }
565: }
566:
567: private Map<ClassSymbol, ClassDocImpl> classMap = new HashMap<ClassSymbol, ClassDocImpl>();
568:
569: /**
570: * Return the ClassDoc (or a subtype) of this class symbol.
571: */
572: ClassDocImpl getClassDoc(ClassSymbol clazz) {
573: ClassDocImpl result = classMap.get(clazz);
574: if (result != null)
575: return result;
576: if (isAnnotationType(clazz)) {
577: result = new AnnotationTypeDocImpl(this , clazz);
578: } else {
579: result = new ClassDocImpl(this , clazz);
580: }
581: classMap.put(clazz, result);
582: return result;
583: }
584:
585: /**
586: * Create the ClassDoc (or a subtype) for a class symbol.
587: */
588: void makeClassDoc(ClassSymbol clazz, String docComment,
589: JCClassDecl tree, Position.LineMap lineMap) {
590: ClassDocImpl result = classMap.get(clazz);
591: if (result != null) {
592: if (docComment != null)
593: result.setRawCommentText(docComment);
594: if (tree != null)
595: result.setTree(tree);
596: return;
597: }
598: if (isAnnotationType(tree)) { // flags of clazz may not yet be set
599: result = new AnnotationTypeDocImpl(this , clazz, docComment,
600: tree, lineMap);
601: } else {
602: result = new ClassDocImpl(this , clazz, docComment, tree,
603: lineMap);
604: }
605: classMap.put(clazz, result);
606: }
607:
608: private static boolean isAnnotationType(ClassSymbol clazz) {
609: return ClassDocImpl.isAnnotationType(clazz);
610: }
611:
612: private static boolean isAnnotationType(JCClassDecl tree) {
613: return (tree.mods.flags & Flags.ANNOTATION) != 0;
614: }
615:
616: private Map<VarSymbol, FieldDocImpl> fieldMap = new HashMap<VarSymbol, FieldDocImpl>();
617:
618: /**
619: * Return the FieldDoc of this var symbol.
620: */
621: FieldDocImpl getFieldDoc(VarSymbol var) {
622: FieldDocImpl result = fieldMap.get(var);
623: if (result != null)
624: return result;
625: result = new FieldDocImpl(this , var);
626: fieldMap.put(var, result);
627: return result;
628: }
629:
630: /**
631: * Create a FieldDoc for a var symbol.
632: */
633: void makeFieldDoc(VarSymbol var, String docComment,
634: JCVariableDecl tree, Position.LineMap lineMap) {
635: FieldDocImpl result = fieldMap.get(var);
636: if (result != null) {
637: if (docComment != null)
638: result.setRawCommentText(docComment);
639: if (tree != null)
640: result.setTree(tree);
641: } else {
642: result = new FieldDocImpl(this , var, docComment, tree,
643: lineMap);
644: fieldMap.put(var, result);
645: }
646: }
647:
648: private Map<MethodSymbol, ExecutableMemberDocImpl> methodMap = new HashMap<MethodSymbol, ExecutableMemberDocImpl>();
649:
650: /**
651: * Create a MethodDoc for this MethodSymbol.
652: * Should be called only on symbols representing methods.
653: */
654: void makeMethodDoc(MethodSymbol meth, String docComment,
655: JCMethodDecl tree, Position.LineMap lineMap) {
656: MethodDocImpl result = (MethodDocImpl) methodMap.get(meth);
657: if (result != null) {
658: if (docComment != null)
659: result.setRawCommentText(docComment);
660: if (tree != null)
661: result.setTree(tree);
662: } else {
663: result = new MethodDocImpl(this , meth, docComment, tree,
664: lineMap);
665: methodMap.put(meth, result);
666: }
667: }
668:
669: /**
670: * Return the MethodDoc for a MethodSymbol.
671: * Should be called only on symbols representing methods.
672: */
673: public MethodDocImpl getMethodDoc(MethodSymbol meth) {
674: MethodDocImpl result = (MethodDocImpl) methodMap.get(meth);
675: if (result != null)
676: return result;
677: result = new MethodDocImpl(this , meth);
678: methodMap.put(meth, result);
679: return result;
680: }
681:
682: /**
683: * Create the ConstructorDoc for a MethodSymbol.
684: * Should be called only on symbols representing constructors.
685: */
686: void makeConstructorDoc(MethodSymbol meth, String docComment,
687: JCMethodDecl tree, Position.LineMap lineMap) {
688: ConstructorDocImpl result = (ConstructorDocImpl) methodMap
689: .get(meth);
690: if (result != null) {
691: if (docComment != null)
692: result.setRawCommentText(docComment);
693: if (tree != null)
694: result.setTree(tree);
695: } else {
696: result = new ConstructorDocImpl(this , meth, docComment,
697: tree, lineMap);
698: methodMap.put(meth, result);
699: }
700: }
701:
702: /**
703: * Return the ConstructorDoc for a MethodSymbol.
704: * Should be called only on symbols representing constructors.
705: */
706: public ConstructorDocImpl getConstructorDoc(MethodSymbol meth) {
707: ConstructorDocImpl result = (ConstructorDocImpl) methodMap
708: .get(meth);
709: if (result != null)
710: return result;
711: result = new ConstructorDocImpl(this , meth);
712: methodMap.put(meth, result);
713: return result;
714: }
715:
716: /**
717: * Create the AnnotationTypeElementDoc for a MethodSymbol.
718: * Should be called only on symbols representing annotation type elements.
719: */
720: void makeAnnotationTypeElementDoc(MethodSymbol meth,
721: String docComment, JCMethodDecl tree,
722: Position.LineMap lineMap) {
723: AnnotationTypeElementDocImpl result = (AnnotationTypeElementDocImpl) methodMap
724: .get(meth);
725: if (result != null) {
726: if (docComment != null)
727: result.setRawCommentText(docComment);
728: if (tree != null)
729: result.setTree(tree);
730: } else {
731: result = new AnnotationTypeElementDocImpl(this , meth,
732: docComment, tree, lineMap);
733: methodMap.put(meth, result);
734: }
735: }
736:
737: /**
738: * Return the AnnotationTypeElementDoc for a MethodSymbol.
739: * Should be called only on symbols representing annotation type elements.
740: */
741: public AnnotationTypeElementDocImpl getAnnotationTypeElementDoc(
742: MethodSymbol meth) {
743:
744: AnnotationTypeElementDocImpl result = (AnnotationTypeElementDocImpl) methodMap
745: .get(meth);
746: if (result != null)
747: return result;
748: result = new AnnotationTypeElementDocImpl(this , meth);
749: methodMap.put(meth, result);
750: return result;
751: }
752:
753: // private Map<ClassType, ParameterizedTypeImpl> parameterizedTypeMap =
754: // new HashMap<ClassType, ParameterizedTypeImpl>();
755: /**
756: * Return the ParameterizedType of this instantiation.
757: // * ### Could use Type.sameTypeAs() instead of equality matching in hashmap
758: // * ### to avoid some duplication.
759: */
760: ParameterizedTypeImpl getParameterizedType(ClassType t) {
761: return new ParameterizedTypeImpl(this , t);
762: // ParameterizedTypeImpl result = parameterizedTypeMap.get(t);
763: // if (result != null) return result;
764: // result = new ParameterizedTypeImpl(this, t);
765: // parameterizedTypeMap.put(t, result);
766: // return result;
767: }
768:
769: /**
770: * Set the encoding.
771: */
772: public void setEncoding(String encoding) {
773: this .encoding = encoding;
774: }
775:
776: /**
777: * Get the encoding.
778: */
779: public String getEncoding() {
780: return encoding;
781: }
782:
783: /**
784: * Convert modifier bits from private coding used by
785: * the compiler to that of java.lang.reflect.Modifier.
786: */
787: static int translateModifiers(long flags) {
788: int result = 0;
789: if ((flags & Flags.ABSTRACT) != 0)
790: result |= Modifier.ABSTRACT;
791: if ((flags & Flags.FINAL) != 0)
792: result |= Modifier.FINAL;
793: if ((flags & Flags.INTERFACE) != 0)
794: result |= Modifier.INTERFACE;
795: if ((flags & Flags.NATIVE) != 0)
796: result |= Modifier.NATIVE;
797: if ((flags & Flags.PRIVATE) != 0)
798: result |= Modifier.PRIVATE;
799: if ((flags & Flags.PROTECTED) != 0)
800: result |= Modifier.PROTECTED;
801: if ((flags & Flags.PUBLIC) != 0)
802: result |= Modifier.PUBLIC;
803: if ((flags & Flags.STATIC) != 0)
804: result |= Modifier.STATIC;
805: if ((flags & Flags.SYNCHRONIZED) != 0)
806: result |= Modifier.SYNCHRONIZED;
807: if ((flags & Flags.TRANSIENT) != 0)
808: result |= Modifier.TRANSIENT;
809: if ((flags & Flags.VOLATILE) != 0)
810: result |= Modifier.VOLATILE;
811: return result;
812: }
813: }
|