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