src/share/classes/com/sun/tools/javadoc/ClassDocImpl.java

Tue, 24 Dec 2013 09:17:37 -0800

author
ksrini
date
Tue, 24 Dec 2013 09:17:37 -0800
changeset 2227
998b10c43157
parent 2113
7d266a2b31b2
child 2233
4a6f853f8721
permissions
-rw-r--r--

8029230: Update copyright year to match last edit in jdk8 langtools repository for 2013
Reviewed-by: ksrini
Contributed-by: steve.sides@oracle.com

     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  */
    26 package com.sun.tools.javadoc;
    28 import java.io.File;
    29 import java.io.IOException;
    30 import java.lang.reflect.Modifier;
    31 import java.net.URI;
    32 import java.util.HashSet;
    33 import java.util.Set;
    35 import javax.tools.FileObject;
    36 import javax.tools.JavaFileManager.Location;
    37 import javax.tools.StandardJavaFileManager;
    38 import javax.tools.StandardLocation;
    40 import com.sun.javadoc.*;
    41 import com.sun.source.util.TreePath;
    42 import com.sun.tools.javac.code.Flags;
    43 import com.sun.tools.javac.code.Kinds;
    44 import com.sun.tools.javac.code.Scope;
    45 import com.sun.tools.javac.code.Symbol;
    46 import com.sun.tools.javac.code.Symbol.*;
    47 import com.sun.tools.javac.code.Type;
    48 import com.sun.tools.javac.code.Type.ClassType;
    49 import com.sun.tools.javac.code.TypeTag;
    50 import com.sun.tools.javac.comp.AttrContext;
    51 import com.sun.tools.javac.comp.Env;
    52 import com.sun.tools.javac.tree.JCTree;
    53 import com.sun.tools.javac.tree.JCTree.JCFieldAccess;
    54 import com.sun.tools.javac.tree.JCTree.JCImport;
    55 import com.sun.tools.javac.tree.TreeInfo;
    56 import com.sun.tools.javac.util.List;
    57 import com.sun.tools.javac.util.ListBuffer;
    58 import com.sun.tools.javac.util.Name;
    59 import com.sun.tools.javac.util.Names;
    60 import com.sun.tools.javac.util.Position;
    61 import static com.sun.tools.javac.code.Kinds.*;
    62 import static com.sun.tools.javac.code.TypeTag.CLASS;
    63 import static com.sun.tools.javac.tree.JCTree.Tag.*;
    65 /**
    66  * Represents a java class and provides access to information
    67  * about the class, the class' comment and tags, and the
    68  * members of the class.  A ClassDocImpl only exists if it was
    69  * processed in this run of javadoc.  References to classes
    70  * which may or may not have been processed in this run are
    71  * referred to using Type (which can be converted to ClassDocImpl,
    72  * if possible).
    73  *
    74  *  <p><b>This is NOT part of any supported API.
    75  *  If you write code that depends on this, you do so at your own risk.
    76  *  This code and its internal interfaces are subject to change or
    77  *  deletion without notice.</b>
    78  *
    79  * @see Type
    80  *
    81  * @since 1.2
    82  * @author Robert Field
    83  * @author Neal Gafter (rewrite)
    84  * @author Scott Seligman (generics, enums, annotations)
    85  */
    87 public class ClassDocImpl extends ProgramElementDocImpl implements ClassDoc {
    89     public final ClassType type;        // protected->public for debugging
    90     protected final ClassSymbol tsym;
    92     boolean isIncluded = false;         // Set in RootDocImpl
    94     private SerializedForm serializedForm;
    96     /**
    97      * Constructor
    98      */
    99     public ClassDocImpl(DocEnv env, ClassSymbol sym) {
   100         this(env, sym, null);
   101     }
   103     /**
   104      * Constructor
   105      */
   106     public ClassDocImpl(DocEnv env, ClassSymbol sym, TreePath treePath) {
   107         super(env, sym, treePath);
   108         this.type = (ClassType)sym.type;
   109         this.tsym = sym;
   110     }
   112     public com.sun.javadoc.Type getElementType() {
   113         return null;
   114     }
   116     /**
   117      * Returns the flags in terms of javac's flags
   118      */
   119     protected long getFlags() {
   120         return getFlags(tsym);
   121     }
   123     /**
   124      * Returns the flags of a ClassSymbol in terms of javac's flags
   125      */
   126     static long getFlags(ClassSymbol clazz) {
   127         while (true) {
   128             try {
   129                 return clazz.flags();
   130             } catch (CompletionFailure ex) {
   131                 /* Quietly ignore completion failures.
   132                  * Note that a CompletionFailure can only
   133                  * occur as a result of calling complete(),
   134                  * which will always remove the current
   135                  * completer, leaving it to be null or
   136                  * follow-up completer. Thus the loop
   137                  * is guaranteed to eventually terminate.
   138                  */
   139             }
   140         }
   141     }
   143     /**
   144      * Is a ClassSymbol an annotation type?
   145      */
   146     static boolean isAnnotationType(ClassSymbol clazz) {
   147         return (getFlags(clazz) & Flags.ANNOTATION) != 0;
   148     }
   150     /**
   151      * Identify the containing class
   152      */
   153     protected ClassSymbol getContainingClass() {
   154         return tsym.owner.enclClass();
   155     }
   157     /**
   158      * Return true if this is a class, not an interface.
   159      */
   160     @Override
   161     public boolean isClass() {
   162         return !Modifier.isInterface(getModifiers());
   163     }
   165     /**
   166      * Return true if this is a ordinary class,
   167      * not an enumeration, exception, an error, or an interface.
   168      */
   169     @Override
   170     public boolean isOrdinaryClass() {
   171         if (isEnum() || isInterface() || isAnnotationType()) {
   172             return false;
   173         }
   174         for (Type t = type; t.hasTag(CLASS); t = env.types.supertype(t)) {
   175             if (t.tsym == env.syms.errorType.tsym ||
   176                 t.tsym == env.syms.exceptionType.tsym) {
   177                 return false;
   178             }
   179         }
   180         return true;
   181     }
   183     /**
   184      * Return true if this is an enumeration.
   185      * (For legacy doclets, return false.)
   186      */
   187     @Override
   188     public boolean isEnum() {
   189         return (getFlags() & Flags.ENUM) != 0
   190                &&
   191                !env.legacyDoclet;
   192     }
   194     /**
   195      * Return true if this is an interface, but not an annotation type.
   196      * Overridden by AnnotationTypeDocImpl.
   197      */
   198     @Override
   199     public boolean isInterface() {
   200         return Modifier.isInterface(getModifiers());
   201     }
   203     /**
   204      * Return true if this is an exception class
   205      */
   206     @Override
   207     public boolean isException() {
   208         if (isEnum() || isInterface() || isAnnotationType()) {
   209             return false;
   210         }
   211         for (Type t = type; t.hasTag(CLASS); t = env.types.supertype(t)) {
   212             if (t.tsym == env.syms.exceptionType.tsym) {
   213                 return true;
   214             }
   215         }
   216         return false;
   217     }
   219     /**
   220      * Return true if this is an error class
   221      */
   222     @Override
   223     public boolean isError() {
   224         if (isEnum() || isInterface() || isAnnotationType()) {
   225             return false;
   226         }
   227         for (Type t = type; t.hasTag(CLASS); t = env.types.supertype(t)) {
   228             if (t.tsym == env.syms.errorType.tsym) {
   229                 return true;
   230             }
   231         }
   232         return false;
   233     }
   235     /**
   236      * Return true if this is a throwable class
   237      */
   238     public boolean isThrowable() {
   239         if (isEnum() || isInterface() || isAnnotationType()) {
   240             return false;
   241         }
   242         for (Type t = type; t.hasTag(CLASS); t = env.types.supertype(t)) {
   243             if (t.tsym == env.syms.throwableType.tsym) {
   244                 return true;
   245             }
   246         }
   247         return false;
   248     }
   250     /**
   251      * Return true if this class is abstract
   252      */
   253     public boolean isAbstract() {
   254         return Modifier.isAbstract(getModifiers());
   255     }
   257     /**
   258      * Returns true if this class was synthesized by the compiler.
   259      */
   260     public boolean isSynthetic() {
   261         return (getFlags() & Flags.SYNTHETIC) != 0;
   262     }
   264     /**
   265      * Return true if this class is included in the active set.
   266      * A ClassDoc is included iff either it is specified on the
   267      * commandline, or if it's containing package is specified
   268      * on the command line, or if it is a member class of an
   269      * included class.
   270      */
   272     public boolean isIncluded() {
   273         if (isIncluded) {
   274             return true;
   275         }
   276         if (env.shouldDocument(tsym)) {
   277             // Class is nameable from top-level and
   278             // the class and all enclosing classes
   279             // pass the modifier filter.
   280             if (containingPackage().isIncluded()) {
   281                 return isIncluded=true;
   282             }
   283             ClassDoc outer = containingClass();
   284             if (outer != null && outer.isIncluded()) {
   285                 return isIncluded=true;
   286             }
   287         }
   288         return false;
   289     }
   291     public boolean isFunctionalInterface() {
   292         return env.types.isFunctionalInterface(tsym) && env.source.allowLambda();
   293     }
   295     /**
   296      * Return the package that this class is contained in.
   297      */
   298     @Override
   299     public PackageDoc containingPackage() {
   300         PackageDocImpl p = env.getPackageDoc(tsym.packge());
   301         if (p.setDocPath == false) {
   302             FileObject docPath;
   303             try {
   304                 Location location = env.fileManager.hasLocation(StandardLocation.SOURCE_PATH)
   305                     ? StandardLocation.SOURCE_PATH : StandardLocation.CLASS_PATH;
   307                 docPath = env.fileManager.getFileForInput(
   308                         location, p.qualifiedName(), "package.html");
   309             } catch (IOException e) {
   310                 docPath = null;
   311             }
   313             if (docPath == null) {
   314                 // fall back on older semantics of looking in same directory as
   315                 // source file for this class
   316                 SourcePosition po = position();
   317                 if (env.fileManager instanceof StandardJavaFileManager &&
   318                         po instanceof SourcePositionImpl) {
   319                     URI uri = ((SourcePositionImpl) po).filename.toUri();
   320                     if ("file".equals(uri.getScheme())) {
   321                         File f = new File(uri);
   322                         File dir = f.getParentFile();
   323                         if (dir != null) {
   324                             File pf = new File(dir, "package.html");
   325                             if (pf.exists()) {
   326                                 StandardJavaFileManager sfm = (StandardJavaFileManager) env.fileManager;
   327                                 docPath = sfm.getJavaFileObjects(pf).iterator().next();
   328                             }
   329                         }
   331                     }
   332                 }
   333             }
   335             p.setDocPath(docPath);
   336         }
   337         return p;
   338     }
   340     /**
   341      * Return the class name without package qualifier - but with
   342      * enclosing class qualifier - as a String.
   343      * <pre>
   344      * Examples:
   345      *  for java.util.Hashtable
   346      *  return Hashtable
   347      *  for java.util.Map.Entry
   348      *  return Map.Entry
   349      * </pre>
   350      */
   351     public String name() {
   352         if (name == null) {
   353             name = getClassName(tsym, false);
   354         }
   355         return name;
   356     }
   358     private String name;
   360     /**
   361      * Return the qualified class name as a String.
   362      * <pre>
   363      * Example:
   364      *  for java.util.Hashtable
   365      *  return java.util.Hashtable
   366      *  if no qualifier, just return flat name
   367      * </pre>
   368      */
   369     public String qualifiedName() {
   370         if (qualifiedName == null) {
   371             qualifiedName = getClassName(tsym, true);
   372         }
   373         return qualifiedName;
   374     }
   376     private String qualifiedName;
   378     /**
   379      * Return unqualified name of type excluding any dimension information.
   380      * <p>
   381      * For example, a two dimensional array of String returns 'String'.
   382      */
   383     public String typeName() {
   384         return name();
   385     }
   387     /**
   388      * Return qualified name of type excluding any dimension information.
   389      *<p>
   390      * For example, a two dimensional array of String
   391      * returns 'java.lang.String'.
   392      */
   393     public String qualifiedTypeName() {
   394         return qualifiedName();
   395     }
   397     /**
   398      * Return the simple name of this type.
   399      */
   400     public String simpleTypeName() {
   401         if (simpleTypeName == null) {
   402             simpleTypeName = tsym.name.toString();
   403         }
   404         return simpleTypeName;
   405     }
   407     private String simpleTypeName;
   409     /**
   410      * Return the qualified name and any type parameters.
   411      * Each parameter is a type variable with optional bounds.
   412      */
   413     @Override
   414     public String toString() {
   415         return classToString(env, tsym, true);
   416     }
   418     /**
   419      * Return the class name as a string.  If "full" is true the name is
   420      * qualified, otherwise it is qualified by its enclosing class(es) only.
   421      */
   422     static String getClassName(ClassSymbol c, boolean full) {
   423         if (full) {
   424             return c.getQualifiedName().toString();
   425         } else {
   426             String n = "";
   427             for ( ; c != null; c = c.owner.enclClass()) {
   428                 n = c.name + (n.equals("") ? "" : ".") + n;
   429             }
   430             return n;
   431         }
   432     }
   434     /**
   435      * Return the class name with any type parameters as a string.
   436      * Each parameter is a type variable with optional bounds.
   437      * If "full" is true all names are qualified, otherwise they are
   438      * qualified by their enclosing class(es) only.
   439      */
   440     static String classToString(DocEnv env, ClassSymbol c, boolean full) {
   441         StringBuilder s = new StringBuilder();
   442         if (!c.isInner()) {             // if c is not an inner class
   443             s.append(getClassName(c, full));
   444         } else {
   445             // c is an inner class, so include type params of outer.
   446             ClassSymbol encl = c.owner.enclClass();
   447             s.append(classToString(env, encl, full))
   448              .append('.')
   449              .append(c.name);
   450         }
   451         s.append(TypeMaker.typeParametersString(env, c, full));
   452         return s.toString();
   453     }
   455     /**
   456      * Is this class (or any enclosing class) generic?  That is, does
   457      * it have type parameters?
   458      */
   459     static boolean isGeneric(ClassSymbol c) {
   460         return c.type.allparams().nonEmpty();
   461     }
   463     /**
   464      * Return the formal type parameters of this class or interface.
   465      * Return an empty array if there are none.
   466      */
   467     public TypeVariable[] typeParameters() {
   468         if (env.legacyDoclet) {
   469             return new TypeVariable[0];
   470         }
   471         TypeVariable res[] = new TypeVariable[type.getTypeArguments().length()];
   472         TypeMaker.getTypes(env, type.getTypeArguments(), res);
   473         return res;
   474     }
   476     /**
   477      * Return the type parameter tags of this class or interface.
   478      */
   479     public ParamTag[] typeParamTags() {
   480         return (env.legacyDoclet)
   481             ? new ParamTag[0]
   482             : comment().typeParamTags();
   483     }
   485     /**
   486      * Return the modifier string for this class. If it's an interface
   487      * exclude 'abstract' keyword from the modifier string
   488      */
   489     @Override
   490     public String modifiers() {
   491         return Modifier.toString(modifierSpecifier());
   492     }
   494     @Override
   495     public int modifierSpecifier() {
   496         int modifiers = getModifiers();
   497         return (isInterface() || isAnnotationType())
   498                 ? modifiers & ~Modifier.ABSTRACT
   499                 : modifiers;
   500     }
   502     /**
   503      * Return the superclass of this class
   504      *
   505      * @return the ClassDocImpl for the superclass of this class, null
   506      * if there is no superclass.
   507      */
   508     public ClassDoc superclass() {
   509         if (isInterface() || isAnnotationType()) return null;
   510         if (tsym == env.syms.objectType.tsym) return null;
   511         ClassSymbol c = (ClassSymbol)env.types.supertype(type).tsym;
   512         if (c == null || c == tsym) c = (ClassSymbol)env.syms.objectType.tsym;
   513         return env.getClassDoc(c);
   514     }
   516     /**
   517      * Return the superclass of this class.  Return null if this is an
   518      * interface.  A superclass is represented by either a
   519      * <code>ClassDoc</code> or a <code>ParameterizedType</code>.
   520      */
   521     public com.sun.javadoc.Type superclassType() {
   522         if (isInterface() || isAnnotationType() ||
   523                 (tsym == env.syms.objectType.tsym))
   524             return null;
   525         Type sup = env.types.supertype(type);
   526         return TypeMaker.getType(env,
   527                                  (sup.hasTag(TypeTag.NONE)) ? env.syms.objectType : sup);
   528     }
   530     /**
   531      * Test whether this class is a subclass of the specified class.
   532      *
   533      * @param cd the candidate superclass.
   534      * @return true if cd is a superclass of this class.
   535      */
   536     public boolean subclassOf(ClassDoc cd) {
   537         return tsym.isSubClass(((ClassDocImpl)cd).tsym, env.types);
   538     }
   540     /**
   541      * Return interfaces implemented by this class or interfaces
   542      * extended by this interface.
   543      *
   544      * @return An array of ClassDocImpl representing the interfaces.
   545      * Return an empty array if there are no interfaces.
   546      */
   547     public ClassDoc[] interfaces() {
   548         ListBuffer<ClassDocImpl> ta = new ListBuffer<ClassDocImpl>();
   549         for (Type t : env.types.interfaces(type)) {
   550             ta.append(env.getClassDoc((ClassSymbol)t.tsym));
   551         }
   552         //### Cache ta here?
   553         return ta.toArray(new ClassDocImpl[ta.length()]);
   554     }
   556     /**
   557      * Return interfaces implemented by this class or interfaces extended
   558      * by this interface. Includes only directly-declared interfaces, not
   559      * inherited interfaces.
   560      * Return an empty array if there are no interfaces.
   561      */
   562     public com.sun.javadoc.Type[] interfaceTypes() {
   563         //### Cache result here?
   564         return TypeMaker.getTypes(env, env.types.interfaces(type));
   565     }
   567     /**
   568      * Return fields in class.
   569      * @param filter include only the included fields if filter==true
   570      */
   571     public FieldDoc[] fields(boolean filter) {
   572         return fields(filter, false);
   573     }
   575     /**
   576      * Return included fields in class.
   577      */
   578     public FieldDoc[] fields() {
   579         return fields(true, false);
   580     }
   582     /**
   583      * Return the enum constants if this is an enum type.
   584      */
   585     public FieldDoc[] enumConstants() {
   586         return fields(false, true);
   587     }
   589     /**
   590      * Return fields in class.
   591      * @param filter  if true, return only the included fields
   592      * @param enumConstants  if true, return the enum constants instead
   593      */
   594     private FieldDoc[] fields(boolean filter, boolean enumConstants) {
   595         List<FieldDocImpl> fields = List.nil();
   596         for (Scope.Entry e = tsym.members().elems; e != null; e = e.sibling) {
   597             if (e.sym != null && e.sym.kind == VAR) {
   598                 VarSymbol s = (VarSymbol)e.sym;
   599                 boolean isEnum = ((s.flags() & Flags.ENUM) != 0) &&
   600                                  !env.legacyDoclet;
   601                 if (isEnum == enumConstants &&
   602                         (!filter || env.shouldDocument(s))) {
   603                     fields = fields.prepend(env.getFieldDoc(s));
   604                 }
   605             }
   606         }
   607         return fields.toArray(new FieldDocImpl[fields.length()]);
   608     }
   610     /**
   611      * Return methods in class.
   612      * This method is overridden by AnnotationTypeDocImpl.
   613      *
   614      * @param filter include only the included methods if filter==true
   615      * @return an array of MethodDocImpl for representing the visible
   616      * methods in this class.  Does not include constructors.
   617      */
   618     public MethodDoc[] methods(boolean filter) {
   619         Names names = tsym.name.table.names;
   620         List<MethodDocImpl> methods = List.nil();
   621         for (Scope.Entry e = tsym.members().elems; e != null; e = e.sibling) {
   622             if (e.sym != null
   623                 && e.sym.kind == Kinds.MTH
   624                 && e.sym.name != names.init
   625                 && e.sym.name != names.clinit) {
   626                 MethodSymbol s = (MethodSymbol)e.sym;
   627                 if (!filter || env.shouldDocument(s)) {
   628                     methods = methods.prepend(env.getMethodDoc(s));
   629                 }
   630             }
   631         }
   632         //### Cache methods here?
   633         return methods.toArray(new MethodDocImpl[methods.length()]);
   634     }
   636     /**
   637      * Return included methods in class.
   638      *
   639      * @return an array of MethodDocImpl for representing the visible
   640      * methods in this class.  Does not include constructors.
   641      */
   642     public MethodDoc[] methods() {
   643         return methods(true);
   644     }
   646     /**
   647      * Return constructors in class.
   648      *
   649      * @param filter include only the included constructors if filter==true
   650      * @return an array of ConstructorDocImpl for representing the visible
   651      * constructors in this class.
   652      */
   653     public ConstructorDoc[] constructors(boolean filter) {
   654         Names names = tsym.name.table.names;
   655         List<ConstructorDocImpl> constructors = List.nil();
   656         for (Scope.Entry e = tsym.members().elems; e != null; e = e.sibling) {
   657             if (e.sym != null &&
   658                 e.sym.kind == Kinds.MTH && e.sym.name == names.init) {
   659                 MethodSymbol s = (MethodSymbol)e.sym;
   660                 if (!filter || env.shouldDocument(s)) {
   661                     constructors = constructors.prepend(env.getConstructorDoc(s));
   662                 }
   663             }
   664         }
   665         //### Cache constructors here?
   666         return constructors.toArray(new ConstructorDocImpl[constructors.length()]);
   667     }
   669     /**
   670      * Return included constructors in class.
   671      *
   672      * @return an array of ConstructorDocImpl for representing the visible
   673      * constructors in this class.
   674      */
   675     public ConstructorDoc[] constructors() {
   676         return constructors(true);
   677     }
   679     /**
   680      * Adds all inner classes of this class, and their
   681      * inner classes recursively, to the list l.
   682      */
   683     void addAllClasses(ListBuffer<ClassDocImpl> l, boolean filtered) {
   684         try {
   685             if (isSynthetic()) return;
   686             // sometimes synthetic classes are not marked synthetic
   687             if (!JavadocTool.isValidClassName(tsym.name.toString())) return;
   688             if (filtered && !env.shouldDocument(tsym)) return;
   689             if (l.contains(this)) return;
   690             l.append(this);
   691             List<ClassDocImpl> more = List.nil();
   692             for (Scope.Entry e = tsym.members().elems; e != null;
   693                  e = e.sibling) {
   694                 if (e.sym != null && e.sym.kind == Kinds.TYP) {
   695                     ClassSymbol s = (ClassSymbol)e.sym;
   696                     ClassDocImpl c = env.getClassDoc(s);
   697                     if (c.isSynthetic()) continue;
   698                     if (c != null) more = more.prepend(c);
   699                 }
   700             }
   701             // this extra step preserves the ordering from oldjavadoc
   702             for (; more.nonEmpty(); more=more.tail) {
   703                 more.head.addAllClasses(l, filtered);
   704             }
   705         } catch (CompletionFailure e) {
   706             // quietly ignore completion failures
   707         }
   708     }
   710     /**
   711      * Return inner classes within this class.
   712      *
   713      * @param filter include only the included inner classes if filter==true.
   714      * @return an array of ClassDocImpl for representing the visible
   715      * classes defined in this class. Anonymous and local classes
   716      * are not included.
   717      */
   718     public ClassDoc[] innerClasses(boolean filter) {
   719         ListBuffer<ClassDocImpl> innerClasses = new ListBuffer<ClassDocImpl>();
   720         for (Scope.Entry e = tsym.members().elems; e != null; e = e.sibling) {
   721             if (e.sym != null && e.sym.kind == Kinds.TYP) {
   722                 ClassSymbol s = (ClassSymbol)e.sym;
   723                 if ((s.flags_field & Flags.SYNTHETIC) != 0) continue;
   724                 if (!filter || env.isVisible(s)) {
   725                     innerClasses.prepend(env.getClassDoc(s));
   726                 }
   727             }
   728         }
   729         //### Cache classes here?
   730         return innerClasses.toArray(new ClassDocImpl[innerClasses.length()]);
   731     }
   733     /**
   734      * Return included inner classes within this class.
   735      *
   736      * @return an array of ClassDocImpl for representing the visible
   737      * classes defined in this class. Anonymous and local classes
   738      * are not included.
   739      */
   740     public ClassDoc[] innerClasses() {
   741         return innerClasses(true);
   742     }
   744     /**
   745      * Find a class within the context of this class.
   746      * Search order: qualified name, in this class (inner),
   747      * in this package, in the class imports, in the package
   748      * imports.
   749      * Return the ClassDocImpl if found, null if not found.
   750      */
   751     //### The specified search order is not the normal rule the
   752     //### compiler would use.  Leave as specified or change it?
   753     public ClassDoc findClass(String className) {
   754         ClassDoc searchResult = searchClass(className);
   755         if (searchResult == null) {
   756             ClassDocImpl enclosingClass = (ClassDocImpl)containingClass();
   757             //Expand search space to include enclosing class.
   758             while (enclosingClass != null && enclosingClass.containingClass() != null) {
   759                 enclosingClass = (ClassDocImpl)enclosingClass.containingClass();
   760             }
   761             searchResult = enclosingClass == null ?
   762                 null : enclosingClass.searchClass(className);
   763         }
   764         return searchResult;
   765     }
   767     private ClassDoc searchClass(String className) {
   768         Names names = tsym.name.table.names;
   770         // search by qualified name first
   771         ClassDoc cd = env.lookupClass(className);
   772         if (cd != null) {
   773             return cd;
   774         }
   776         // search inner classes
   777         //### Add private entry point to avoid creating array?
   778         //### Replicate code in innerClasses here to avoid consing?
   779         for (ClassDoc icd : innerClasses()) {
   780             if (icd.name().equals(className) ||
   781                     //### This is from original javadoc but it looks suspicious to me...
   782                     //### I believe it is attempting to compensate for the confused
   783                     //### convention of including the nested class qualifiers in the
   784                     //### 'name' of the inner class, rather than the true simple name.
   785                     icd.name().endsWith("." + className)) {
   786                 return icd;
   787             } else {
   788                 ClassDoc innercd = ((ClassDocImpl) icd).searchClass(className);
   789                 if (innercd != null) {
   790                     return innercd;
   791                 }
   792             }
   793         }
   795         // check in this package
   796         cd = containingPackage().findClass(className);
   797         if (cd != null) {
   798             return cd;
   799         }
   801         // make sure that this symbol has been completed
   802         if (tsym.completer != null) {
   803             tsym.complete();
   804         }
   806         // search imports
   808         if (tsym.sourcefile != null) {
   810             //### This information is available only for source classes.
   812             Env<AttrContext> compenv = env.enter.getEnv(tsym);
   813             if (compenv == null) return null;
   815             Scope s = compenv.toplevel.namedImportScope;
   816             for (Scope.Entry e = s.lookup(names.fromString(className)); e.scope != null; e = e.next()) {
   817                 if (e.sym.kind == Kinds.TYP) {
   818                     ClassDoc c = env.getClassDoc((ClassSymbol)e.sym);
   819                     return c;
   820                 }
   821             }
   823             s = compenv.toplevel.starImportScope;
   824             for (Scope.Entry e = s.lookup(names.fromString(className)); e.scope != null; e = e.next()) {
   825                 if (e.sym.kind == Kinds.TYP) {
   826                     ClassDoc c = env.getClassDoc((ClassSymbol)e.sym);
   827                     return c;
   828                 }
   829             }
   830         }
   832         return null; // not found
   833     }
   836     private boolean hasParameterTypes(MethodSymbol method, String[] argTypes) {
   838         if (argTypes == null) {
   839             // wildcard
   840             return true;
   841         }
   843         int i = 0;
   844         List<Type> types = method.type.getParameterTypes();
   846         if (argTypes.length != types.length()) {
   847             return false;
   848         }
   850         for (Type t : types) {
   851             String argType = argTypes[i++];
   852             // For vararg method, "T..." matches type T[].
   853             if (i == argTypes.length) {
   854                 argType = argType.replace("...", "[]");
   855             }
   856             if (!hasTypeName(env.types.erasure(t), argType)) {  //###(gj)
   857                 return false;
   858             }
   859         }
   860         return true;
   861     }
   862     // where
   863     private boolean hasTypeName(Type t, String name) {
   864         return
   865             name.equals(TypeMaker.getTypeName(t, true))
   866             ||
   867             name.equals(TypeMaker.getTypeName(t, false))
   868             ||
   869             (qualifiedName() + "." + name).equals(TypeMaker.getTypeName(t, true));
   870     }
   874     /**
   875      * Find a method in this class scope.
   876      * Search order: this class, interfaces, superclasses, outerclasses.
   877      * Note that this is not necessarily what the compiler would do!
   878      *
   879      * @param methodName the unqualified name to search for.
   880      * @param paramTypes the array of Strings for method parameter types.
   881      * @return the first MethodDocImpl which matches, null if not found.
   882      */
   883     public MethodDocImpl findMethod(String methodName, String[] paramTypes) {
   884         // Use hash table 'searched' to avoid searching same class twice.
   885         //### It is not clear how this could happen.
   886         return searchMethod(methodName, paramTypes, new HashSet<ClassDocImpl>());
   887     }
   889     private MethodDocImpl searchMethod(String methodName,
   890                                        String[] paramTypes, Set<ClassDocImpl> searched) {
   891         //### Note that this search is not necessarily what the compiler would do!
   893         Names names = tsym.name.table.names;
   894         // do not match constructors
   895         if (names.init.contentEquals(methodName)) {
   896             return null;
   897         }
   899         ClassDocImpl cdi;
   900         MethodDocImpl mdi;
   902         if (searched.contains(this)) {
   903             return null;
   904         }
   905         searched.add(this);
   907         //DEBUG
   908         /*---------------------------------*
   909          System.out.print("searching " + this + " for " + methodName);
   910          if (paramTypes == null) {
   911          System.out.println("()");
   912          } else {
   913          System.out.print("(");
   914          for (int k=0; k < paramTypes.length; k++) {
   915          System.out.print(paramTypes[k]);
   916          if ((k + 1) < paramTypes.length) {
   917          System.out.print(", ");
   918          }
   919          }
   920          System.out.println(")");
   921          }
   922          *---------------------------------*/
   924         // search current class
   925         Scope.Entry e = tsym.members().lookup(names.fromString(methodName));
   927         //### Using modifier filter here isn't really correct,
   928         //### but emulates the old behavior.  Instead, we should
   929         //### apply the normal rules of visibility and inheritance.
   931         if (paramTypes == null) {
   932             // If no parameters specified, we are allowed to return
   933             // any method with a matching name.  In practice, the old
   934             // code returned the first method, which is now the last!
   935             // In order to provide textually identical results, we
   936             // attempt to emulate the old behavior.
   937             MethodSymbol lastFound = null;
   938             for (; e.scope != null; e = e.next()) {
   939                 if (e.sym.kind == Kinds.MTH) {
   940                     //### Should intern methodName as Name.
   941                     if (e.sym.name.toString().equals(methodName)) {
   942                         lastFound = (MethodSymbol)e.sym;
   943                     }
   944                 }
   945             }
   946             if (lastFound != null) {
   947                 return env.getMethodDoc(lastFound);
   948             }
   949         } else {
   950             for (; e.scope != null; e = e.next()) {
   951                 if (e.sym != null &&
   952                     e.sym.kind == Kinds.MTH) {
   953                     //### Should intern methodName as Name.
   954                     if (hasParameterTypes((MethodSymbol)e.sym, paramTypes)) {
   955                         return env.getMethodDoc((MethodSymbol)e.sym);
   956                     }
   957                 }
   958             }
   959         }
   961         //### If we found a MethodDoc above, but which did not pass
   962         //### the modifier filter, we should return failure here!
   964         // search superclass
   965         cdi = (ClassDocImpl)superclass();
   966         if (cdi != null) {
   967             mdi = cdi.searchMethod(methodName, paramTypes, searched);
   968             if (mdi != null) {
   969                 return mdi;
   970             }
   971         }
   973         // search interfaces
   974         ClassDoc intf[] = interfaces();
   975         for (int i = 0; i < intf.length; i++) {
   976             cdi = (ClassDocImpl)intf[i];
   977             mdi = cdi.searchMethod(methodName, paramTypes, searched);
   978             if (mdi != null) {
   979                 return mdi;
   980             }
   981         }
   983         // search enclosing class
   984         cdi = (ClassDocImpl)containingClass();
   985         if (cdi != null) {
   986             mdi = cdi.searchMethod(methodName, paramTypes, searched);
   987             if (mdi != null) {
   988                 return mdi;
   989             }
   990         }
   992         //###(gj) As a temporary measure until type variables are better
   993         //### handled, try again without the parameter types.
   994         //### This should most often find the right method, and occassionally
   995         //### find the wrong one.
   996         //if (paramTypes != null) {
   997         //    return findMethod(methodName, null);
   998         //}
  1000         return null;
  1003     /**
  1004      * Find constructor in this class.
  1006      * @param constrName the unqualified name to search for.
  1007      * @param paramTypes the array of Strings for constructor parameters.
  1008      * @return the first ConstructorDocImpl which matches, null if not found.
  1009      */
  1010     public ConstructorDoc findConstructor(String constrName,
  1011                                           String[] paramTypes) {
  1012         Names names = tsym.name.table.names;
  1013         for (Scope.Entry e = tsym.members().lookup(names.fromString("<init>")); e.scope != null; e = e.next()) {
  1014             if (e.sym.kind == Kinds.MTH) {
  1015                 if (hasParameterTypes((MethodSymbol)e.sym, paramTypes)) {
  1016                     return env.getConstructorDoc((MethodSymbol)e.sym);
  1021         //###(gj) As a temporary measure until type variables are better
  1022         //### handled, try again without the parameter types.
  1023         //### This will often find the right constructor, and occassionally
  1024         //### find the wrong one.
  1025         //if (paramTypes != null) {
  1026         //    return findConstructor(constrName, null);
  1027         //}
  1029         return null;
  1032     /**
  1033      * Find a field in this class scope.
  1034      * Search order: this class, outerclasses, interfaces,
  1035      * superclasses. IMP: If see tag is defined in an inner class,
  1036      * which extends a super class and if outerclass and the super
  1037      * class have a visible field in common then Java compiler cribs
  1038      * about the ambiguity, but the following code will search in the
  1039      * above given search order.
  1041      * @param fieldName the unqualified name to search for.
  1042      * @return the first FieldDocImpl which matches, null if not found.
  1043      */
  1044     public FieldDoc findField(String fieldName) {
  1045         return searchField(fieldName, new HashSet<ClassDocImpl>());
  1048     private FieldDocImpl searchField(String fieldName, Set<ClassDocImpl> searched) {
  1049         Names names = tsym.name.table.names;
  1050         if (searched.contains(this)) {
  1051             return null;
  1053         searched.add(this);
  1055         for (Scope.Entry e = tsym.members().lookup(names.fromString(fieldName)); e.scope != null; e = e.next()) {
  1056             if (e.sym.kind == Kinds.VAR) {
  1057                 //### Should intern fieldName as Name.
  1058                 return env.getFieldDoc((VarSymbol)e.sym);
  1062         //### If we found a FieldDoc above, but which did not pass
  1063         //### the modifier filter, we should return failure here!
  1065         ClassDocImpl cdi = (ClassDocImpl)containingClass();
  1066         if (cdi != null) {
  1067             FieldDocImpl fdi = cdi.searchField(fieldName, searched);
  1068             if (fdi != null) {
  1069                 return fdi;
  1073         // search superclass
  1074         cdi = (ClassDocImpl)superclass();
  1075         if (cdi != null) {
  1076             FieldDocImpl fdi = cdi.searchField(fieldName, searched);
  1077             if (fdi != null) {
  1078                 return fdi;
  1082         // search interfaces
  1083         ClassDoc intf[] = interfaces();
  1084         for (int i = 0; i < intf.length; i++) {
  1085             cdi = (ClassDocImpl)intf[i];
  1086             FieldDocImpl fdi = cdi.searchField(fieldName, searched);
  1087             if (fdi != null) {
  1088                 return fdi;
  1092         return null;
  1095     /**
  1096      * Get the list of classes declared as imported.
  1097      * These are called "single-type-import declarations" in the JLS.
  1098      * This method is deprecated in the ClassDoc interface.
  1100      * @return an array of ClassDocImpl representing the imported classes.
  1102      * @deprecated  Import declarations are implementation details that
  1103      *          should not be exposed here.  In addition, not all imported
  1104      *          classes are imported through single-type-import declarations.
  1105      */
  1106     @Deprecated
  1107     public ClassDoc[] importedClasses() {
  1108         // information is not available for binary classfiles
  1109         if (tsym.sourcefile == null) return new ClassDoc[0];
  1111         ListBuffer<ClassDocImpl> importedClasses = new ListBuffer<ClassDocImpl>();
  1113         Env<AttrContext> compenv = env.enter.getEnv(tsym);
  1114         if (compenv == null) return new ClassDocImpl[0];
  1116         Name asterisk = tsym.name.table.names.asterisk;
  1117         for (JCTree t : compenv.toplevel.defs) {
  1118             if (t.hasTag(IMPORT)) {
  1119                 JCTree imp = ((JCImport) t).qualid;
  1120                 if ((TreeInfo.name(imp) != asterisk) &&
  1121                         (imp.type.tsym.kind & Kinds.TYP) != 0) {
  1122                     importedClasses.append(
  1123                             env.getClassDoc((ClassSymbol)imp.type.tsym));
  1128         return importedClasses.toArray(new ClassDocImpl[importedClasses.length()]);
  1131     /**
  1132      * Get the list of packages declared as imported.
  1133      * These are called "type-import-on-demand declarations" in the JLS.
  1134      * This method is deprecated in the ClassDoc interface.
  1136      * @return an array of PackageDocImpl representing the imported packages.
  1138      * ###NOTE: the syntax supports importing all inner classes from a class as well.
  1139      * @deprecated  Import declarations are implementation details that
  1140      *          should not be exposed here.  In addition, this method's
  1141      *          return type does not allow for all type-import-on-demand
  1142      *          declarations to be returned.
  1143      */
  1144     @Deprecated
  1145     public PackageDoc[] importedPackages() {
  1146         // information is not available for binary classfiles
  1147         if (tsym.sourcefile == null) return new PackageDoc[0];
  1149         ListBuffer<PackageDocImpl> importedPackages = new ListBuffer<PackageDocImpl>();
  1151         //### Add the implicit "import java.lang.*" to the result
  1152         Names names = tsym.name.table.names;
  1153         importedPackages.append(env.getPackageDoc(env.reader.enterPackage(names.java_lang)));
  1155         Env<AttrContext> compenv = env.enter.getEnv(tsym);
  1156         if (compenv == null) return new PackageDocImpl[0];
  1158         for (JCTree t : compenv.toplevel.defs) {
  1159             if (t.hasTag(IMPORT)) {
  1160                 JCTree imp = ((JCImport) t).qualid;
  1161                 if (TreeInfo.name(imp) == names.asterisk) {
  1162                     JCFieldAccess sel = (JCFieldAccess)imp;
  1163                     Symbol s = sel.selected.type.tsym;
  1164                     PackageDocImpl pdoc = env.getPackageDoc(s.packge());
  1165                     if (!importedPackages.contains(pdoc))
  1166                         importedPackages.append(pdoc);
  1171         return importedPackages.toArray(new PackageDocImpl[importedPackages.length()]);
  1174     /**
  1175      * Return the type's dimension information.
  1176      * Always return "", as this is not an array type.
  1177      */
  1178     public String dimension() {
  1179         return "";
  1182     /**
  1183      * Return this type as a class, which it already is.
  1184      */
  1185     public ClassDoc asClassDoc() {
  1186         return this;
  1189     /**
  1190      * Return null (unless overridden), as this is not an annotation type.
  1191      */
  1192     public AnnotationTypeDoc asAnnotationTypeDoc() {
  1193         return null;
  1196     /**
  1197      * Return null, as this is not a class instantiation.
  1198      */
  1199     public ParameterizedType asParameterizedType() {
  1200         return null;
  1203     /**
  1204      * Return null, as this is not a type variable.
  1205      */
  1206     public TypeVariable asTypeVariable() {
  1207         return null;
  1210     /**
  1211      * Return null, as this is not a wildcard type.
  1212      */
  1213     public WildcardType asWildcardType() {
  1214         return null;
  1217     /**
  1218      * Returns null, as this is not an annotated type.
  1219      */
  1220     public AnnotatedType asAnnotatedType() {
  1221         return null;
  1224     /**
  1225      * Return false, as this is not a primitive type.
  1226      */
  1227     public boolean isPrimitive() {
  1228         return false;
  1231     //--- Serialization ---
  1233     //### These methods ignore modifier filter.
  1235     /**
  1236      * Return true if this class implements <code>java.io.Serializable</code>.
  1238      * Since <code>java.io.Externalizable</code> extends
  1239      * <code>java.io.Serializable</code>,
  1240      * Externalizable objects are also Serializable.
  1241      */
  1242     public boolean isSerializable() {
  1243         try {
  1244             return env.types.isSubtype(type, env.syms.serializableType);
  1245         } catch (CompletionFailure ex) {
  1246             // quietly ignore completion failures
  1247             return false;
  1251     /**
  1252      * Return true if this class implements
  1253      * <code>java.io.Externalizable</code>.
  1254      */
  1255     public boolean isExternalizable() {
  1256         try {
  1257             return env.types.isSubtype(type, env.externalizableSym.type);
  1258         } catch (CompletionFailure ex) {
  1259             // quietly ignore completion failures
  1260             return false;
  1264     /**
  1265      * Return the serialization methods for this class.
  1267      * @return an array of <code>MethodDocImpl</code> that represents
  1268      * the serialization methods for this class.
  1269      */
  1270     public MethodDoc[] serializationMethods() {
  1271         if (serializedForm == null) {
  1272             serializedForm = new SerializedForm(env, tsym, this);
  1274         //### Clone this?
  1275         return serializedForm.methods();
  1278     /**
  1279      * Return the Serializable fields of class.<p>
  1281      * Return either a list of default fields documented by
  1282      * <code>serial</code> tag<br>
  1283      * or return a single <code>FieldDoc</code> for
  1284      * <code>serialPersistentField</code> member.
  1285      * There should be a <code>serialField</code> tag for
  1286      * each Serializable field defined by an <code>ObjectStreamField</code>
  1287      * array component of <code>serialPersistentField</code>.
  1289      * @returns an array of <code>FieldDoc</code> for the Serializable fields
  1290      * of this class.
  1292      * @see #definesSerializableFields()
  1293      * @see SerialFieldTagImpl
  1294      */
  1295     public FieldDoc[] serializableFields() {
  1296         if (serializedForm == null) {
  1297             serializedForm = new SerializedForm(env, tsym, this);
  1299         //### Clone this?
  1300         return serializedForm.fields();
  1303     /**
  1304      * Return true if Serializable fields are explicitly defined with
  1305      * the special class member <code>serialPersistentFields</code>.
  1307      * @see #serializableFields()
  1308      * @see SerialFieldTagImpl
  1309      */
  1310     public boolean definesSerializableFields() {
  1311         if (!isSerializable() || isExternalizable()) {
  1312             return false;
  1313         } else {
  1314             if (serializedForm == null) {
  1315                 serializedForm = new SerializedForm(env, tsym, this);
  1317             //### Clone this?
  1318             return serializedForm.definesSerializableFields();
  1322     /**
  1323      * Determine if a class is a RuntimeException.
  1324      * <p>
  1325      * Used only by ThrowsTagImpl.
  1326      */
  1327     boolean isRuntimeException() {
  1328         return tsym.isSubClass(env.syms.runtimeExceptionType.tsym, env.types);
  1331     /**
  1332      * Return the source position of the entity, or null if
  1333      * no position is available.
  1334      */
  1335     @Override
  1336     public SourcePosition position() {
  1337         if (tsym.sourcefile == null) return null;
  1338         return SourcePositionImpl.make(tsym.sourcefile,
  1339                                        (tree==null) ? Position.NOPOS : tree.pos,
  1340                                        lineMap);

mercurial