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