Tue, 11 Aug 2009 01:13:14 +0100
6521805: Regression: JDK5/JDK6 javac allows write access to outer class reference
Summary: javac should warn/complain about identifiers with the same name as synthetic symbol
Reviewed-by: jjg
1 /*
2 * Copyright 2000-2009 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.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.Attr;
38 import com.sun.tools.javac.comp.Check;
39 import com.sun.tools.javac.tree.JCTree.*;
40 import com.sun.tools.javac.util.Context;
41 import com.sun.tools.javac.util.Names;
42 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;
106 JavaFileManager fileManager;
108 /** Allow documenting from class files? */
109 boolean docClasses = false;
111 /** Does the doclet only expect pre-1.5 doclet API? */
112 boolean legacyDoclet = true;
114 /**
115 * Set this to true if you would like to not emit any errors, warnings and
116 * notices.
117 */
118 private boolean silent = false;
120 /**
121 * Constructor
122 *
123 * @param context Context for this javadoc instance.
124 */
125 private DocEnv(Context context) {
126 context.put(docEnvKey, this);
128 messager = Messager.instance0(context);
129 syms = Symtab.instance(context);
130 reader = JavadocClassReader.instance0(context);
131 enter = JavadocEnter.instance0(context);
132 attr = Attr.instance(context);
133 names = Names.instance(context);
134 externalizableSym = reader.enterClass(names.fromString("java.io.Externalizable"));
135 chk = Check.instance(context);
136 types = Types.instance(context);
137 fileManager = context.get(JavaFileManager.class);
139 // Default. Should normally be reset with setLocale.
140 this.doclocale = new DocLocale(this, "", breakiterator);
141 }
143 public void setSilent(boolean silent) {
144 this.silent = silent;
145 }
147 /**
148 * Look up ClassDoc by qualified name.
149 */
150 public ClassDocImpl lookupClass(String name) {
151 ClassSymbol c = getClassSymbol(name);
152 if (c != null) {
153 return getClassDoc(c);
154 } else {
155 return null;
156 }
157 }
159 /**
160 * Load ClassDoc by qualified name.
161 */
162 public ClassDocImpl loadClass(String name) {
163 try {
164 ClassSymbol c = reader.loadClass(names.fromString(name));
165 return getClassDoc(c);
166 } catch (CompletionFailure ex) {
167 chk.completionError(null, ex);
168 return null;
169 }
170 }
172 /**
173 * Look up PackageDoc by qualified name.
174 */
175 public PackageDocImpl lookupPackage(String name) {
176 //### Jing alleges that class check is needed
177 //### to avoid a compiler bug. Most likely
178 //### instead a dummy created for error recovery.
179 //### Should investigate this.
180 PackageSymbol p = syms.packages.get(names.fromString(name));
181 ClassSymbol c = getClassSymbol(name);
182 if (p != null && c == null) {
183 return getPackageDoc(p);
184 } else {
185 return null;
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, 0, nameLen));
200 if (s != null)
201 return s; // found it!
202 idx = name.substring(0, idx).lastIndexOf('.');
203 if (idx < 0) break;
204 nameChars[idx] = '$';
205 }
206 return null;
207 }
209 /**
210 * Set the locale.
211 */
212 public void setLocale(String localeName) {
213 // create locale specifics
214 doclocale = new DocLocale(this, localeName, breakiterator);
215 // reset Messager if locale has changed.
216 messager.reset();
217 }
219 /** Check whether this member should be documented. */
220 public boolean shouldDocument(VarSymbol sym) {
221 long mod = sym.flags();
223 if ((mod & Flags.SYNTHETIC) != 0) {
224 return false;
225 }
227 return showAccess.checkModifier(translateModifiers(mod));
228 }
230 /** Check whether this member should be documented. */
231 public boolean shouldDocument(MethodSymbol sym) {
232 long mod = sym.flags();
234 if ((mod & Flags.SYNTHETIC) != 0) {
235 return false;
236 }
238 return showAccess.checkModifier(translateModifiers(mod));
239 }
241 /** check whether this class should be documented. */
242 public boolean shouldDocument(ClassSymbol sym) {
243 return
244 (sym.flags_field&Flags.SYNTHETIC) == 0 && // no synthetics
245 (docClasses || getClassDoc(sym).tree != null) &&
246 isVisible(sym);
247 }
249 //### Comment below is inaccurate wrt modifier filter testing
250 /**
251 * Check the visibility if this is an nested class.
252 * if this is not a nested class, return true.
253 * if this is an static visible nested class,
254 * return true.
255 * if this is an visible nested class
256 * if the outer class is visible return true.
257 * else return false.
258 * IMPORTANT: This also allows, static nested classes
259 * to be defined inside an nested class, which is not
260 * allowed by the compiler. So such an test case will
261 * not reach upto this method itself, but if compiler
262 * allows it, then that will go through.
263 */
264 protected boolean isVisible(ClassSymbol sym) {
265 long mod = sym.flags_field;
266 if (!showAccess.checkModifier(translateModifiers(mod))) {
267 return false;
268 }
269 ClassSymbol encl = sym.owner.enclClass();
270 return (encl == null || (mod & Flags.STATIC) != 0 || isVisible(encl));
271 }
273 //---------------- print forwarders ----------------//
275 /**
276 * Print error message, increment error count.
277 *
278 * @param msg message to print.
279 */
280 public void printError(String msg) {
281 if (silent)
282 return;
283 messager.printError(msg);
284 }
286 /**
287 * Print error message, increment error count.
288 *
289 * @param key selects message from resource
290 */
291 public void error(DocImpl doc, String key) {
292 if (silent)
293 return;
294 messager.error(doc==null ? null : doc.position(), key);
295 }
297 /**
298 * Print error message, increment error count.
299 *
300 * @param key selects message from resource
301 */
302 public void error(SourcePosition pos, String key) {
303 if (silent)
304 return;
305 messager.error(pos, key);
306 }
308 /**
309 * Print error message, increment error count.
310 *
311 * @param msg message to print.
312 */
313 public void printError(SourcePosition pos, String msg) {
314 if (silent)
315 return;
316 messager.printError(pos, msg);
317 }
319 /**
320 * Print error message, increment error count.
321 *
322 * @param key selects message from resource
323 * @param a1 first argument
324 */
325 public void error(DocImpl doc, String key, String a1) {
326 if (silent)
327 return;
328 messager.error(doc==null ? null : doc.position(), key, a1);
329 }
331 /**
332 * Print error message, increment error count.
333 *
334 * @param key selects message from resource
335 * @param a1 first argument
336 * @param a2 second argument
337 */
338 public void error(DocImpl doc, String key, String a1, String a2) {
339 if (silent)
340 return;
341 messager.error(doc==null ? null : doc.position(), key, a1, a2);
342 }
344 /**
345 * Print error message, increment error count.
346 *
347 * @param key selects message from resource
348 * @param a1 first argument
349 * @param a2 second argument
350 * @param a3 third argument
351 */
352 public void error(DocImpl doc, String key, String a1, String a2, String a3) {
353 if (silent)
354 return;
355 messager.error(doc==null ? null : doc.position(), key, a1, a2, a3);
356 }
358 /**
359 * Print warning message, increment warning count.
360 *
361 * @param msg message to print.
362 */
363 public void printWarning(String msg) {
364 if (silent)
365 return;
366 messager.printWarning(msg);
367 }
369 /**
370 * Print warning message, increment warning count.
371 *
372 * @param key selects message from resource
373 */
374 public void warning(DocImpl doc, String key) {
375 if (silent)
376 return;
377 messager.warning(doc==null ? null : doc.position(), key);
378 }
380 /**
381 * Print warning message, increment warning count.
382 *
383 * @param msg message to print.
384 */
385 public void printWarning(SourcePosition pos, String msg) {
386 if (silent)
387 return;
388 messager.printWarning(pos, msg);
389 }
391 /**
392 * Print warning message, increment warning count.
393 *
394 * @param key selects message from resource
395 * @param a1 first argument
396 */
397 public void warning(DocImpl doc, String key, String a1) {
398 if (silent)
399 return;
400 messager.warning(doc==null ? null : doc.position(), key, a1);
401 }
403 /**
404 * Print warning message, increment warning count.
405 *
406 * @param key selects message from resource
407 * @param a1 first argument
408 * @param a2 second argument
409 */
410 public void warning(DocImpl doc, String key, String a1, String a2) {
411 if (silent)
412 return;
413 messager.warning(doc==null ? null : doc.position(), key, a1, a2);
414 }
416 /**
417 * Print warning message, increment warning count.
418 *
419 * @param key selects message from resource
420 * @param a1 first argument
421 * @param a2 second argument
422 * @param a3 third argument
423 */
424 public void warning(DocImpl doc, String key, String a1, String a2, String a3) {
425 if (silent)
426 return;
427 messager.warning(doc==null ? null : doc.position(), key, a1, a2, a3);
428 }
430 /**
431 * Print warning message, increment warning count.
432 *
433 * @param key selects message from resource
434 * @param a1 first argument
435 * @param a2 second argument
436 * @param a3 third argument
437 */
438 public void warning(DocImpl doc, String key, String a1, String a2, String a3,
439 String a4) {
440 if (silent)
441 return;
442 messager.warning(doc==null ? null : doc.position(), key, a1, a2, a3, a4);
443 }
445 /**
446 * Print a message.
447 *
448 * @param msg message to print.
449 */
450 public void printNotice(String msg) {
451 if (silent || quiet)
452 return;
453 messager.printNotice(msg);
454 }
457 /**
458 * Print a message.
459 *
460 * @param key selects message from resource
461 */
462 public void notice(String key) {
463 if (silent || quiet)
464 return;
465 messager.notice(key);
466 }
468 /**
469 * Print a message.
470 *
471 * @param msg message to print.
472 */
473 public void printNotice(SourcePosition pos, String msg) {
474 if (silent || quiet)
475 return;
476 messager.printNotice(pos, msg);
477 }
479 /**
480 * Print a message.
481 *
482 * @param key selects message from resource
483 * @param a1 first argument
484 */
485 public void notice(String key, String a1) {
486 if (silent || quiet)
487 return;
488 messager.notice(key, a1);
489 }
491 /**
492 * Print a message.
493 *
494 * @param key selects message from resource
495 * @param a1 first argument
496 * @param a2 second argument
497 */
498 public void notice(String key, String a1, String a2) {
499 if (silent || quiet)
500 return;
501 messager.notice(key, a1, a2);
502 }
504 /**
505 * Print a message.
506 *
507 * @param key selects message from resource
508 * @param a1 first argument
509 * @param a2 second argument
510 * @param a3 third argument
511 */
512 public void notice(String key, String a1, String a2, String a3) {
513 if (silent || quiet)
514 return;
515 messager.notice(key, a1, a2, a3);
516 }
518 /**
519 * Exit, reporting errors and warnings.
520 */
521 public void exit() {
522 // Messager should be replaced by a more general
523 // compilation environment. This can probably
524 // subsume DocEnv as well.
525 messager.exit();
526 }
528 private Map<PackageSymbol, PackageDocImpl> packageMap =
529 new HashMap<PackageSymbol, PackageDocImpl>();
530 /**
531 * Return the PackageDoc of this package symbol.
532 */
533 public PackageDocImpl getPackageDoc(PackageSymbol pack) {
534 PackageDocImpl result = packageMap.get(pack);
535 if (result != null) return result;
536 result = new PackageDocImpl(this, pack);
537 packageMap.put(pack, result);
538 return result;
539 }
541 /**
542 * Create the PackageDoc (or a subtype) for a package symbol.
543 */
544 void makePackageDoc(PackageSymbol pack, String docComment, JCCompilationUnit tree) {
545 PackageDocImpl result = packageMap.get(pack);
546 if (result != null) {
547 if (docComment != null) result.setRawCommentText(docComment);
548 if (tree != null) result.setTree(tree);
549 } else {
550 result = new PackageDocImpl(this, pack, docComment, tree);
551 packageMap.put(pack, result);
552 }
553 }
556 private Map<ClassSymbol, ClassDocImpl> classMap =
557 new HashMap<ClassSymbol, ClassDocImpl>();
558 /**
559 * Return the ClassDoc (or a subtype) of this class symbol.
560 */
561 ClassDocImpl getClassDoc(ClassSymbol clazz) {
562 ClassDocImpl result = classMap.get(clazz);
563 if (result != null) return result;
564 if (isAnnotationType(clazz)) {
565 result = new AnnotationTypeDocImpl(this, clazz);
566 } else {
567 result = new ClassDocImpl(this, clazz);
568 }
569 classMap.put(clazz, result);
570 return result;
571 }
573 /**
574 * Create the ClassDoc (or a subtype) for a class symbol.
575 */
576 void makeClassDoc(ClassSymbol clazz, String docComment, JCClassDecl tree, Position.LineMap lineMap) {
577 ClassDocImpl result = classMap.get(clazz);
578 if (result != null) {
579 if (docComment != null) result.setRawCommentText(docComment);
580 if (tree != null) result.setTree(tree);
581 return;
582 }
583 if (isAnnotationType(tree)) { // flags of clazz may not yet be set
584 result = new AnnotationTypeDocImpl(this, clazz, docComment, tree, lineMap);
585 } else {
586 result = new ClassDocImpl(this, clazz, docComment, tree, lineMap);
587 }
588 classMap.put(clazz, result);
589 }
591 private static boolean isAnnotationType(ClassSymbol clazz) {
592 return ClassDocImpl.isAnnotationType(clazz);
593 }
595 private static boolean isAnnotationType(JCClassDecl tree) {
596 return (tree.mods.flags & Flags.ANNOTATION) != 0;
597 }
599 private Map<VarSymbol, FieldDocImpl> fieldMap =
600 new HashMap<VarSymbol, FieldDocImpl>();
601 /**
602 * Return the FieldDoc of this var symbol.
603 */
604 FieldDocImpl getFieldDoc(VarSymbol var) {
605 FieldDocImpl result = fieldMap.get(var);
606 if (result != null) return result;
607 result = new FieldDocImpl(this, var);
608 fieldMap.put(var, result);
609 return result;
610 }
611 /**
612 * Create a FieldDoc for a var symbol.
613 */
614 void makeFieldDoc(VarSymbol var, String docComment, JCVariableDecl tree, Position.LineMap lineMap) {
615 FieldDocImpl result = fieldMap.get(var);
616 if (result != null) {
617 if (docComment != null) result.setRawCommentText(docComment);
618 if (tree != null) result.setTree(tree);
619 } else {
620 result = new FieldDocImpl(this, var, docComment, tree, lineMap);
621 fieldMap.put(var, result);
622 }
623 }
625 private Map<MethodSymbol, ExecutableMemberDocImpl> methodMap =
626 new HashMap<MethodSymbol, ExecutableMemberDocImpl>();
627 /**
628 * Create a MethodDoc for this MethodSymbol.
629 * Should be called only on symbols representing methods.
630 */
631 void makeMethodDoc(MethodSymbol meth, String docComment,
632 JCMethodDecl tree, Position.LineMap lineMap) {
633 MethodDocImpl result = (MethodDocImpl)methodMap.get(meth);
634 if (result != null) {
635 if (docComment != null) result.setRawCommentText(docComment);
636 if (tree != null) result.setTree(tree);
637 } else {
638 result = new MethodDocImpl(this, meth, docComment, tree, lineMap);
639 methodMap.put(meth, result);
640 }
641 }
643 /**
644 * Return the MethodDoc for a MethodSymbol.
645 * Should be called only on symbols representing methods.
646 */
647 public MethodDocImpl getMethodDoc(MethodSymbol meth) {
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 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 ConstructorDocImpl result = (ConstructorDocImpl)methodMap.get(meth);
677 if (result != null) return result;
678 result = new ConstructorDocImpl(this, meth);
679 methodMap.put(meth, result);
680 return result;
681 }
683 /**
684 * Create the AnnotationTypeElementDoc for a MethodSymbol.
685 * Should be called only on symbols representing annotation type elements.
686 */
687 void makeAnnotationTypeElementDoc(MethodSymbol meth,
688 String docComment, JCMethodDecl tree, Position.LineMap lineMap) {
689 AnnotationTypeElementDocImpl result =
690 (AnnotationTypeElementDocImpl)methodMap.get(meth);
691 if (result != null) {
692 if (docComment != null) result.setRawCommentText(docComment);
693 if (tree != null) result.setTree(tree);
694 } else {
695 result =
696 new AnnotationTypeElementDocImpl(this, meth, docComment, tree, lineMap);
697 methodMap.put(meth, result);
698 }
699 }
701 /**
702 * Return the AnnotationTypeElementDoc for a MethodSymbol.
703 * Should be called only on symbols representing annotation type elements.
704 */
705 public AnnotationTypeElementDocImpl getAnnotationTypeElementDoc(
706 MethodSymbol meth) {
708 AnnotationTypeElementDocImpl result =
709 (AnnotationTypeElementDocImpl)methodMap.get(meth);
710 if (result != null) return result;
711 result = new AnnotationTypeElementDocImpl(this, meth);
712 methodMap.put(meth, result);
713 return result;
714 }
716 // private Map<ClassType, ParameterizedTypeImpl> parameterizedTypeMap =
717 // new HashMap<ClassType, ParameterizedTypeImpl>();
718 /**
719 * Return the ParameterizedType of this instantiation.
720 // * ### Could use Type.sameTypeAs() instead of equality matching in hashmap
721 // * ### to avoid some duplication.
722 */
723 ParameterizedTypeImpl getParameterizedType(ClassType t) {
724 return new ParameterizedTypeImpl(this, t);
725 // ParameterizedTypeImpl result = parameterizedTypeMap.get(t);
726 // if (result != null) return result;
727 // result = new ParameterizedTypeImpl(this, t);
728 // parameterizedTypeMap.put(t, result);
729 // return result;
730 }
732 /**
733 * Set the encoding.
734 */
735 public void setEncoding(String encoding) {
736 this.encoding = encoding;
737 }
739 /**
740 * Get the encoding.
741 */
742 public String getEncoding() {
743 return encoding;
744 }
746 /**
747 * Convert modifier bits from private coding used by
748 * the compiler to that of java.lang.reflect.Modifier.
749 */
750 static int translateModifiers(long flags) {
751 int result = 0;
752 if ((flags & Flags.ABSTRACT) != 0)
753 result |= Modifier.ABSTRACT;
754 if ((flags & Flags.FINAL) != 0)
755 result |= Modifier.FINAL;
756 if ((flags & Flags.INTERFACE) != 0)
757 result |= Modifier.INTERFACE;
758 if ((flags & Flags.NATIVE) != 0)
759 result |= Modifier.NATIVE;
760 if ((flags & Flags.PRIVATE) != 0)
761 result |= Modifier.PRIVATE;
762 if ((flags & Flags.PROTECTED) != 0)
763 result |= Modifier.PROTECTED;
764 if ((flags & Flags.PUBLIC) != 0)
765 result |= Modifier.PUBLIC;
766 if ((flags & Flags.STATIC) != 0)
767 result |= Modifier.STATIC;
768 if ((flags & Flags.SYNCHRONIZED) != 0)
769 result |= Modifier.SYNCHRONIZED;
770 if ((flags & Flags.TRANSIENT) != 0)
771 result |= Modifier.TRANSIENT;
772 if ((flags & Flags.VOLATILE) != 0)
773 result |= Modifier.VOLATILE;
774 return result;
775 }
776 }