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

Sat, 01 Dec 2007 00:00:00 +0000

author
duke
date
Sat, 01 Dec 2007 00:00:00 +0000
changeset 1
9a66ca7c79fa
child 113
eff38cc97183
permissions
-rw-r--r--

Initial load

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

mercurial