duke@1: /*
jjg@1357: * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
duke@1: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
duke@1: *
duke@1: * This code is free software; you can redistribute it and/or modify it
duke@1: * under the terms of the GNU General Public License version 2 only, as
ohair@554: * published by the Free Software Foundation. Oracle designates this
duke@1: * particular file as subject to the "Classpath" exception as provided
ohair@554: * by Oracle in the LICENSE file that accompanied this code.
duke@1: *
duke@1: * This code is distributed in the hope that it will be useful, but WITHOUT
duke@1: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
duke@1: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
duke@1: * version 2 for more details (a copy is included in the LICENSE file that
duke@1: * accompanied this code).
duke@1: *
duke@1: * You should have received a copy of the GNU General Public License version
duke@1: * 2 along with this work; if not, write to the Free Software Foundation,
duke@1: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
duke@1: *
ohair@554: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
ohair@554: * or visit www.oracle.com if you need additional information or have any
ohair@554: * questions.
duke@1: */
duke@1:
duke@1: package com.sun.tools.javadoc;
duke@1:
jjg@1357: import java.io.IOException;
jjg@197: import java.io.InputStream;
jjg@1357:
jjg@197: import javax.tools.FileObject;
jjg@197:
duke@1: import com.sun.javadoc.*;
jjg@1443: import com.sun.source.util.TreePath;
duke@1: import com.sun.tools.javac.code.Attribute;
duke@1: import com.sun.tools.javac.code.Scope;
duke@1: import com.sun.tools.javac.code.Symbol.ClassSymbol;
duke@1: import com.sun.tools.javac.code.Symbol.PackageSymbol;
duke@1: import com.sun.tools.javac.tree.JCTree;
jjg@197: import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
duke@1: import com.sun.tools.javac.util.List;
duke@1: import com.sun.tools.javac.util.ListBuffer;
duke@1: import com.sun.tools.javac.util.Name;
duke@1: import com.sun.tools.javac.util.Position;
duke@1:
duke@1: /**
duke@1: * Represents a java package. Provides access to information
duke@1: * about the package, the package's comment and tags, and the
duke@1: * classes in the package.
duke@1: *
jjg@1359: *
This is NOT part of any supported API.
jjg@1359: * If you write code that depends on this, you do so at your own risk.
jjg@1359: * This code and its internal interfaces are subject to change or
jjg@1359: * deletion without notice.
jjg@1359: *
duke@1: * @since 1.2
duke@1: * @author Kaiyang Liu (original)
duke@1: * @author Robert Field (rewrite)
duke@1: * @author Neal Gafter (rewrite)
duke@1: * @author Scott Seligman (package-info.java)
duke@1: */
duke@1:
duke@1: public class PackageDocImpl extends DocImpl implements PackageDoc {
duke@1:
duke@1: protected PackageSymbol sym;
duke@1: private JCCompilationUnit tree = null; // for source position
duke@1:
jjg@197: public FileObject docPath = null;
duke@1: private boolean foundDoc; // found a doc comment in either
duke@1: // package.html or package-info.java
duke@1:
duke@1: boolean isIncluded = false; // Set in RootDocImpl.
duke@1: public boolean setDocPath = false; //Flag to avoid setting doc path multiple times.
duke@1:
duke@1: /**
duke@1: * Constructor
duke@1: */
duke@1: public PackageDocImpl(DocEnv env, PackageSymbol sym) {
jjg@1443: this(env, sym, null);
duke@1: }
duke@1:
duke@1: /**
duke@1: * Constructor
duke@1: */
jjg@1443: public PackageDocImpl(DocEnv env, PackageSymbol sym, TreePath treePath) {
jjg@1443: super(env, treePath);
duke@1: this.sym = sym;
jjg@1443: this.tree = (treePath == null) ? null : (JCCompilationUnit) treePath.getCompilationUnit();
duke@1: foundDoc = (documentation != null);
duke@1: }
duke@1:
duke@1: void setTree(JCTree tree) {
duke@1: this.tree = (JCCompilationUnit) tree;
duke@1: }
duke@1:
jjg@1443: public void setTreePath(TreePath treePath) {
jjg@1443: super.setTreePath(treePath);
duke@1: checkDoc();
duke@1: }
duke@1:
duke@1: /**
duke@1: * Do lazy initialization of "documentation" string.
duke@1: */
ksrini@1051: protected String documentation() {
jjg@197: if (documentation != null)
jjg@197: return documentation;
duke@1: if (docPath != null) {
duke@1: // read from file
duke@1: try {
jjg@197: InputStream s = docPath.openInputStream();
duke@1: documentation = readHTMLDocumentation(s, docPath);
duke@1: } catch (IOException exc) {
duke@1: documentation = "";
jjg@197: env.error(null, "javadoc.File_Read_Error", docPath.getName());
duke@1: }
duke@1: } else {
duke@1: // no doc file to be had
duke@1: documentation = "";
duke@1: }
duke@1: return documentation;
duke@1: }
duke@1:
duke@1: /**
duke@1: * Cache of all classes contained in this package, including
duke@1: * member classes of those classes, and their member classes, etc.
duke@1: * Includes only those classes at the specified protection level
duke@1: * and weaker.
duke@1: */
duke@1: private List allClassesFiltered = null;
duke@1:
duke@1: /**
duke@1: * Cache of all classes contained in this package, including
duke@1: * member classes of those classes, and their member classes, etc.
duke@1: */
duke@1: private List allClasses = null;
duke@1:
duke@1: /**
duke@1: * Return a list of all classes contained in this package, including
duke@1: * member classes of those classes, and their member classes, etc.
duke@1: */
duke@1: private List getClasses(boolean filtered) {
duke@1: if (allClasses != null && !filtered) {
duke@1: return allClasses;
duke@1: }
duke@1: if (allClassesFiltered != null && filtered) {
duke@1: return allClassesFiltered;
duke@1: }
duke@1: ListBuffer classes = new ListBuffer();
duke@1: for (Scope.Entry e = sym.members().elems; e != null; e = e.sibling) {
duke@1: if (e.sym != null) {
duke@1: ClassSymbol s = (ClassSymbol)e.sym;
duke@1: ClassDocImpl c = env.getClassDoc(s);
duke@1: if (c != null && !c.isSynthetic())
duke@1: c.addAllClasses(classes, filtered);
duke@1: }
duke@1: }
duke@1: if (filtered)
duke@1: return allClassesFiltered = classes.toList();
duke@1: else
duke@1: return allClasses = classes.toList();
duke@1: }
duke@1:
duke@1: /**
duke@1: * Add all included classes (including Exceptions and Errors)
duke@1: * and interfaces.
duke@1: */
duke@1: public void addAllClassesTo(ListBuffer list) {
duke@1: list.appendList(getClasses(true));
duke@1: }
duke@1:
duke@1: /**
duke@1: * Get all classes (including Exceptions and Errors)
duke@1: * and interfaces.
duke@1: * @since J2SE1.4.
duke@1: *
duke@1: * @return all classes and interfaces in this package, filtered to include
duke@1: * only the included classes if filter==true.
duke@1: */
duke@1: public ClassDoc[] allClasses(boolean filter) {
duke@1: List classes = getClasses(filter);
duke@1: return classes.toArray(new ClassDocImpl[classes.length()]);
duke@1: }
duke@1:
duke@1: /**
duke@1: * Get all included classes (including Exceptions and Errors)
duke@1: * and interfaces. Same as allClasses(true).
duke@1: *
duke@1: * @return all included classes and interfaces in this package.
duke@1: */
duke@1: public ClassDoc[] allClasses() {
duke@1: return allClasses(true);
duke@1: }
duke@1:
duke@1: /**
duke@1: * Get ordinary classes (that is, exclude exceptions, errors,
duke@1: * enums, interfaces, and annotation types) in this package.
duke@1: *
duke@1: * @return included ordinary classes in this package.
duke@1: */
duke@1: public ClassDoc[] ordinaryClasses() {
duke@1: ListBuffer ret = new ListBuffer();
duke@1: for (ClassDocImpl c : getClasses(true)) {
duke@1: if (c.isOrdinaryClass()) {
duke@1: ret.append(c);
duke@1: }
duke@1: }
duke@1: return ret.toArray(new ClassDocImpl[ret.length()]);
duke@1: }
duke@1:
duke@1: /**
duke@1: * Get Exception classes in this package.
duke@1: *
duke@1: * @return included Exceptions in this package.
duke@1: */
duke@1: public ClassDoc[] exceptions() {
duke@1: ListBuffer ret = new ListBuffer();
duke@1: for (ClassDocImpl c : getClasses(true)) {
duke@1: if (c.isException()) {
duke@1: ret.append(c);
duke@1: }
duke@1: }
duke@1: return ret.toArray(new ClassDocImpl[ret.length()]);
duke@1: }
duke@1:
duke@1: /**
duke@1: * Get Error classes in this package.
duke@1: *
duke@1: * @return included Errors in this package.
duke@1: */
duke@1: public ClassDoc[] errors() {
duke@1: ListBuffer ret = new ListBuffer();
duke@1: for (ClassDocImpl c : getClasses(true)) {
duke@1: if (c.isError()) {
duke@1: ret.append(c);
duke@1: }
duke@1: }
duke@1: return ret.toArray(new ClassDocImpl[ret.length()]);
duke@1: }
duke@1:
duke@1: /**
duke@1: * Get included enum types in this package.
duke@1: *
duke@1: * @return included enum types in this package.
duke@1: */
duke@1: public ClassDoc[] enums() {
duke@1: ListBuffer ret = new ListBuffer();
duke@1: for (ClassDocImpl c : getClasses(true)) {
duke@1: if (c.isEnum()) {
duke@1: ret.append(c);
duke@1: }
duke@1: }
duke@1: return ret.toArray(new ClassDocImpl[ret.length()]);
duke@1: }
duke@1:
duke@1: /**
duke@1: * Get included interfaces in this package, omitting annotation types.
duke@1: *
duke@1: * @return included interfaces in this package.
duke@1: */
duke@1: public ClassDoc[] interfaces() {
duke@1: ListBuffer ret = new ListBuffer();
duke@1: for (ClassDocImpl c : getClasses(true)) {
duke@1: if (c.isInterface()) {
duke@1: ret.append(c);
duke@1: }
duke@1: }
duke@1: return ret.toArray(new ClassDocImpl[ret.length()]);
duke@1: }
duke@1:
duke@1: /**
duke@1: * Get included annotation types in this package.
duke@1: *
duke@1: * @return included annotation types in this package.
duke@1: */
duke@1: public AnnotationTypeDoc[] annotationTypes() {
duke@1: ListBuffer ret =
duke@1: new ListBuffer();
duke@1: for (ClassDocImpl c : getClasses(true)) {
duke@1: if (c.isAnnotationType()) {
duke@1: ret.append((AnnotationTypeDocImpl)c);
duke@1: }
duke@1: }
duke@1: return ret.toArray(new AnnotationTypeDocImpl[ret.length()]);
duke@1: }
duke@1:
duke@1: /**
duke@1: * Get the annotations of this package.
duke@1: * Return an empty array if there are none.
duke@1: */
duke@1: public AnnotationDesc[] annotations() {
jfranck@1464: AnnotationDesc res[] = new AnnotationDesc[sym.getRawAttributes().length()];
duke@1: int i = 0;
jfranck@1464: for (Attribute.Compound a : sym.getRawAttributes()) {
duke@1: res[i++] = new AnnotationDescImpl(env, a);
duke@1: }
duke@1: return res;
duke@1: }
duke@1:
duke@1:
duke@1: /**
duke@1: * Lookup for a class within this package.
duke@1: *
duke@1: * @return ClassDocImpl of found class, or null if not found.
duke@1: */
duke@1: public ClassDoc findClass(String className) {
duke@1: final boolean filtered = true;
duke@1: for (ClassDocImpl c : getClasses(filtered)) {
duke@1: if (c.name().equals(className)) {
duke@1: return c;
duke@1: }
duke@1: }
duke@1: return null;
duke@1: }
duke@1:
duke@1: /**
duke@1: * Return true if this package is included in the active set.
duke@1: */
duke@1: public boolean isIncluded() {
duke@1: return isIncluded;
duke@1: }
duke@1:
duke@1: /**
duke@1: * Get package name.
duke@1: *
duke@1: * Note that we do not provide a means of obtaining the simple
duke@1: * name of a package -- package names are always returned in their
duke@1: * uniquely qualified form.
duke@1: */
duke@1: public String name() {
duke@1: return qualifiedName();
duke@1: }
duke@1:
duke@1: /**
duke@1: * Get package name.
duke@1: */
duke@1: public String qualifiedName() {
duke@1: Name fullname = sym.getQualifiedName();
duke@1: // Some bogus tests depend on the interned "" being returned.
duke@1: // See 6457276.
duke@1: return fullname.isEmpty() ? "" : fullname.toString();
duke@1: }
duke@1:
duke@1: /**
duke@1: * set doc path for an unzipped directory
duke@1: */
jjg@197: public void setDocPath(FileObject path) {
duke@1: setDocPath = true;
duke@1: if (path == null)
duke@1: return;
jjg@197: if (!path.equals(docPath)) {
jjg@197: docPath = path;
duke@1: checkDoc();
duke@1: }
duke@1: }
duke@1:
duke@1: // Has checkDoc() sounded off yet?
duke@1: private boolean checkDocWarningEmitted = false;
duke@1:
duke@1: /**
duke@1: * Invoked when a source of package doc comments is located.
duke@1: * Emits a diagnostic if this is the second one.
duke@1: */
duke@1: private void checkDoc() {
duke@1: if (foundDoc) {
duke@1: if (!checkDocWarningEmitted) {
duke@1: env.warning(null, "javadoc.Multiple_package_comments", name());
duke@1: checkDocWarningEmitted = true;
duke@1: }
duke@1: } else {
duke@1: foundDoc = true;
duke@1: }
duke@1: }
duke@1:
duke@1: /**
duke@1: * Return the source position of the entity, or null if
duke@1: * no position is available.
duke@1: */
duke@1: public SourcePosition position() {
duke@1: return (tree != null)
jjg@197: ? SourcePositionImpl.make(tree.sourcefile, tree.pos, tree.lineMap)
duke@1: : SourcePositionImpl.make(docPath, Position.NOPOS, null);
duke@1: }
duke@1: }