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 1997-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.io.InputStream;
29 import java.io.IOException;
30 import javax.tools.FileObject;
32 import com.sun.javadoc.*;
34 import com.sun.tools.javac.code.Attribute;
35 import com.sun.tools.javac.code.Scope;
36 import com.sun.tools.javac.code.Symbol.ClassSymbol;
37 import com.sun.tools.javac.code.Symbol.PackageSymbol;
38 import com.sun.tools.javac.tree.JCTree;
39 import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
40 import com.sun.tools.javac.util.List;
41 import com.sun.tools.javac.util.ListBuffer;
42 import com.sun.tools.javac.util.Name;
43 import com.sun.tools.javac.util.Position;
45 /**
46 * Represents a java package. Provides access to information
47 * about the package, the package's comment and tags, and the
48 * classes in the package.
49 *
50 * @since 1.2
51 * @author Kaiyang Liu (original)
52 * @author Robert Field (rewrite)
53 * @author Neal Gafter (rewrite)
54 * @author Scott Seligman (package-info.java)
55 */
57 public class PackageDocImpl extends DocImpl implements PackageDoc {
59 protected PackageSymbol sym;
60 private JCCompilationUnit tree = null; // for source position
62 public FileObject docPath = null;
63 private boolean foundDoc; // found a doc comment in either
64 // package.html or package-info.java
66 boolean isIncluded = false; // Set in RootDocImpl.
67 public boolean setDocPath = false; //Flag to avoid setting doc path multiple times.
69 /**
70 * Constructor
71 */
72 public PackageDocImpl(DocEnv env, PackageSymbol sym) {
73 this(env, sym, null, null);
74 }
76 /**
77 * Constructor
78 */
79 public PackageDocImpl(DocEnv env, PackageSymbol sym,
80 String documentation, JCTree tree) {
81 super(env, documentation);
82 this.sym = sym;
83 this.tree = (JCCompilationUnit) tree;
84 foundDoc = (documentation != null);
85 }
87 void setTree(JCTree tree) {
88 this.tree = (JCCompilationUnit) tree;
89 }
91 public void setRawCommentText(String rawDocumentation) {
92 super.setRawCommentText(rawDocumentation);
93 checkDoc();
94 }
96 /**
97 * Do lazy initialization of "documentation" string.
98 */
99 String documentation() {
100 if (documentation != null)
101 return documentation;
102 if (docPath != null) {
103 // read from file
104 try {
105 InputStream s = docPath.openInputStream();
106 documentation = readHTMLDocumentation(s, docPath);
107 } catch (IOException exc) {
108 documentation = "";
109 env.error(null, "javadoc.File_Read_Error", docPath.getName());
110 }
111 } else {
112 // no doc file to be had
113 documentation = "";
114 }
115 return documentation;
116 }
118 /**
119 * Cache of all classes contained in this package, including
120 * member classes of those classes, and their member classes, etc.
121 * Includes only those classes at the specified protection level
122 * and weaker.
123 */
124 private List<ClassDocImpl> allClassesFiltered = null;
126 /**
127 * Cache of all classes contained in this package, including
128 * member classes of those classes, and their member classes, etc.
129 */
130 private List<ClassDocImpl> allClasses = null;
132 /**
133 * Return a list of all classes contained in this package, including
134 * member classes of those classes, and their member classes, etc.
135 */
136 private List<ClassDocImpl> getClasses(boolean filtered) {
137 if (allClasses != null && !filtered) {
138 return allClasses;
139 }
140 if (allClassesFiltered != null && filtered) {
141 return allClassesFiltered;
142 }
143 ListBuffer<ClassDocImpl> classes = new ListBuffer<ClassDocImpl>();
144 for (Scope.Entry e = sym.members().elems; e != null; e = e.sibling) {
145 if (e.sym != null) {
146 ClassSymbol s = (ClassSymbol)e.sym;
147 ClassDocImpl c = env.getClassDoc(s);
148 if (c != null && !c.isSynthetic())
149 c.addAllClasses(classes, filtered);
150 }
151 }
152 if (filtered)
153 return allClassesFiltered = classes.toList();
154 else
155 return allClasses = classes.toList();
156 }
158 /**
159 * Add all included classes (including Exceptions and Errors)
160 * and interfaces.
161 */
162 public void addAllClassesTo(ListBuffer<ClassDocImpl> list) {
163 list.appendList(getClasses(true));
164 }
166 /**
167 * Get all classes (including Exceptions and Errors)
168 * and interfaces.
169 * @since J2SE1.4.
170 *
171 * @return all classes and interfaces in this package, filtered to include
172 * only the included classes if filter==true.
173 */
174 public ClassDoc[] allClasses(boolean filter) {
175 List<ClassDocImpl> classes = getClasses(filter);
176 return classes.toArray(new ClassDocImpl[classes.length()]);
177 }
179 /**
180 * Get all included classes (including Exceptions and Errors)
181 * and interfaces. Same as allClasses(true).
182 *
183 * @return all included classes and interfaces in this package.
184 */
185 public ClassDoc[] allClasses() {
186 return allClasses(true);
187 }
189 /**
190 * Get ordinary classes (that is, exclude exceptions, errors,
191 * enums, interfaces, and annotation types) in this package.
192 *
193 * @return included ordinary classes in this package.
194 */
195 public ClassDoc[] ordinaryClasses() {
196 ListBuffer<ClassDocImpl> ret = new ListBuffer<ClassDocImpl>();
197 for (ClassDocImpl c : getClasses(true)) {
198 if (c.isOrdinaryClass()) {
199 ret.append(c);
200 }
201 }
202 return ret.toArray(new ClassDocImpl[ret.length()]);
203 }
205 /**
206 * Get Exception classes in this package.
207 *
208 * @return included Exceptions in this package.
209 */
210 public ClassDoc[] exceptions() {
211 ListBuffer<ClassDocImpl> ret = new ListBuffer<ClassDocImpl>();
212 for (ClassDocImpl c : getClasses(true)) {
213 if (c.isException()) {
214 ret.append(c);
215 }
216 }
217 return ret.toArray(new ClassDocImpl[ret.length()]);
218 }
220 /**
221 * Get Error classes in this package.
222 *
223 * @return included Errors in this package.
224 */
225 public ClassDoc[] errors() {
226 ListBuffer<ClassDocImpl> ret = new ListBuffer<ClassDocImpl>();
227 for (ClassDocImpl c : getClasses(true)) {
228 if (c.isError()) {
229 ret.append(c);
230 }
231 }
232 return ret.toArray(new ClassDocImpl[ret.length()]);
233 }
235 /**
236 * Get included enum types in this package.
237 *
238 * @return included enum types in this package.
239 */
240 public ClassDoc[] enums() {
241 ListBuffer<ClassDocImpl> ret = new ListBuffer<ClassDocImpl>();
242 for (ClassDocImpl c : getClasses(true)) {
243 if (c.isEnum()) {
244 ret.append(c);
245 }
246 }
247 return ret.toArray(new ClassDocImpl[ret.length()]);
248 }
250 /**
251 * Get included interfaces in this package, omitting annotation types.
252 *
253 * @return included interfaces in this package.
254 */
255 public ClassDoc[] interfaces() {
256 ListBuffer<ClassDocImpl> ret = new ListBuffer<ClassDocImpl>();
257 for (ClassDocImpl c : getClasses(true)) {
258 if (c.isInterface()) {
259 ret.append(c);
260 }
261 }
262 return ret.toArray(new ClassDocImpl[ret.length()]);
263 }
265 /**
266 * Get included annotation types in this package.
267 *
268 * @return included annotation types in this package.
269 */
270 public AnnotationTypeDoc[] annotationTypes() {
271 ListBuffer<AnnotationTypeDocImpl> ret =
272 new ListBuffer<AnnotationTypeDocImpl>();
273 for (ClassDocImpl c : getClasses(true)) {
274 if (c.isAnnotationType()) {
275 ret.append((AnnotationTypeDocImpl)c);
276 }
277 }
278 return ret.toArray(new AnnotationTypeDocImpl[ret.length()]);
279 }
281 /**
282 * Get the annotations of this package.
283 * Return an empty array if there are none.
284 */
285 public AnnotationDesc[] annotations() {
286 AnnotationDesc res[] = new AnnotationDesc[sym.getAnnotationMirrors().length()];
287 int i = 0;
288 for (Attribute.Compound a : sym.getAnnotationMirrors()) {
289 res[i++] = new AnnotationDescImpl(env, a);
290 }
291 return res;
292 }
295 /**
296 * Lookup for a class within this package.
297 *
298 * @return ClassDocImpl of found class, or null if not found.
299 */
300 public ClassDoc findClass(String className) {
301 final boolean filtered = true;
302 for (ClassDocImpl c : getClasses(filtered)) {
303 if (c.name().equals(className)) {
304 return c;
305 }
306 }
307 return null;
308 }
310 /**
311 * Return true if this package is included in the active set.
312 */
313 public boolean isIncluded() {
314 return isIncluded;
315 }
317 /**
318 * Get package name.
319 *
320 * Note that we do not provide a means of obtaining the simple
321 * name of a package -- package names are always returned in their
322 * uniquely qualified form.
323 */
324 public String name() {
325 return qualifiedName();
326 }
328 /**
329 * Get package name.
330 */
331 public String qualifiedName() {
332 Name fullname = sym.getQualifiedName();
333 // Some bogus tests depend on the interned "" being returned.
334 // See 6457276.
335 return fullname.isEmpty() ? "" : fullname.toString();
336 }
338 /**
339 * set doc path for an unzipped directory
340 */
341 public void setDocPath(FileObject path) {
342 setDocPath = true;
343 if (path == null)
344 return;
345 if (!path.equals(docPath)) {
346 docPath = path;
347 checkDoc();
348 }
349 }
351 // Has checkDoc() sounded off yet?
352 private boolean checkDocWarningEmitted = false;
354 /**
355 * Invoked when a source of package doc comments is located.
356 * Emits a diagnostic if this is the second one.
357 */
358 private void checkDoc() {
359 if (foundDoc) {
360 if (!checkDocWarningEmitted) {
361 env.warning(null, "javadoc.Multiple_package_comments", name());
362 checkDocWarningEmitted = true;
363 }
364 } else {
365 foundDoc = true;
366 }
367 }
369 /**
370 * Return the source position of the entity, or null if
371 * no position is available.
372 */
373 public SourcePosition position() {
374 return (tree != null)
375 ? SourcePositionImpl.make(tree.sourcefile, tree.pos, tree.lineMap)
376 : SourcePositionImpl.make(docPath, Position.NOPOS, null);
377 }
378 }