diff -r 000000000000 -r 959103a6100f src/share/classes/com/sun/tools/javadoc/ClassDocImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/classes/com/sun/tools/javadoc/ClassDocImpl.java Wed Apr 27 01:34:52 2016 +0800 @@ -0,0 +1,1338 @@ +/* + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sun.tools.javadoc; + +import java.io.File; +import java.io.IOException; +import java.lang.reflect.Modifier; +import java.net.URI; +import java.util.HashSet; +import java.util.Set; + +import javax.tools.FileObject; +import javax.tools.JavaFileManager.Location; +import javax.tools.StandardJavaFileManager; +import javax.tools.StandardLocation; + +import com.sun.javadoc.*; +import com.sun.source.util.TreePath; +import com.sun.tools.javac.code.Flags; +import com.sun.tools.javac.code.Kinds; +import com.sun.tools.javac.code.Scope; +import com.sun.tools.javac.code.Symbol; +import com.sun.tools.javac.code.Symbol.*; +import com.sun.tools.javac.code.Type; +import com.sun.tools.javac.code.Type.ClassType; +import com.sun.tools.javac.code.TypeTag; +import com.sun.tools.javac.comp.AttrContext; +import com.sun.tools.javac.comp.Env; +import com.sun.tools.javac.tree.JCTree; +import com.sun.tools.javac.tree.JCTree.JCFieldAccess; +import com.sun.tools.javac.tree.JCTree.JCImport; +import com.sun.tools.javac.tree.TreeInfo; +import com.sun.tools.javac.util.List; +import com.sun.tools.javac.util.ListBuffer; +import com.sun.tools.javac.util.Name; +import com.sun.tools.javac.util.Names; +import com.sun.tools.javac.util.Position; +import static com.sun.tools.javac.code.Kinds.*; +import static com.sun.tools.javac.code.TypeTag.CLASS; +import static com.sun.tools.javac.tree.JCTree.Tag.*; + +/** + * Represents a java class and provides access to information + * about the class, the class' comment and tags, and the + * members of the class. A ClassDocImpl only exists if it was + * processed in this run of javadoc. References to classes + * which may or may not have been processed in this run are + * referred to using Type (which can be converted to ClassDocImpl, + * if possible). + * + *
This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + * + * @see Type + * + * @since 1.2 + * @author Robert Field + * @author Neal Gafter (rewrite) + * @author Scott Seligman (generics, enums, annotations) + */ + +public class ClassDocImpl extends ProgramElementDocImpl implements ClassDoc { + + public final ClassType type; // protected->public for debugging + protected final ClassSymbol tsym; + + boolean isIncluded = false; // Set in RootDocImpl + + private SerializedForm serializedForm; + + /** + * Constructor + */ + public ClassDocImpl(DocEnv env, ClassSymbol sym) { + this(env, sym, null); + } + + /** + * Constructor + */ + public ClassDocImpl(DocEnv env, ClassSymbol sym, TreePath treePath) { + super(env, sym, treePath); + this.type = (ClassType)sym.type; + this.tsym = sym; + } + + public com.sun.javadoc.Type getElementType() { + return null; + } + + /** + * Returns the flags in terms of javac's flags + */ + protected long getFlags() { + return getFlags(tsym); + } + + /** + * Returns the flags of a ClassSymbol in terms of javac's flags + */ + static long getFlags(ClassSymbol clazz) { + while (true) { + try { + return clazz.flags(); + } catch (CompletionFailure ex) { + /* Quietly ignore completion failures. + * Note that a CompletionFailure can only + * occur as a result of calling complete(), + * which will always remove the current + * completer, leaving it to be null or + * follow-up completer. Thus the loop + * is guaranteed to eventually terminate. + */ + } + } + } + + /** + * Is a ClassSymbol an annotation type? + */ + static boolean isAnnotationType(ClassSymbol clazz) { + return (getFlags(clazz) & Flags.ANNOTATION) != 0; + } + + /** + * Identify the containing class + */ + protected ClassSymbol getContainingClass() { + return tsym.owner.enclClass(); + } + + /** + * Return true if this is a class, not an interface. + */ + @Override + public boolean isClass() { + return !Modifier.isInterface(getModifiers()); + } + + /** + * Return true if this is a ordinary class, + * not an enumeration, exception, an error, or an interface. + */ + @Override + public boolean isOrdinaryClass() { + if (isEnum() || isInterface() || isAnnotationType()) { + return false; + } + for (Type t = type; t.hasTag(CLASS); t = env.types.supertype(t)) { + if (t.tsym == env.syms.errorType.tsym || + t.tsym == env.syms.exceptionType.tsym) { + return false; + } + } + return true; + } + + /** + * Return true if this is an enumeration. + * (For legacy doclets, return false.) + */ + @Override + public boolean isEnum() { + return (getFlags() & Flags.ENUM) != 0 + && + !env.legacyDoclet; + } + + /** + * Return true if this is an interface, but not an annotation type. + * Overridden by AnnotationTypeDocImpl. + */ + @Override + public boolean isInterface() { + return Modifier.isInterface(getModifiers()); + } + + /** + * Return true if this is an exception class + */ + @Override + public boolean isException() { + if (isEnum() || isInterface() || isAnnotationType()) { + return false; + } + for (Type t = type; t.hasTag(CLASS); t = env.types.supertype(t)) { + if (t.tsym == env.syms.exceptionType.tsym) { + return true; + } + } + return false; + } + + /** + * Return true if this is an error class + */ + @Override + public boolean isError() { + if (isEnum() || isInterface() || isAnnotationType()) { + return false; + } + for (Type t = type; t.hasTag(CLASS); t = env.types.supertype(t)) { + if (t.tsym == env.syms.errorType.tsym) { + return true; + } + } + return false; + } + + /** + * Return true if this is a throwable class + */ + public boolean isThrowable() { + if (isEnum() || isInterface() || isAnnotationType()) { + return false; + } + for (Type t = type; t.hasTag(CLASS); t = env.types.supertype(t)) { + if (t.tsym == env.syms.throwableType.tsym) { + return true; + } + } + return false; + } + + /** + * Return true if this class is abstract + */ + public boolean isAbstract() { + return Modifier.isAbstract(getModifiers()); + } + + /** + * Returns true if this class was synthesized by the compiler. + */ + public boolean isSynthetic() { + return (getFlags() & Flags.SYNTHETIC) != 0; + } + + /** + * Return true if this class is included in the active set. + * A ClassDoc is included iff either it is specified on the + * commandline, or if it's containing package is specified + * on the command line, or if it is a member class of an + * included class. + */ + + public boolean isIncluded() { + if (isIncluded) { + return true; + } + if (env.shouldDocument(tsym)) { + // Class is nameable from top-level and + // the class and all enclosing classes + // pass the modifier filter. + if (containingPackage().isIncluded()) { + return isIncluded=true; + } + ClassDoc outer = containingClass(); + if (outer != null && outer.isIncluded()) { + return isIncluded=true; + } + } + return false; + } + + /** + * Return the package that this class is contained in. + */ + @Override + public PackageDoc containingPackage() { + PackageDocImpl p = env.getPackageDoc(tsym.packge()); + if (p.setDocPath == false) { + FileObject docPath; + try { + Location location = env.fileManager.hasLocation(StandardLocation.SOURCE_PATH) + ? StandardLocation.SOURCE_PATH : StandardLocation.CLASS_PATH; + + docPath = env.fileManager.getFileForInput( + location, p.qualifiedName(), "package.html"); + } catch (IOException e) { + docPath = null; + } + + if (docPath == null) { + // fall back on older semantics of looking in same directory as + // source file for this class + SourcePosition po = position(); + if (env.fileManager instanceof StandardJavaFileManager && + po instanceof SourcePositionImpl) { + URI uri = ((SourcePositionImpl) po).filename.toUri(); + if ("file".equals(uri.getScheme())) { + File f = new File(uri); + File dir = f.getParentFile(); + if (dir != null) { + File pf = new File(dir, "package.html"); + if (pf.exists()) { + StandardJavaFileManager sfm = (StandardJavaFileManager) env.fileManager; + docPath = sfm.getJavaFileObjects(pf).iterator().next(); + } + } + + } + } + } + + p.setDocPath(docPath); + } + return p; + } + + /** + * Return the class name without package qualifier - but with + * enclosing class qualifier - as a String. + *
+ * Examples: + * for java.util.Hashtable + * return Hashtable + * for java.util.Map.Entry + * return Map.Entry + *+ */ + public String name() { + if (name == null) { + name = getClassName(tsym, false); + } + return name; + } + + private String name; + + /** + * Return the qualified class name as a String. + *
+ * Example: + * for java.util.Hashtable + * return java.util.Hashtable + * if no qualifier, just return flat name + *+ */ + public String qualifiedName() { + if (qualifiedName == null) { + qualifiedName = getClassName(tsym, true); + } + return qualifiedName; + } + + private String qualifiedName; + + /** + * Return unqualified name of type excluding any dimension information. + *
+ * For example, a two dimensional array of String returns 'String'. + */ + public String typeName() { + return name(); + } + + /** + * Return qualified name of type excluding any dimension information. + *
+ * For example, a two dimensional array of String
+ * returns 'java.lang.String'.
+ */
+ public String qualifiedTypeName() {
+ return qualifiedName();
+ }
+
+ /**
+ * Return the simple name of this type.
+ */
+ public String simpleTypeName() {
+ if (simpleTypeName == null) {
+ simpleTypeName = tsym.name.toString();
+ }
+ return simpleTypeName;
+ }
+
+ private String simpleTypeName;
+
+ /**
+ * Return the qualified name and any type parameters.
+ * Each parameter is a type variable with optional bounds.
+ */
+ @Override
+ public String toString() {
+ return classToString(env, tsym, true);
+ }
+
+ /**
+ * Return the class name as a string. If "full" is true the name is
+ * qualified, otherwise it is qualified by its enclosing class(es) only.
+ */
+ static String getClassName(ClassSymbol c, boolean full) {
+ if (full) {
+ return c.getQualifiedName().toString();
+ } else {
+ String n = "";
+ for ( ; c != null; c = c.owner.enclClass()) {
+ n = c.name + (n.equals("") ? "" : ".") + n;
+ }
+ return n;
+ }
+ }
+
+ /**
+ * Return the class name with any type parameters as a string.
+ * Each parameter is a type variable with optional bounds.
+ * If "full" is true all names are qualified, otherwise they are
+ * qualified by their enclosing class(es) only.
+ */
+ static String classToString(DocEnv env, ClassSymbol c, boolean full) {
+ StringBuilder s = new StringBuilder();
+ if (!c.isInner()) { // if c is not an inner class
+ s.append(getClassName(c, full));
+ } else {
+ // c is an inner class, so include type params of outer.
+ ClassSymbol encl = c.owner.enclClass();
+ s.append(classToString(env, encl, full))
+ .append('.')
+ .append(c.name);
+ }
+ s.append(TypeMaker.typeParametersString(env, c, full));
+ return s.toString();
+ }
+
+ /**
+ * Is this class (or any enclosing class) generic? That is, does
+ * it have type parameters?
+ */
+ static boolean isGeneric(ClassSymbol c) {
+ return c.type.allparams().nonEmpty();
+ }
+
+ /**
+ * Return the formal type parameters of this class or interface.
+ * Return an empty array if there are none.
+ */
+ public TypeVariable[] typeParameters() {
+ if (env.legacyDoclet) {
+ return new TypeVariable[0];
+ }
+ TypeVariable res[] = new TypeVariable[type.getTypeArguments().length()];
+ TypeMaker.getTypes(env, type.getTypeArguments(), res);
+ return res;
+ }
+
+ /**
+ * Return the type parameter tags of this class or interface.
+ */
+ public ParamTag[] typeParamTags() {
+ return (env.legacyDoclet)
+ ? new ParamTag[0]
+ : comment().typeParamTags();
+ }
+
+ /**
+ * Return the modifier string for this class. If it's an interface
+ * exclude 'abstract' keyword from the modifier string
+ */
+ @Override
+ public String modifiers() {
+ return Modifier.toString(modifierSpecifier());
+ }
+
+ @Override
+ public int modifierSpecifier() {
+ int modifiers = getModifiers();
+ return (isInterface() || isAnnotationType())
+ ? modifiers & ~Modifier.ABSTRACT
+ : modifiers;
+ }
+
+ /**
+ * Return the superclass of this class
+ *
+ * @return the ClassDocImpl for the superclass of this class, null
+ * if there is no superclass.
+ */
+ public ClassDoc superclass() {
+ if (isInterface() || isAnnotationType()) return null;
+ if (tsym == env.syms.objectType.tsym) return null;
+ ClassSymbol c = (ClassSymbol)env.types.supertype(type).tsym;
+ if (c == null || c == tsym) c = (ClassSymbol)env.syms.objectType.tsym;
+ return env.getClassDoc(c);
+ }
+
+ /**
+ * Return the superclass of this class. Return null if this is an
+ * interface. A superclass is represented by either a
+ *
+ *
+ * Return either a list of default fields documented by
+ *
+ * Used only by ThrowsTagImpl.
+ */
+ boolean isRuntimeException() {
+ return tsym.isSubClass(env.syms.runtimeExceptionType.tsym, env.types);
+ }
+
+ /**
+ * Return the source position of the entity, or null if
+ * no position is available.
+ */
+ @Override
+ public SourcePosition position() {
+ if (tsym.sourcefile == null) return null;
+ return SourcePositionImpl.make(tsym.sourcefile,
+ (tree==null) ? Position.NOPOS : tree.pos,
+ lineMap);
+ }
+}
ClassDoc
or a ParameterizedType
.
+ */
+ public com.sun.javadoc.Type superclassType() {
+ if (isInterface() || isAnnotationType() ||
+ (tsym == env.syms.objectType.tsym))
+ return null;
+ Type sup = env.types.supertype(type);
+ return TypeMaker.getType(env,
+ (sup.hasTag(TypeTag.NONE)) ? env.syms.objectType : sup);
+ }
+
+ /**
+ * Test whether this class is a subclass of the specified class.
+ *
+ * @param cd the candidate superclass.
+ * @return true if cd is a superclass of this class.
+ */
+ public boolean subclassOf(ClassDoc cd) {
+ return tsym.isSubClass(((ClassDocImpl)cd).tsym, env.types);
+ }
+
+ /**
+ * Return interfaces implemented by this class or interfaces
+ * extended by this interface.
+ *
+ * @return An array of ClassDocImpl representing the interfaces.
+ * Return an empty array if there are no interfaces.
+ */
+ public ClassDoc[] interfaces() {
+ ListBufferjava.io.Serializable
.
+ *
+ * Since java.io.Externalizable
extends
+ * java.io.Serializable
,
+ * Externalizable objects are also Serializable.
+ */
+ public boolean isSerializable() {
+ try {
+ return env.types.isSubtype(type, env.syms.serializableType);
+ } catch (CompletionFailure ex) {
+ // quietly ignore completion failures
+ return false;
+ }
+ }
+
+ /**
+ * Return true if this class implements
+ * java.io.Externalizable
.
+ */
+ public boolean isExternalizable() {
+ try {
+ return env.types.isSubtype(type, env.externalizableSym.type);
+ } catch (CompletionFailure ex) {
+ // quietly ignore completion failures
+ return false;
+ }
+ }
+
+ /**
+ * Return the serialization methods for this class.
+ *
+ * @return an array of MethodDocImpl
that represents
+ * the serialization methods for this class.
+ */
+ public MethodDoc[] serializationMethods() {
+ if (serializedForm == null) {
+ serializedForm = new SerializedForm(env, tsym, this);
+ }
+ //### Clone this?
+ return serializedForm.methods();
+ }
+
+ /**
+ * Return the Serializable fields of class.serial
tag
+ * or return a single FieldDoc
for
+ * serialPersistentField
member.
+ * There should be a serialField
tag for
+ * each Serializable field defined by an ObjectStreamField
+ * array component of serialPersistentField
.
+ *
+ * @returns an array of FieldDoc
for the Serializable fields
+ * of this class.
+ *
+ * @see #definesSerializableFields()
+ * @see SerialFieldTagImpl
+ */
+ public FieldDoc[] serializableFields() {
+ if (serializedForm == null) {
+ serializedForm = new SerializedForm(env, tsym, this);
+ }
+ //### Clone this?
+ return serializedForm.fields();
+ }
+
+ /**
+ * Return true if Serializable fields are explicitly defined with
+ * the special class member serialPersistentFields
.
+ *
+ * @see #serializableFields()
+ * @see SerialFieldTagImpl
+ */
+ public boolean definesSerializableFields() {
+ if (!isSerializable() || isExternalizable()) {
+ return false;
+ } else {
+ if (serializedForm == null) {
+ serializedForm = new SerializedForm(env, tsym, this);
+ }
+ //### Clone this?
+ return serializedForm.definesSerializableFields();
+ }
+ }
+
+ /**
+ * Determine if a class is a RuntimeException.
+ *