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

Thu, 02 Oct 2008 19:58:40 -0700

author
xdono
date
Thu, 02 Oct 2008 19:58:40 -0700
changeset 117
24a47c3062fe
parent 113
eff38cc97183
child 197
1bf037016426
permissions
-rw-r--r--

6754988: Update copyright year
Summary: Update for files that have been modified starting July 2008
Reviewed-by: ohair, tbell

     1 /*
     2  * Copyright 1997-2008 Sun Microsystems, Inc.  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.  Sun designates this
     8  * particular file as subject to the "Classpath" exception as provided
     9  * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
    22  * CA 95054 USA or visit www.sun.com if you need additional information or
    23  * have any questions.
    24  */
    26 package com.sun.tools.javadoc;
    28 import com.sun.javadoc.*;
    30 import static com.sun.javadoc.LanguageVersion.*;
    32 import com.sun.tools.javac.util.List;
    33 import com.sun.tools.javac.util.ListBuffer;
    34 import com.sun.tools.javac.util.Name;
    35 import com.sun.tools.javac.util.Position;
    37 import com.sun.tools.javac.code.Flags;
    38 import com.sun.tools.javac.code.Kinds;
    39 import com.sun.tools.javac.code.TypeTags;
    40 import com.sun.tools.javac.code.Type;
    41 import com.sun.tools.javac.code.Type.ClassType;
    42 import com.sun.tools.javac.code.Scope;
    43 import com.sun.tools.javac.code.Symbol;
    44 import com.sun.tools.javac.code.Symbol.*;
    46 import com.sun.tools.javac.comp.AttrContext;
    47 import com.sun.tools.javac.comp.Env;
    49 import com.sun.tools.javac.tree.JCTree;
    50 import com.sun.tools.javac.tree.JCTree.JCFieldAccess;
    51 import com.sun.tools.javac.tree.JCTree.JCImport;
    52 import com.sun.tools.javac.tree.JCTree.JCClassDecl;
    53 import com.sun.tools.javac.tree.TreeInfo;
    55 import com.sun.tools.javac.util.Names;
    56 import static com.sun.tools.javac.code.Flags.*;
    57 import static com.sun.tools.javac.code.Kinds.*;
    59 import java.io.File;
    60 import java.util.Set;
    61 import java.util.HashSet;
    62 import java.lang.reflect.Modifier;
    64 /**
    65  * Represents a java class and provides access to information
    66  * about the class, the class' comment and tags, and the
    67  * members of the class.  A ClassDocImpl only exists if it was
    68  * processed in this run of javadoc.  References to classes
    69  * which may or may not have been processed in this run are
    70  * referred to using Type (which can be converted to ClassDocImpl,
    71  * if possible).
    72  *
    73  * @see Type
    74  *
    75  * @since 1.2
    76  * @author Robert Field
    77  * @author Neal Gafter (rewrite)
    78  * @author Scott Seligman (generics, enums, annotations)
    79  */
    81 public class ClassDocImpl extends ProgramElementDocImpl implements ClassDoc {
    83     public final ClassType type;        // protected->public for debugging
    84     protected final ClassSymbol tsym;
    86     boolean isIncluded = false;         // Set in RootDocImpl
    88     private SerializedForm serializedForm;
    90     /**
    91      * Constructor
    92      */
    93     public ClassDocImpl(DocEnv env, ClassSymbol sym) {
    94         this(env, sym, null, null, null);
    95     }
    97     /**
    98      * Constructor
    99      */
   100     public ClassDocImpl(DocEnv env, ClassSymbol sym, String documentation,
   101                         JCClassDecl tree, Position.LineMap lineMap) {
   102         super(env, sym, documentation, tree, lineMap);
   103         this.type = (ClassType)sym.type;
   104         this.tsym = sym;
   105     }
   107     /**
   108      * Returns the flags in terms of javac's flags
   109      */
   110     protected long getFlags() {
   111         return getFlags(tsym);
   112     }
   114     /**
   115      * Returns the flags of a ClassSymbol in terms of javac's flags
   116      */
   117     static long getFlags(ClassSymbol clazz) {
   118         while (true) {
   119             try {
   120                 return clazz.flags();
   121             } catch (CompletionFailure ex) {
   122                 // quietly ignore completion failures
   123             }
   124         }
   125     }
   127     /**
   128      * Is a ClassSymbol an annotation type?
   129      */
   130     static boolean isAnnotationType(ClassSymbol clazz) {
   131         return (getFlags(clazz) & Flags.ANNOTATION) != 0;
   132     }
   134     /**
   135      * Identify the containing class
   136      */
   137     protected ClassSymbol getContainingClass() {
   138         return tsym.owner.enclClass();
   139     }
   141     /**
   142      * Return true if this is a class, not an interface.
   143      */
   144     public boolean isClass() {
   145         return !Modifier.isInterface(getModifiers());
   146     }
   148     /**
   149      * Return true if this is a ordinary class,
   150      * not an enumeration, exception, an error, or an interface.
   151      */
   152     public boolean isOrdinaryClass() {
   153         if (isEnum() || isInterface() || isAnnotationType()) {
   154             return false;
   155         }
   156         for (Type t = type; t.tag == TypeTags.CLASS; t = env.types.supertype(t)) {
   157             if (t.tsym == env.syms.errorType.tsym ||
   158                 t.tsym == env.syms.exceptionType.tsym) {
   159                 return false;
   160             }
   161         }
   162         return true;
   163     }
   165     /**
   166      * Return true if this is an enumeration.
   167      * (For legacy doclets, return false.)
   168      */
   169     public boolean isEnum() {
   170         return (getFlags() & Flags.ENUM) != 0
   171                &&
   172                !env.legacyDoclet;
   173     }
   175     /**
   176      * Return true if this is an interface, but not an annotation type.
   177      * Overridden by AnnotationTypeDocImpl.
   178      */
   179     public boolean isInterface() {
   180         return Modifier.isInterface(getModifiers());
   181     }
   183     /**
   184      * Return true if this is an exception class
   185      */
   186     public boolean isException() {
   187         if (isEnum() || isInterface() || isAnnotationType()) {
   188             return false;
   189         }
   190         for (Type t = type; t.tag == TypeTags.CLASS; t = env.types.supertype(t)) {
   191             if (t.tsym == env.syms.exceptionType.tsym) {
   192                 return true;
   193             }
   194         }
   195         return false;
   196     }
   198     /**
   199      * Return true if this is an error class
   200      */
   201     public boolean isError() {
   202         if (isEnum() || isInterface() || isAnnotationType()) {
   203             return false;
   204         }
   205         for (Type t = type; t.tag == TypeTags.CLASS; t = env.types.supertype(t)) {
   206             if (t.tsym == env.syms.errorType.tsym) {
   207                 return true;
   208             }
   209         }
   210         return false;
   211     }
   213     /**
   214      * Return true if this is a throwable class
   215      */
   216     public boolean isThrowable() {
   217         if (isEnum() || isInterface() || isAnnotationType()) {
   218             return false;
   219         }
   220         for (Type t = type; t.tag == TypeTags.CLASS; t = env.types.supertype(t)) {
   221             if (t.tsym == env.syms.throwableType.tsym) {
   222                 return true;
   223             }
   224         }
   225         return false;
   226     }
   228     /**
   229      * Return true if this class is abstract
   230      */
   231     public boolean isAbstract() {
   232         return Modifier.isAbstract(getModifiers());
   233     }
   235     /**
   236      * Returns true if this class was synthesized by the compiler.
   237      */
   238     public boolean isSynthetic() {
   239         return (getFlags() & Flags.SYNTHETIC) != 0;
   240     }
   242     /**
   243      * Return true if this class is included in the active set.
   244      * A ClassDoc is included iff either it is specified on the
   245      * commandline, or if it's containing package is specified
   246      * on the command line, or if it is a member class of an
   247      * included class.
   248      */
   250     public boolean isIncluded() {
   251         if (isIncluded) {
   252             return true;
   253         }
   254         if (env.shouldDocument(tsym)) {
   255             // Class is nameable from top-level and
   256             // the class and all enclosing classes
   257             // pass the modifier filter.
   258             if (containingPackage().isIncluded()) {
   259                 return isIncluded=true;
   260             }
   261             ClassDoc outer = containingClass();
   262             if (outer != null && outer.isIncluded()) {
   263                 return isIncluded=true;
   264             }
   265         }
   266         return false;
   267     }
   269     /**
   270      * Return the package that this class is contained in.
   271      */
   272     public PackageDoc containingPackage() {
   273         PackageDocImpl p = env.getPackageDoc(tsym.packge());
   274         SourcePosition po = position();
   275         if (po != null && p.setDocPath == false && p.zipDocPath == null) {
   276             //Set the package path if possible
   277             File packageDir = po.file().getParentFile();
   278             if (packageDir != null
   279                 && (new File(packageDir, "package.html")).exists()) {
   280                 p.setDocPath(packageDir.getPath());
   281             } else {
   282                 p.setDocPath(null);
   283             }
   284         }
   285         return p;
   286     }
   288     /**
   289      * Return the class name without package qualifier - but with
   290      * enclosing class qualifier - as a String.
   291      * <pre>
   292      * Examples:
   293      *  for java.util.Hashtable
   294      *  return Hashtable
   295      *  for java.util.Map.Entry
   296      *  return Map.Entry
   297      * </pre>
   298      */
   299     public String name() {
   300         return getClassName(tsym, false);
   301     }
   303     /**
   304      * Return the qualified class name as a String.
   305      * <pre>
   306      * Example:
   307      *  for java.util.Hashtable
   308      *  return java.util.Hashtable
   309      *  if no qualifier, just return flat name
   310      * </pre>
   311      */
   312     public String qualifiedName() {
   313         return getClassName(tsym, true);
   314     }
   316     /**
   317      * Return unqualified name of type excluding any dimension information.
   318      * <p>
   319      * For example, a two dimensional array of String returns 'String'.
   320      */
   321     public String typeName() {
   322         return name();
   323     }
   325     /**
   326      * Return qualified name of type excluding any dimension information.
   327      *<p>
   328      * For example, a two dimensional array of String
   329      * returns 'java.lang.String'.
   330      */
   331     public String qualifiedTypeName() {
   332         return qualifiedName();
   333     }
   335     /**
   336      * Return the simple name of this type.
   337      */
   338     public String simpleTypeName() {
   339         return tsym.name.toString();
   340     }
   342     /**
   343      * Return the qualified name and any type parameters.
   344      * Each parameter is a type variable with optional bounds.
   345      */
   346     public String toString() {
   347         return classToString(env, tsym, true);
   348     }
   350     /**
   351      * Return the class name as a string.  If "full" is true the name is
   352      * qualified, otherwise it is qualified by its enclosing class(es) only.
   353      */
   354     static String getClassName(ClassSymbol c, boolean full) {
   355         if (full) {
   356             return c.getQualifiedName().toString();
   357         } else {
   358             String n = "";
   359             for ( ; c != null; c = c.owner.enclClass()) {
   360                 n = c.name + (n.equals("") ? "" : ".") + n;
   361             }
   362             return n;
   363         }
   364     }
   366     /**
   367      * Return the class name with any type parameters as a string.
   368      * Each parameter is a type variable with optional bounds.
   369      * If "full" is true all names are qualified, otherwise they are
   370      * qualified by their enclosing class(es) only.
   371      */
   372     static String classToString(DocEnv env, ClassSymbol c, boolean full) {
   373         StringBuffer s = new StringBuffer();
   374         if (!c.isInner()) {             // if c is not an inner class
   375             s.append(getClassName(c, full));
   376         } else {
   377             // c is an inner class, so include type params of outer.
   378             ClassSymbol encl = c.owner.enclClass();
   379             s.append(classToString(env, encl, full))
   380              .append('.')
   381              .append(c.name);
   382         }
   383         s.append(TypeMaker.typeParametersString(env, c, full));
   384         return s.toString();
   385     }
   387     /**
   388      * Is this class (or any enclosing class) generic?  That is, does
   389      * it have type parameters?
   390      */
   391     static boolean isGeneric(ClassSymbol c) {
   392         return c.type.allparams().nonEmpty();
   393     }
   395     /**
   396      * Return the formal type parameters of this class or interface.
   397      * Return an empty array if there are none.
   398      */
   399     public TypeVariable[] typeParameters() {
   400         if (env.legacyDoclet) {
   401             return new TypeVariable[0];
   402         }
   403         TypeVariable res[] = new TypeVariable[type.getTypeArguments().length()];
   404         TypeMaker.getTypes(env, type.getTypeArguments(), res);
   405         return res;
   406     }
   408     /**
   409      * Return the type parameter tags of this class or interface.
   410      */
   411     public ParamTag[] typeParamTags() {
   412         return (env.legacyDoclet)
   413             ? new ParamTag[0]
   414             : comment().typeParamTags();
   415     }
   417     /**
   418      * Return the modifier string for this class. If it's an interface
   419      * exclude 'abstract' keyword from the modifier string
   420      */
   421     public String modifiers() {
   422         return Modifier.toString(modifierSpecifier());
   423     }
   425     public int modifierSpecifier() {
   426         int modifiers = getModifiers();
   427         return (isInterface() || isAnnotationType())
   428                 ? modifiers & ~Modifier.ABSTRACT
   429                 : modifiers;
   430     }
   432     /**
   433      * Return the superclass of this class
   434      *
   435      * @return the ClassDocImpl for the superclass of this class, null
   436      * if there is no superclass.
   437      */
   438     public ClassDoc superclass() {
   439         if (isInterface() || isAnnotationType()) return null;
   440         if (tsym == env.syms.objectType.tsym) return null;
   441         ClassSymbol c = (ClassSymbol)env.types.supertype(type).tsym;
   442         if (c == null || c == tsym) c = (ClassSymbol)env.syms.objectType.tsym;
   443         return env.getClassDoc(c);
   444     }
   446     /**
   447      * Return the superclass of this class.  Return null if this is an
   448      * interface.  A superclass is represented by either a
   449      * <code>ClassDoc</code> or a <code>ParameterizedType</code>.
   450      */
   451     public com.sun.javadoc.Type superclassType() {
   452         if (isInterface() || isAnnotationType() ||
   453                 (tsym == env.syms.objectType.tsym))
   454             return null;
   455         Type sup = env.types.supertype(type);
   456         return TypeMaker.getType(env,
   457                                  (sup != type) ? sup : env.syms.objectType);
   458     }
   460     /**
   461      * Test whether this class is a subclass of the specified class.
   462      *
   463      * @param cd the candidate superclass.
   464      * @return true if cd is a superclass of this class.
   465      */
   466     public boolean subclassOf(ClassDoc cd) {
   467         return tsym.isSubClass(((ClassDocImpl)cd).tsym, env.types);
   468     }
   470     /**
   471      * Return interfaces implemented by this class or interfaces
   472      * extended by this interface.
   473      *
   474      * @return An array of ClassDocImpl representing the interfaces.
   475      * Return an empty array if there are no interfaces.
   476      */
   477     public ClassDoc[] interfaces() {
   478         ListBuffer<ClassDocImpl> ta = new ListBuffer<ClassDocImpl>();
   479         for (Type t : env.types.interfaces(type)) {
   480             ta.append(env.getClassDoc((ClassSymbol)t.tsym));
   481         }
   482         //### Cache ta here?
   483         return ta.toArray(new ClassDocImpl[ta.length()]);
   484     }
   486     /**
   487      * Return interfaces implemented by this class or interfaces extended
   488      * by this interface. Includes only directly-declared interfaces, not
   489      * inherited interfaces.
   490      * Return an empty array if there are no interfaces.
   491      */
   492     public com.sun.javadoc.Type[] interfaceTypes() {
   493         //### Cache result here?
   494         return TypeMaker.getTypes(env, env.types.interfaces(type));
   495     }
   497     /**
   498      * Return fields in class.
   499      * @param filter include only the included fields if filter==true
   500      */
   501     public FieldDoc[] fields(boolean filter) {
   502         return fields(filter, false);
   503     }
   505     /**
   506      * Return included fields in class.
   507      */
   508     public FieldDoc[] fields() {
   509         return fields(true, false);
   510     }
   512     /**
   513      * Return the enum constants if this is an enum type.
   514      */
   515     public FieldDoc[] enumConstants() {
   516         return fields(false, true);
   517     }
   519     /**
   520      * Return fields in class.
   521      * @param filter  if true, return only the included fields
   522      * @param enumConstants  if true, return the enum constants instead
   523      */
   524     private FieldDoc[] fields(boolean filter, boolean enumConstants) {
   525         List<FieldDocImpl> fields = List.nil();
   526         for (Scope.Entry e = tsym.members().elems; e != null; e = e.sibling) {
   527             if (e.sym != null && e.sym.kind == VAR) {
   528                 VarSymbol s = (VarSymbol)e.sym;
   529                 boolean isEnum = ((s.flags() & Flags.ENUM) != 0) &&
   530                                  !env.legacyDoclet;
   531                 if (isEnum == enumConstants &&
   532                         (!filter || env.shouldDocument(s))) {
   533                     fields = fields.prepend(env.getFieldDoc(s));
   534                 }
   535             }
   536         }
   537         return fields.toArray(new FieldDocImpl[fields.length()]);
   538     }
   540     /**
   541      * Return methods in class.
   542      * This method is overridden by AnnotationTypeDocImpl.
   543      *
   544      * @param filter include only the included methods if filter==true
   545      * @return an array of MethodDocImpl for representing the visible
   546      * methods in this class.  Does not include constructors.
   547      */
   548     public MethodDoc[] methods(boolean filter) {
   549         Names names = tsym.name.table.names;
   550         List<MethodDocImpl> methods = List.nil();
   551         for (Scope.Entry e = tsym.members().elems; e != null; e = e.sibling) {
   552             if (e.sym != null &&
   553                 e.sym.kind == Kinds.MTH && e.sym.name != names.init) {
   554                 MethodSymbol s = (MethodSymbol)e.sym;
   555                 if (!filter || env.shouldDocument(s)) {
   556                     methods = methods.prepend(env.getMethodDoc(s));
   557                 }
   558             }
   559         }
   560         //### Cache methods here?
   561         return methods.toArray(new MethodDocImpl[methods.length()]);
   562     }
   564     /**
   565      * Return included methods in class.
   566      *
   567      * @return an array of MethodDocImpl for representing the visible
   568      * methods in this class.  Does not include constructors.
   569      */
   570     public MethodDoc[] methods() {
   571         return methods(true);
   572     }
   574     /**
   575      * Return constructors in class.
   576      *
   577      * @param filter include only the included constructors if filter==true
   578      * @return an array of ConstructorDocImpl for representing the visible
   579      * constructors in this class.
   580      */
   581     public ConstructorDoc[] constructors(boolean filter) {
   582         Names names = tsym.name.table.names;
   583         List<ConstructorDocImpl> constructors = List.nil();
   584         for (Scope.Entry e = tsym.members().elems; e != null; e = e.sibling) {
   585             if (e.sym != null &&
   586                 e.sym.kind == Kinds.MTH && e.sym.name == names.init) {
   587                 MethodSymbol s = (MethodSymbol)e.sym;
   588                 if (!filter || env.shouldDocument(s)) {
   589                     constructors = constructors.prepend(env.getConstructorDoc(s));
   590                 }
   591             }
   592         }
   593         //### Cache constructors here?
   594         return constructors.toArray(new ConstructorDocImpl[constructors.length()]);
   595     }
   597     /**
   598      * Return included constructors in class.
   599      *
   600      * @return an array of ConstructorDocImpl for representing the visible
   601      * constructors in this class.
   602      */
   603     public ConstructorDoc[] constructors() {
   604         return constructors(true);
   605     }
   607     /**
   608      * Adds all inner classes of this class, and their
   609      * inner classes recursively, to the list l.
   610      */
   611     void addAllClasses(ListBuffer<ClassDocImpl> l, boolean filtered) {
   612         try {
   613             if (isSynthetic()) return;
   614             // sometimes synthetic classes are not marked synthetic
   615             if (!JavadocTool.isValidClassName(tsym.name.toString())) return;
   616             if (filtered && !env.shouldDocument(tsym)) return;
   617             if (l.contains(this)) return;
   618             l.append(this);
   619             List<ClassDocImpl> more = List.nil();
   620             for (Scope.Entry e = tsym.members().elems; e != null;
   621                  e = e.sibling) {
   622                 if (e.sym != null && e.sym.kind == Kinds.TYP) {
   623                     ClassSymbol s = (ClassSymbol)e.sym;
   624                     ClassDocImpl c = env.getClassDoc(s);
   625                     if (c.isSynthetic()) continue;
   626                     if (c != null) more = more.prepend(c);
   627                 }
   628             }
   629             // this extra step preserves the ordering from oldjavadoc
   630             for (; more.nonEmpty(); more=more.tail) {
   631                 more.head.addAllClasses(l, filtered);
   632             }
   633         } catch (CompletionFailure e) {
   634             // quietly ignore completion failures
   635         }
   636     }
   638     /**
   639      * Return inner classes within this class.
   640      *
   641      * @param filter include only the included inner classes if filter==true.
   642      * @return an array of ClassDocImpl for representing the visible
   643      * classes defined in this class. Anonymous and local classes
   644      * are not included.
   645      */
   646     public ClassDoc[] innerClasses(boolean filter) {
   647         ListBuffer<ClassDocImpl> innerClasses = new ListBuffer<ClassDocImpl>();
   648         for (Scope.Entry e = tsym.members().elems; e != null; e = e.sibling) {
   649             if (e.sym != null && e.sym.kind == Kinds.TYP) {
   650                 ClassSymbol s = (ClassSymbol)e.sym;
   651                 if ((s.flags_field & Flags.SYNTHETIC) != 0) continue;
   652                 if (!filter || env.isVisible(s)) {
   653                     innerClasses.prepend(env.getClassDoc(s));
   654                 }
   655             }
   656         }
   657         //### Cache classes here?
   658         return innerClasses.toArray(new ClassDocImpl[innerClasses.length()]);
   659     }
   661     /**
   662      * Return included inner classes within this class.
   663      *
   664      * @return an array of ClassDocImpl for representing the visible
   665      * classes defined in this class. Anonymous and local classes
   666      * are not included.
   667      */
   668     public ClassDoc[] innerClasses() {
   669         return innerClasses(true);
   670     }
   672     /**
   673      * Find a class within the context of this class.
   674      * Search order: qualified name, in this class (inner),
   675      * in this package, in the class imports, in the package
   676      * imports.
   677      * Return the ClassDocImpl if found, null if not found.
   678      */
   679     //### The specified search order is not the normal rule the
   680     //### compiler would use.  Leave as specified or change it?
   681     public ClassDoc findClass(String className) {
   682         ClassDoc searchResult = searchClass(className);
   683         if (searchResult == null) {
   684             ClassDocImpl enclosingClass = (ClassDocImpl)containingClass();
   685             //Expand search space to include enclosing class.
   686             while (enclosingClass != null && enclosingClass.containingClass() != null) {
   687                 enclosingClass = (ClassDocImpl)enclosingClass.containingClass();
   688             }
   689             searchResult = enclosingClass == null ?
   690                 null : enclosingClass.searchClass(className);
   691         }
   692         return searchResult;
   693     }
   695     private ClassDoc searchClass(String className) {
   696         Names names = tsym.name.table.names;
   698         // search by qualified name first
   699         ClassDoc cd = env.lookupClass(className);
   700         if (cd != null) {
   701             return cd;
   702         }
   704         // search inner classes
   705         //### Add private entry point to avoid creating array?
   706         //### Replicate code in innerClasses here to avoid consing?
   707         ClassDoc innerClasses[] = innerClasses();
   708         for (int i = 0; i < innerClasses.length; i++) {
   709             if (innerClasses[i].name().equals(className) ||
   710                 //### This is from original javadoc but it looks suspicious to me...
   711                 //### I believe it is attempting to compensate for the confused
   712                 //### convention of including the nested class qualifiers in the
   713                 //### 'name' of the inner class, rather than the true simple name.
   714                 innerClasses[i].name().endsWith(className)) {
   715                 return innerClasses[i];
   716             } else {
   717                 ClassDoc innercd = ((ClassDocImpl) innerClasses[i]).searchClass(className);
   718                 if (innercd != null) {
   719                     return innercd;
   720                 }
   721             }
   722         }
   724         // check in this package
   725         cd = containingPackage().findClass(className);
   726         if (cd != null) {
   727             return cd;
   728         }
   730         // make sure that this symbol has been completed
   731         if (tsym.completer != null) {
   732             tsym.complete();
   733         }
   735         // search imports
   737         if (tsym.sourcefile != null) {
   739             //### This information is available only for source classes.
   741             Env<AttrContext> compenv = env.enter.getEnv(tsym);
   742             if (compenv == null) return null;
   744             Scope s = compenv.toplevel.namedImportScope;
   745             for (Scope.Entry e = s.lookup(names.fromString(className)); e.scope != null; e = e.next()) {
   746                 if (e.sym.kind == Kinds.TYP) {
   747                     ClassDoc c = env.getClassDoc((ClassSymbol)e.sym);
   748                     return c;
   749                 }
   750             }
   752             s = compenv.toplevel.starImportScope;
   753             for (Scope.Entry e = s.lookup(names.fromString(className)); e.scope != null; e = e.next()) {
   754                 if (e.sym.kind == Kinds.TYP) {
   755                     ClassDoc c = env.getClassDoc((ClassSymbol)e.sym);
   756                     return c;
   757                 }
   758             }
   759         }
   761         return null; // not found
   762     }
   765     private boolean hasParameterTypes(MethodSymbol method, String[] argTypes) {
   767         if (argTypes == null) {
   768             // wildcard
   769             return true;
   770         }
   772         int i = 0;
   773         List<Type> types = method.type.getParameterTypes();
   775         if (argTypes.length != types.length()) {
   776             return false;
   777         }
   779         for (Type t : types) {
   780             String argType = argTypes[i++];
   781             // For vararg method, "T..." matches type T[].
   782             if (i == argTypes.length) {
   783                 argType = argType.replace("...", "[]");
   784             }
   785             if (!hasTypeName(env.types.erasure(t), argType)) {  //###(gj)
   786                 return false;
   787             }
   788         }
   789         return true;
   790     }
   791     // where
   792     private boolean hasTypeName(Type t, String name) {
   793         return
   794             name.equals(TypeMaker.getTypeName(t, true))
   795             ||
   796             name.equals(TypeMaker.getTypeName(t, false))
   797             ||
   798             (qualifiedName() + "." + name).equals(TypeMaker.getTypeName(t, true));
   799     }
   803     /**
   804      * Find a method in this class scope.
   805      * Search order: this class, interfaces, superclasses, outerclasses.
   806      * Note that this is not necessarily what the compiler would do!
   807      *
   808      * @param methodName the unqualified name to search for.
   809      * @param paramTypeArray the array of Strings for method parameter types.
   810      * @return the first MethodDocImpl which matches, null if not found.
   811      */
   812     public MethodDocImpl findMethod(String methodName, String[] paramTypes) {
   813         // Use hash table 'searched' to avoid searching same class twice.
   814         //### It is not clear how this could happen.
   815         return searchMethod(methodName, paramTypes, new HashSet<ClassDocImpl>());
   816     }
   818     private MethodDocImpl searchMethod(String methodName,
   819                                        String[] paramTypes, Set<ClassDocImpl> searched) {
   820         //### Note that this search is not necessarily what the compiler would do!
   822         ClassDocImpl cdi;
   823         MethodDocImpl mdi;
   825         if (searched.contains(this)) {
   826             return null;
   827         }
   828         searched.add(this);
   830         //DEBUG
   831         /*---------------------------------*
   832          System.out.print("searching " + this + " for " + methodName);
   833          if (paramTypes == null) {
   834          System.out.println("()");
   835          } else {
   836          System.out.print("(");
   837          for (int k=0; k < paramTypes.length; k++) {
   838          System.out.print(paramTypes[k]);
   839          if ((k + 1) < paramTypes.length) {
   840          System.out.print(", ");
   841          }
   842          }
   843          System.out.println(")");
   844          }
   845          *---------------------------------*/
   847         // search current class
   848         Names names = tsym.name.table.names;
   849         Scope.Entry e = tsym.members().lookup(names.fromString(methodName));
   851         //### Using modifier filter here isn't really correct,
   852         //### but emulates the old behavior.  Instead, we should
   853         //### apply the normal rules of visibility and inheritance.
   855         if (paramTypes == null) {
   856             // If no parameters specified, we are allowed to return
   857             // any method with a matching name.  In practice, the old
   858             // code returned the first method, which is now the last!
   859             // In order to provide textually identical results, we
   860             // attempt to emulate the old behavior.
   861             MethodSymbol lastFound = null;
   862             for (; e.scope != null; e = e.next()) {
   863                 if (e.sym.kind == Kinds.MTH) {
   864                     //### Should intern methodName as Name.
   865                     if (e.sym.name.toString().equals(methodName)) {
   866                         lastFound = (MethodSymbol)e.sym;
   867                     }
   868                 }
   869             }
   870             if (lastFound != null) {
   871                 return env.getMethodDoc(lastFound);
   872             }
   873         } else {
   874             for (; e.scope != null; e = e.next()) {
   875                 if (e.sym != null &&
   876                     e.sym.kind == Kinds.MTH) {
   877                     //### Should intern methodName as Name.
   878                     if (hasParameterTypes((MethodSymbol)e.sym, paramTypes)) {
   879                         return env.getMethodDoc((MethodSymbol)e.sym);
   880                     }
   881                 }
   882             }
   883         }
   885         //### If we found a MethodDoc above, but which did not pass
   886         //### the modifier filter, we should return failure here!
   888         // search superclass
   889         cdi = (ClassDocImpl)superclass();
   890         if (cdi != null) {
   891             mdi = cdi.searchMethod(methodName, paramTypes, searched);
   892             if (mdi != null) {
   893                 return mdi;
   894             }
   895         }
   897         // search interfaces
   898         ClassDoc intf[] = interfaces();
   899         for (int i = 0; i < intf.length; i++) {
   900             cdi = (ClassDocImpl)intf[i];
   901             mdi = cdi.searchMethod(methodName, paramTypes, searched);
   902             if (mdi != null) {
   903                 return mdi;
   904             }
   905         }
   907         // search enclosing class
   908         cdi = (ClassDocImpl)containingClass();
   909         if (cdi != null) {
   910             mdi = cdi.searchMethod(methodName, paramTypes, searched);
   911             if (mdi != null) {
   912                 return mdi;
   913             }
   914         }
   916         //###(gj) As a temporary measure until type variables are better
   917         //### handled, try again without the parameter types.
   918         //### This should most often find the right method, and occassionally
   919         //### find the wrong one.
   920         //if (paramTypes != null) {
   921         //    return findMethod(methodName, null);
   922         //}
   924         return null;
   925     }
   927     /**
   928      * Find constructor in this class.
   929      *
   930      * @param constrName the unqualified name to search for.
   931      * @param paramTypeArray the array of Strings for constructor parameters.
   932      * @return the first ConstructorDocImpl which matches, null if not found.
   933      */
   934     public ConstructorDoc findConstructor(String constrName,
   935                                           String[] paramTypes) {
   936         Names names = tsym.name.table.names;
   937         for (Scope.Entry e = tsym.members().lookup(names.fromString("<init>")); e.scope != null; e = e.next()) {
   938             if (e.sym.kind == Kinds.MTH) {
   939                 if (hasParameterTypes((MethodSymbol)e.sym, paramTypes)) {
   940                     return env.getConstructorDoc((MethodSymbol)e.sym);
   941                 }
   942             }
   943         }
   945         //###(gj) As a temporary measure until type variables are better
   946         //### handled, try again without the parameter types.
   947         //### This will often find the right constructor, and occassionally
   948         //### find the wrong one.
   949         //if (paramTypes != null) {
   950         //    return findConstructor(constrName, null);
   951         //}
   953         return null;
   954     }
   956     /**
   957      * Find a field in this class scope.
   958      * Search order: this class, outerclasses, interfaces,
   959      * superclasses. IMP: If see tag is defined in an inner class,
   960      * which extends a super class and if outerclass and the super
   961      * class have a visible field in common then Java compiler cribs
   962      * about the ambiguity, but the following code will search in the
   963      * above given search order.
   964      *
   965      * @param fieldName the unqualified name to search for.
   966      * @return the first FieldDocImpl which matches, null if not found.
   967      */
   968     public FieldDoc findField(String fieldName) {
   969         return searchField(fieldName, new HashSet<ClassDocImpl>());
   970     }
   972     private FieldDocImpl searchField(String fieldName, Set<ClassDocImpl> searched) {
   973         Names names = tsym.name.table.names;
   974         if (searched.contains(this)) {
   975             return null;
   976         }
   977         searched.add(this);
   979         for (Scope.Entry e = tsym.members().lookup(names.fromString(fieldName)); e.scope != null; e = e.next()) {
   980             if (e.sym.kind == Kinds.VAR) {
   981                 //### Should intern fieldName as Name.
   982                 return env.getFieldDoc((VarSymbol)e.sym);
   983             }
   984         }
   986         //### If we found a FieldDoc above, but which did not pass
   987         //### the modifier filter, we should return failure here!
   989         ClassDocImpl cdi = (ClassDocImpl)containingClass();
   990         if (cdi != null) {
   991             FieldDocImpl fdi = cdi.searchField(fieldName, searched);
   992             if (fdi != null) {
   993                 return fdi;
   994             }
   995         }
   997         // search superclass
   998         cdi = (ClassDocImpl)superclass();
   999         if (cdi != null) {
  1000             FieldDocImpl fdi = cdi.searchField(fieldName, searched);
  1001             if (fdi != null) {
  1002                 return fdi;
  1006         // search interfaces
  1007         ClassDoc intf[] = interfaces();
  1008         for (int i = 0; i < intf.length; i++) {
  1009             cdi = (ClassDocImpl)intf[i];
  1010             FieldDocImpl fdi = cdi.searchField(fieldName, searched);
  1011             if (fdi != null) {
  1012                 return fdi;
  1016         return null;
  1019     /**
  1020      * Get the list of classes declared as imported.
  1021      * These are called "single-type-import declarations" in the JLS.
  1022      * This method is deprecated in the ClassDoc interface.
  1024      * @return an array of ClassDocImpl representing the imported classes.
  1026      * @deprecated  Import declarations are implementation details that
  1027      *          should not be exposed here.  In addition, not all imported
  1028      *          classes are imported through single-type-import declarations.
  1029      */
  1030     @Deprecated
  1031     public ClassDoc[] importedClasses() {
  1032         // information is not available for binary classfiles
  1033         if (tsym.sourcefile == null) return new ClassDoc[0];
  1035         ListBuffer<ClassDocImpl> importedClasses = new ListBuffer<ClassDocImpl>();
  1037         Env<AttrContext> compenv = env.enter.getEnv(tsym);
  1038         if (compenv == null) return new ClassDocImpl[0];
  1040         Name asterisk = tsym.name.table.names.asterisk;
  1041         for (JCTree t : compenv.toplevel.defs) {
  1042             if (t.getTag() == JCTree.IMPORT) {
  1043                 JCTree imp = ((JCImport) t).qualid;
  1044                 if ((TreeInfo.name(imp) != asterisk) &&
  1045                         (imp.type.tsym.kind & Kinds.TYP) != 0) {
  1046                     importedClasses.append(
  1047                             env.getClassDoc((ClassSymbol)imp.type.tsym));
  1052         return importedClasses.toArray(new ClassDocImpl[importedClasses.length()]);
  1055     /**
  1056      * Get the list of packages declared as imported.
  1057      * These are called "type-import-on-demand declarations" in the JLS.
  1058      * This method is deprecated in the ClassDoc interface.
  1060      * @return an array of PackageDocImpl representing the imported packages.
  1062      * ###NOTE: the syntax supports importing all inner classes from a class as well.
  1063      * @deprecated  Import declarations are implementation details that
  1064      *          should not be exposed here.  In addition, this method's
  1065      *          return type does not allow for all type-import-on-demand
  1066      *          declarations to be returned.
  1067      */
  1068     @Deprecated
  1069     public PackageDoc[] importedPackages() {
  1070         // information is not available for binary classfiles
  1071         if (tsym.sourcefile == null) return new PackageDoc[0];
  1073         ListBuffer<PackageDocImpl> importedPackages = new ListBuffer<PackageDocImpl>();
  1075         //### Add the implicit "import java.lang.*" to the result
  1076         Names names = tsym.name.table.names;
  1077         importedPackages.append(env.getPackageDoc(env.reader.enterPackage(names.java_lang)));
  1079         Env<AttrContext> compenv = env.enter.getEnv(tsym);
  1080         if (compenv == null) return new PackageDocImpl[0];
  1082         for (JCTree t : compenv.toplevel.defs) {
  1083             if (t.getTag() == JCTree.IMPORT) {
  1084                 JCTree imp = ((JCImport) t).qualid;
  1085                 if (TreeInfo.name(imp) == names.asterisk) {
  1086                     JCFieldAccess sel = (JCFieldAccess)imp;
  1087                     Symbol s = sel.selected.type.tsym;
  1088                     PackageDocImpl pdoc = env.getPackageDoc(s.packge());
  1089                     if (!importedPackages.contains(pdoc))
  1090                         importedPackages.append(pdoc);
  1095         return importedPackages.toArray(new PackageDocImpl[importedPackages.length()]);
  1098     /**
  1099      * Return the type's dimension information.
  1100      * Always return "", as this is not an array type.
  1101      */
  1102     public String dimension() {
  1103         return "";
  1106     /**
  1107      * Return this type as a class, which it already is.
  1108      */
  1109     public ClassDoc asClassDoc() {
  1110         return this;
  1113     /**
  1114      * Return null (unless overridden), as this is not an annotation type.
  1115      */
  1116     public AnnotationTypeDoc asAnnotationTypeDoc() {
  1117         return null;
  1120     /**
  1121      * Return null, as this is not a class instantiation.
  1122      */
  1123     public ParameterizedType asParameterizedType() {
  1124         return null;
  1127     /**
  1128      * Return null, as this is not a type variable.
  1129      */
  1130     public TypeVariable asTypeVariable() {
  1131         return null;
  1134     /**
  1135      * Return null, as this is not a wildcard type.
  1136      */
  1137     public WildcardType asWildcardType() {
  1138         return null;
  1141     /**
  1142      * Return false, as this is not a primitive type.
  1143      */
  1144     public boolean isPrimitive() {
  1145         return false;
  1148     //--- Serialization ---
  1150     //### These methods ignore modifier filter.
  1152     /**
  1153      * Return true if this class implements <code>java.io.Serializable</code>.
  1155      * Since <code>java.io.Externalizable</code> extends
  1156      * <code>java.io.Serializable</code>,
  1157      * Externalizable objects are also Serializable.
  1158      */
  1159     public boolean isSerializable() {
  1160         try {
  1161             return env.types.isSubtype(type, env.syms.serializableType);
  1162         } catch (CompletionFailure ex) {
  1163             // quietly ignore completion failures
  1164             return false;
  1168     /**
  1169      * Return true if this class implements
  1170      * <code>java.io.Externalizable</code>.
  1171      */
  1172     public boolean isExternalizable() {
  1173         try {
  1174             return env.types.isSubtype(type, env.externalizableSym.type);
  1175         } catch (CompletionFailure ex) {
  1176             // quietly ignore completion failures
  1177             return false;
  1181     /**
  1182      * Return the serialization methods for this class.
  1184      * @return an array of <code>MethodDocImpl</code> that represents
  1185      * the serialization methods for this class.
  1186      */
  1187     public MethodDoc[] serializationMethods() {
  1188         if (serializedForm == null) {
  1189             serializedForm = new SerializedForm(env, tsym, this);
  1191         //### Clone this?
  1192         return serializedForm.methods();
  1195     /**
  1196      * Return the Serializable fields of class.<p>
  1198      * Return either a list of default fields documented by
  1199      * <code>serial</code> tag<br>
  1200      * or return a single <code>FieldDoc</code> for
  1201      * <code>serialPersistentField</code> member.
  1202      * There should be a <code>serialField</code> tag for
  1203      * each Serializable field defined by an <code>ObjectStreamField</code>
  1204      * array component of <code>serialPersistentField</code>.
  1206      * @returns an array of <code>FieldDoc</code> for the Serializable fields
  1207      * of this class.
  1209      * @see #definesSerializableFields()
  1210      * @see SerialFieldTagImpl
  1211      */
  1212     public FieldDoc[] serializableFields() {
  1213         if (serializedForm == null) {
  1214             serializedForm = new SerializedForm(env, tsym, this);
  1216         //### Clone this?
  1217         return serializedForm.fields();
  1220     /**
  1221      * Return true if Serializable fields are explicitly defined with
  1222      * the special class member <code>serialPersistentFields</code>.
  1224      * @see #serializableFields()
  1225      * @see SerialFieldTagImpl
  1226      */
  1227     public boolean definesSerializableFields() {
  1228         if (!isSerializable() || isExternalizable()) {
  1229             return false;
  1230         } else {
  1231             if (serializedForm == null) {
  1232                 serializedForm = new SerializedForm(env, tsym, this);
  1234             //### Clone this?
  1235             return serializedForm.definesSerializableFields();
  1239     /**
  1240      * Determine if a class is a RuntimeException.
  1241      * <p>
  1242      * Used only by ThrowsTagImpl.
  1243      */
  1244     boolean isRuntimeException() {
  1245         return tsym.isSubClass(env.syms.runtimeExceptionType.tsym, env.types);
  1248     /**
  1249      * Return the source position of the entity, or null if
  1250      * no position is available.
  1251      */
  1252     public SourcePosition position() {
  1253         if (tsym.sourcefile == null) return null;
  1254         return SourcePositionImpl.make(tsym.sourcefile.toString(),
  1255                                        (tree==null) ? Position.NOPOS : tree.pos,
  1256                                        lineMap);

mercurial