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

Tue, 28 Dec 2010 15:54:52 -0800

author
ohair
date
Tue, 28 Dec 2010 15:54:52 -0800
changeset 798
4868a36f6fd8
parent 721
5286a99de2e6
child 910
ebf7c13df6c0
permissions
-rw-r--r--

6962318: Update copyright year
Reviewed-by: xdono

     1 /*
     2  * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.  Oracle designates this
     8  * particular file as subject to the "Classpath" exception as provided
     9  * by Oracle in the LICENSE file that accompanied this code.
    10  *
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    14  * version 2 for more details (a copy is included in the LICENSE file that
    15  * accompanied this code).
    16  *
    17  * You should have received a copy of the GNU General Public License version
    18  * 2 along with this work; if not, write to the Free Software Foundation,
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    20  *
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    22  * or visit www.oracle.com if you need additional information or have any
    23  * questions.
    24  */
    26 package com.sun.tools.javadoc;
    28 import java.io.File;
    29 import java.io.IOException;
    30 import java.lang.reflect.Modifier;
    31 import java.net.URI;
    32 import java.util.HashSet;
    33 import java.util.Set;
    34 import javax.tools.FileObject;
    35 import javax.tools.JavaFileManager.Location;
    36 import javax.tools.StandardJavaFileManager;
    37 import javax.tools.StandardLocation;
    39 import com.sun.javadoc.*;
    41 import static com.sun.javadoc.LanguageVersion.*;
    43 import com.sun.tools.javac.code.Flags;
    44 import com.sun.tools.javac.code.Kinds;
    45 import com.sun.tools.javac.code.Scope;
    46 import com.sun.tools.javac.code.Symbol;
    47 import com.sun.tools.javac.code.Symbol.*;
    48 import com.sun.tools.javac.code.Type;
    49 import com.sun.tools.javac.code.Type.ClassType;
    50 import com.sun.tools.javac.code.TypeTags;
    52 import com.sun.tools.javac.comp.AttrContext;
    53 import com.sun.tools.javac.comp.Env;
    55 import com.sun.tools.javac.tree.JCTree;
    56 import com.sun.tools.javac.tree.JCTree.JCClassDecl;
    57 import com.sun.tools.javac.tree.JCTree.JCFieldAccess;
    58 import com.sun.tools.javac.tree.JCTree.JCImport;
    59 import com.sun.tools.javac.tree.TreeInfo;
    61 import com.sun.tools.javac.util.List;
    62 import com.sun.tools.javac.util.ListBuffer;
    63 import com.sun.tools.javac.util.Name;
    64 import com.sun.tools.javac.util.Names;
    65 import com.sun.tools.javac.util.Position;
    67 import static com.sun.tools.javac.code.Flags.*;
    68 import static com.sun.tools.javac.code.Kinds.*;
    70 /**
    71  * Represents a java class and provides access to information
    72  * about the class, the class' comment and tags, and the
    73  * members of the class.  A ClassDocImpl only exists if it was
    74  * processed in this run of javadoc.  References to classes
    75  * which may or may not have been processed in this run are
    76  * referred to using Type (which can be converted to ClassDocImpl,
    77  * if possible).
    78  *
    79  * @see Type
    80  *
    81  * @since 1.2
    82  * @author Robert Field
    83  * @author Neal Gafter (rewrite)
    84  * @author Scott Seligman (generics, enums, annotations)
    85  */
    87 public class ClassDocImpl extends ProgramElementDocImpl implements ClassDoc {
    89     public final ClassType type;        // protected->public for debugging
    90     protected final ClassSymbol tsym;
    92     boolean isIncluded = false;         // Set in RootDocImpl
    94     private SerializedForm serializedForm;
    96     /**
    97      * Constructor
    98      */
    99     public ClassDocImpl(DocEnv env, ClassSymbol sym) {
   100         this(env, sym, null, null, null);
   101     }
   103     /**
   104      * Constructor
   105      */
   106     public ClassDocImpl(DocEnv env, ClassSymbol sym, String documentation,
   107                         JCClassDecl tree, Position.LineMap lineMap) {
   108         super(env, sym, documentation, tree, lineMap);
   109         this.type = (ClassType)sym.type;
   110         this.tsym = sym;
   111     }
   113     /**
   114      * Returns the flags in terms of javac's flags
   115      */
   116     protected long getFlags() {
   117         return getFlags(tsym);
   118     }
   120     /**
   121      * Returns the flags of a ClassSymbol in terms of javac's flags
   122      */
   123     static long getFlags(ClassSymbol clazz) {
   124         while (true) {
   125             try {
   126                 return clazz.flags();
   127             } catch (CompletionFailure ex) {
   128                 // quietly ignore completion failures
   129             }
   130         }
   131     }
   133     /**
   134      * Is a ClassSymbol an annotation type?
   135      */
   136     static boolean isAnnotationType(ClassSymbol clazz) {
   137         return (getFlags(clazz) & Flags.ANNOTATION) != 0;
   138     }
   140     /**
   141      * Identify the containing class
   142      */
   143     protected ClassSymbol getContainingClass() {
   144         return tsym.owner.enclClass();
   145     }
   147     /**
   148      * Return true if this is a class, not an interface.
   149      */
   150     public boolean isClass() {
   151         return !Modifier.isInterface(getModifiers());
   152     }
   154     /**
   155      * Return true if this is a ordinary class,
   156      * not an enumeration, exception, an error, or an interface.
   157      */
   158     public boolean isOrdinaryClass() {
   159         if (isEnum() || isInterface() || isAnnotationType()) {
   160             return false;
   161         }
   162         for (Type t = type; t.tag == TypeTags.CLASS; t = env.types.supertype(t)) {
   163             if (t.tsym == env.syms.errorType.tsym ||
   164                 t.tsym == env.syms.exceptionType.tsym) {
   165                 return false;
   166             }
   167         }
   168         return true;
   169     }
   171     /**
   172      * Return true if this is an enumeration.
   173      * (For legacy doclets, return false.)
   174      */
   175     public boolean isEnum() {
   176         return (getFlags() & Flags.ENUM) != 0
   177                &&
   178                !env.legacyDoclet;
   179     }
   181     /**
   182      * Return true if this is an interface, but not an annotation type.
   183      * Overridden by AnnotationTypeDocImpl.
   184      */
   185     public boolean isInterface() {
   186         return Modifier.isInterface(getModifiers());
   187     }
   189     /**
   190      * Return true if this is an exception class
   191      */
   192     public boolean isException() {
   193         if (isEnum() || isInterface() || isAnnotationType()) {
   194             return false;
   195         }
   196         for (Type t = type; t.tag == TypeTags.CLASS; t = env.types.supertype(t)) {
   197             if (t.tsym == env.syms.exceptionType.tsym) {
   198                 return true;
   199             }
   200         }
   201         return false;
   202     }
   204     /**
   205      * Return true if this is an error class
   206      */
   207     public boolean isError() {
   208         if (isEnum() || isInterface() || isAnnotationType()) {
   209             return false;
   210         }
   211         for (Type t = type; t.tag == TypeTags.CLASS; t = env.types.supertype(t)) {
   212             if (t.tsym == env.syms.errorType.tsym) {
   213                 return true;
   214             }
   215         }
   216         return false;
   217     }
   219     /**
   220      * Return true if this is a throwable class
   221      */
   222     public boolean isThrowable() {
   223         if (isEnum() || isInterface() || isAnnotationType()) {
   224             return false;
   225         }
   226         for (Type t = type; t.tag == TypeTags.CLASS; t = env.types.supertype(t)) {
   227             if (t.tsym == env.syms.throwableType.tsym) {
   228                 return true;
   229             }
   230         }
   231         return false;
   232     }
   234     /**
   235      * Return true if this class is abstract
   236      */
   237     public boolean isAbstract() {
   238         return Modifier.isAbstract(getModifiers());
   239     }
   241     /**
   242      * Returns true if this class was synthesized by the compiler.
   243      */
   244     public boolean isSynthetic() {
   245         return (getFlags() & Flags.SYNTHETIC) != 0;
   246     }
   248     /**
   249      * Return true if this class is included in the active set.
   250      * A ClassDoc is included iff either it is specified on the
   251      * commandline, or if it's containing package is specified
   252      * on the command line, or if it is a member class of an
   253      * included class.
   254      */
   256     public boolean isIncluded() {
   257         if (isIncluded) {
   258             return true;
   259         }
   260         if (env.shouldDocument(tsym)) {
   261             // Class is nameable from top-level and
   262             // the class and all enclosing classes
   263             // pass the modifier filter.
   264             if (containingPackage().isIncluded()) {
   265                 return isIncluded=true;
   266             }
   267             ClassDoc outer = containingClass();
   268             if (outer != null && outer.isIncluded()) {
   269                 return isIncluded=true;
   270             }
   271         }
   272         return false;
   273     }
   275     /**
   276      * Return the package that this class is contained in.
   277      */
   278     public PackageDoc containingPackage() {
   279         PackageDocImpl p = env.getPackageDoc(tsym.packge());
   280         if (p.setDocPath == false) {
   281             FileObject docPath;
   282             try {
   283                 Location location = env.fileManager.hasLocation(StandardLocation.SOURCE_PATH)
   284                     ? StandardLocation.SOURCE_PATH : StandardLocation.CLASS_PATH;
   286                 docPath = env.fileManager.getFileForInput(
   287                         location, p.qualifiedName(), "package.html");
   288             } catch (IOException e) {
   289                 docPath = null;
   290             }
   292             if (docPath == null) {
   293                 // fall back on older semantics of looking in same directory as
   294                 // source file for this class
   295                 SourcePosition po = position();
   296                 if (env.fileManager instanceof StandardJavaFileManager &&
   297                         po instanceof SourcePositionImpl) {
   298                     URI uri = ((SourcePositionImpl) po).filename.toUri();
   299                     if ("file".equals(uri.getScheme())) {
   300                         File f = new File(uri);
   301                         File dir = f.getParentFile();
   302                         if (dir != null) {
   303                             File pf = new File(dir, "package.html");
   304                             if (pf.exists()) {
   305                                 StandardJavaFileManager sfm = (StandardJavaFileManager) env.fileManager;
   306                                 docPath = sfm.getJavaFileObjects(pf).iterator().next();
   307                             }
   308                         }
   310                     }
   311                 }
   312             }
   314             p.setDocPath(docPath);
   315         }
   316         return p;
   317     }
   319     /**
   320      * Return the class name without package qualifier - but with
   321      * enclosing class qualifier - as a String.
   322      * <pre>
   323      * Examples:
   324      *  for java.util.Hashtable
   325      *  return Hashtable
   326      *  for java.util.Map.Entry
   327      *  return Map.Entry
   328      * </pre>
   329      */
   330     public String name() {
   331         return getClassName(tsym, false);
   332     }
   334     /**
   335      * Return the qualified class name as a String.
   336      * <pre>
   337      * Example:
   338      *  for java.util.Hashtable
   339      *  return java.util.Hashtable
   340      *  if no qualifier, just return flat name
   341      * </pre>
   342      */
   343     public String qualifiedName() {
   344         return getClassName(tsym, true);
   345     }
   347     /**
   348      * Return unqualified name of type excluding any dimension information.
   349      * <p>
   350      * For example, a two dimensional array of String returns 'String'.
   351      */
   352     public String typeName() {
   353         return name();
   354     }
   356     /**
   357      * Return qualified name of type excluding any dimension information.
   358      *<p>
   359      * For example, a two dimensional array of String
   360      * returns 'java.lang.String'.
   361      */
   362     public String qualifiedTypeName() {
   363         return qualifiedName();
   364     }
   366     /**
   367      * Return the simple name of this type.
   368      */
   369     public String simpleTypeName() {
   370         return tsym.name.toString();
   371     }
   373     /**
   374      * Return the qualified name and any type parameters.
   375      * Each parameter is a type variable with optional bounds.
   376      */
   377     public String toString() {
   378         return classToString(env, tsym, true);
   379     }
   381     /**
   382      * Return the class name as a string.  If "full" is true the name is
   383      * qualified, otherwise it is qualified by its enclosing class(es) only.
   384      */
   385     static String getClassName(ClassSymbol c, boolean full) {
   386         if (full) {
   387             return c.getQualifiedName().toString();
   388         } else {
   389             String n = "";
   390             for ( ; c != null; c = c.owner.enclClass()) {
   391                 n = c.name + (n.equals("") ? "" : ".") + n;
   392             }
   393             return n;
   394         }
   395     }
   397     /**
   398      * Return the class name with any type parameters as a string.
   399      * Each parameter is a type variable with optional bounds.
   400      * If "full" is true all names are qualified, otherwise they are
   401      * qualified by their enclosing class(es) only.
   402      */
   403     static String classToString(DocEnv env, ClassSymbol c, boolean full) {
   404         StringBuffer s = new StringBuffer();
   405         if (!c.isInner()) {             // if c is not an inner class
   406             s.append(getClassName(c, full));
   407         } else {
   408             // c is an inner class, so include type params of outer.
   409             ClassSymbol encl = c.owner.enclClass();
   410             s.append(classToString(env, encl, full))
   411              .append('.')
   412              .append(c.name);
   413         }
   414         s.append(TypeMaker.typeParametersString(env, c, full));
   415         return s.toString();
   416     }
   418     /**
   419      * Is this class (or any enclosing class) generic?  That is, does
   420      * it have type parameters?
   421      */
   422     static boolean isGeneric(ClassSymbol c) {
   423         return c.type.allparams().nonEmpty();
   424     }
   426     /**
   427      * Return the formal type parameters of this class or interface.
   428      * Return an empty array if there are none.
   429      */
   430     public TypeVariable[] typeParameters() {
   431         if (env.legacyDoclet) {
   432             return new TypeVariable[0];
   433         }
   434         TypeVariable res[] = new TypeVariable[type.getTypeArguments().length()];
   435         TypeMaker.getTypes(env, type.getTypeArguments(), res);
   436         return res;
   437     }
   439     /**
   440      * Return the type parameter tags of this class or interface.
   441      */
   442     public ParamTag[] typeParamTags() {
   443         return (env.legacyDoclet)
   444             ? new ParamTag[0]
   445             : comment().typeParamTags();
   446     }
   448     /**
   449      * Return the modifier string for this class. If it's an interface
   450      * exclude 'abstract' keyword from the modifier string
   451      */
   452     public String modifiers() {
   453         return Modifier.toString(modifierSpecifier());
   454     }
   456     public int modifierSpecifier() {
   457         int modifiers = getModifiers();
   458         return (isInterface() || isAnnotationType())
   459                 ? modifiers & ~Modifier.ABSTRACT
   460                 : modifiers;
   461     }
   463     /**
   464      * Return the superclass of this class
   465      *
   466      * @return the ClassDocImpl for the superclass of this class, null
   467      * if there is no superclass.
   468      */
   469     public ClassDoc superclass() {
   470         if (isInterface() || isAnnotationType()) return null;
   471         if (tsym == env.syms.objectType.tsym) return null;
   472         ClassSymbol c = (ClassSymbol)env.types.supertype(type).tsym;
   473         if (c == null || c == tsym) c = (ClassSymbol)env.syms.objectType.tsym;
   474         return env.getClassDoc(c);
   475     }
   477     /**
   478      * Return the superclass of this class.  Return null if this is an
   479      * interface.  A superclass is represented by either a
   480      * <code>ClassDoc</code> or a <code>ParameterizedType</code>.
   481      */
   482     public com.sun.javadoc.Type superclassType() {
   483         if (isInterface() || isAnnotationType() ||
   484                 (tsym == env.syms.objectType.tsym))
   485             return null;
   486         Type sup = env.types.supertype(type);
   487         return TypeMaker.getType(env,
   488                                  (sup != type) ? sup : env.syms.objectType);
   489     }
   491     /**
   492      * Test whether this class is a subclass of the specified class.
   493      *
   494      * @param cd the candidate superclass.
   495      * @return true if cd is a superclass of this class.
   496      */
   497     public boolean subclassOf(ClassDoc cd) {
   498         return tsym.isSubClass(((ClassDocImpl)cd).tsym, env.types);
   499     }
   501     /**
   502      * Return interfaces implemented by this class or interfaces
   503      * extended by this interface.
   504      *
   505      * @return An array of ClassDocImpl representing the interfaces.
   506      * Return an empty array if there are no interfaces.
   507      */
   508     public ClassDoc[] interfaces() {
   509         ListBuffer<ClassDocImpl> ta = new ListBuffer<ClassDocImpl>();
   510         for (Type t : env.types.interfaces(type)) {
   511             ta.append(env.getClassDoc((ClassSymbol)t.tsym));
   512         }
   513         //### Cache ta here?
   514         return ta.toArray(new ClassDocImpl[ta.length()]);
   515     }
   517     /**
   518      * Return interfaces implemented by this class or interfaces extended
   519      * by this interface. Includes only directly-declared interfaces, not
   520      * inherited interfaces.
   521      * Return an empty array if there are no interfaces.
   522      */
   523     public com.sun.javadoc.Type[] interfaceTypes() {
   524         //### Cache result here?
   525         return TypeMaker.getTypes(env, env.types.interfaces(type));
   526     }
   528     /**
   529      * Return fields in class.
   530      * @param filter include only the included fields if filter==true
   531      */
   532     public FieldDoc[] fields(boolean filter) {
   533         return fields(filter, false);
   534     }
   536     /**
   537      * Return included fields in class.
   538      */
   539     public FieldDoc[] fields() {
   540         return fields(true, false);
   541     }
   543     /**
   544      * Return the enum constants if this is an enum type.
   545      */
   546     public FieldDoc[] enumConstants() {
   547         return fields(false, true);
   548     }
   550     /**
   551      * Return fields in class.
   552      * @param filter  if true, return only the included fields
   553      * @param enumConstants  if true, return the enum constants instead
   554      */
   555     private FieldDoc[] fields(boolean filter, boolean enumConstants) {
   556         List<FieldDocImpl> fields = List.nil();
   557         for (Scope.Entry e = tsym.members().elems; e != null; e = e.sibling) {
   558             if (e.sym != null && e.sym.kind == VAR) {
   559                 VarSymbol s = (VarSymbol)e.sym;
   560                 boolean isEnum = ((s.flags() & Flags.ENUM) != 0) &&
   561                                  !env.legacyDoclet;
   562                 if (isEnum == enumConstants &&
   563                         (!filter || env.shouldDocument(s))) {
   564                     fields = fields.prepend(env.getFieldDoc(s));
   565                 }
   566             }
   567         }
   568         return fields.toArray(new FieldDocImpl[fields.length()]);
   569     }
   571     /**
   572      * Return methods in class.
   573      * This method is overridden by AnnotationTypeDocImpl.
   574      *
   575      * @param filter include only the included methods if filter==true
   576      * @return an array of MethodDocImpl for representing the visible
   577      * methods in this class.  Does not include constructors.
   578      */
   579     public MethodDoc[] methods(boolean filter) {
   580         Names names = tsym.name.table.names;
   581         List<MethodDocImpl> methods = List.nil();
   582         for (Scope.Entry e = tsym.members().elems; e != null; e = e.sibling) {
   583             if (e.sym != null &&
   584                 e.sym.kind == Kinds.MTH && e.sym.name != names.init) {
   585                 MethodSymbol s = (MethodSymbol)e.sym;
   586                 if (!filter || env.shouldDocument(s)) {
   587                     methods = methods.prepend(env.getMethodDoc(s));
   588                 }
   589             }
   590         }
   591         //### Cache methods here?
   592         return methods.toArray(new MethodDocImpl[methods.length()]);
   593     }
   595     /**
   596      * Return included methods in class.
   597      *
   598      * @return an array of MethodDocImpl for representing the visible
   599      * methods in this class.  Does not include constructors.
   600      */
   601     public MethodDoc[] methods() {
   602         return methods(true);
   603     }
   605     /**
   606      * Return constructors in class.
   607      *
   608      * @param filter include only the included constructors if filter==true
   609      * @return an array of ConstructorDocImpl for representing the visible
   610      * constructors in this class.
   611      */
   612     public ConstructorDoc[] constructors(boolean filter) {
   613         Names names = tsym.name.table.names;
   614         List<ConstructorDocImpl> constructors = List.nil();
   615         for (Scope.Entry e = tsym.members().elems; e != null; e = e.sibling) {
   616             if (e.sym != null &&
   617                 e.sym.kind == Kinds.MTH && e.sym.name == names.init) {
   618                 MethodSymbol s = (MethodSymbol)e.sym;
   619                 if (!filter || env.shouldDocument(s)) {
   620                     constructors = constructors.prepend(env.getConstructorDoc(s));
   621                 }
   622             }
   623         }
   624         //### Cache constructors here?
   625         return constructors.toArray(new ConstructorDocImpl[constructors.length()]);
   626     }
   628     /**
   629      * Return included constructors in class.
   630      *
   631      * @return an array of ConstructorDocImpl for representing the visible
   632      * constructors in this class.
   633      */
   634     public ConstructorDoc[] constructors() {
   635         return constructors(true);
   636     }
   638     /**
   639      * Adds all inner classes of this class, and their
   640      * inner classes recursively, to the list l.
   641      */
   642     void addAllClasses(ListBuffer<ClassDocImpl> l, boolean filtered) {
   643         try {
   644             if (isSynthetic()) return;
   645             // sometimes synthetic classes are not marked synthetic
   646             if (!JavadocTool.isValidClassName(tsym.name.toString())) return;
   647             if (filtered && !env.shouldDocument(tsym)) return;
   648             if (l.contains(this)) return;
   649             l.append(this);
   650             List<ClassDocImpl> more = List.nil();
   651             for (Scope.Entry e = tsym.members().elems; e != null;
   652                  e = e.sibling) {
   653                 if (e.sym != null && e.sym.kind == Kinds.TYP) {
   654                     ClassSymbol s = (ClassSymbol)e.sym;
   655                     ClassDocImpl c = env.getClassDoc(s);
   656                     if (c.isSynthetic()) continue;
   657                     if (c != null) more = more.prepend(c);
   658                 }
   659             }
   660             // this extra step preserves the ordering from oldjavadoc
   661             for (; more.nonEmpty(); more=more.tail) {
   662                 more.head.addAllClasses(l, filtered);
   663             }
   664         } catch (CompletionFailure e) {
   665             // quietly ignore completion failures
   666         }
   667     }
   669     /**
   670      * Return inner classes within this class.
   671      *
   672      * @param filter include only the included inner classes if filter==true.
   673      * @return an array of ClassDocImpl for representing the visible
   674      * classes defined in this class. Anonymous and local classes
   675      * are not included.
   676      */
   677     public ClassDoc[] innerClasses(boolean filter) {
   678         ListBuffer<ClassDocImpl> innerClasses = new ListBuffer<ClassDocImpl>();
   679         for (Scope.Entry e = tsym.members().elems; e != null; e = e.sibling) {
   680             if (e.sym != null && e.sym.kind == Kinds.TYP) {
   681                 ClassSymbol s = (ClassSymbol)e.sym;
   682                 if ((s.flags_field & Flags.SYNTHETIC) != 0) continue;
   683                 if (!filter || env.isVisible(s)) {
   684                     innerClasses.prepend(env.getClassDoc(s));
   685                 }
   686             }
   687         }
   688         //### Cache classes here?
   689         return innerClasses.toArray(new ClassDocImpl[innerClasses.length()]);
   690     }
   692     /**
   693      * Return included inner classes within this class.
   694      *
   695      * @return an array of ClassDocImpl for representing the visible
   696      * classes defined in this class. Anonymous and local classes
   697      * are not included.
   698      */
   699     public ClassDoc[] innerClasses() {
   700         return innerClasses(true);
   701     }
   703     /**
   704      * Find a class within the context of this class.
   705      * Search order: qualified name, in this class (inner),
   706      * in this package, in the class imports, in the package
   707      * imports.
   708      * Return the ClassDocImpl if found, null if not found.
   709      */
   710     //### The specified search order is not the normal rule the
   711     //### compiler would use.  Leave as specified or change it?
   712     public ClassDoc findClass(String className) {
   713         ClassDoc searchResult = searchClass(className);
   714         if (searchResult == null) {
   715             ClassDocImpl enclosingClass = (ClassDocImpl)containingClass();
   716             //Expand search space to include enclosing class.
   717             while (enclosingClass != null && enclosingClass.containingClass() != null) {
   718                 enclosingClass = (ClassDocImpl)enclosingClass.containingClass();
   719             }
   720             searchResult = enclosingClass == null ?
   721                 null : enclosingClass.searchClass(className);
   722         }
   723         return searchResult;
   724     }
   726     private ClassDoc searchClass(String className) {
   727         Names names = tsym.name.table.names;
   729         // search by qualified name first
   730         ClassDoc cd = env.lookupClass(className);
   731         if (cd != null) {
   732             return cd;
   733         }
   735         // search inner classes
   736         //### Add private entry point to avoid creating array?
   737         //### Replicate code in innerClasses here to avoid consing?
   738         ClassDoc innerClasses[] = innerClasses();
   739         for (int i = 0; i < innerClasses.length; i++) {
   740             if (innerClasses[i].name().equals(className) ||
   741                 //### This is from original javadoc but it looks suspicious to me...
   742                 //### I believe it is attempting to compensate for the confused
   743                 //### convention of including the nested class qualifiers in the
   744                 //### 'name' of the inner class, rather than the true simple name.
   745                 innerClasses[i].name().endsWith(className)) {
   746                 return innerClasses[i];
   747             } else {
   748                 ClassDoc innercd = ((ClassDocImpl) innerClasses[i]).searchClass(className);
   749                 if (innercd != null) {
   750                     return innercd;
   751                 }
   752             }
   753         }
   755         // check in this package
   756         cd = containingPackage().findClass(className);
   757         if (cd != null) {
   758             return cd;
   759         }
   761         // make sure that this symbol has been completed
   762         if (tsym.completer != null) {
   763             tsym.complete();
   764         }
   766         // search imports
   768         if (tsym.sourcefile != null) {
   770             //### This information is available only for source classes.
   772             Env<AttrContext> compenv = env.enter.getEnv(tsym);
   773             if (compenv == null) return null;
   775             Scope s = compenv.toplevel.namedImportScope;
   776             for (Scope.Entry e = s.lookup(names.fromString(className)); e.scope != null; e = e.next()) {
   777                 if (e.sym.kind == Kinds.TYP) {
   778                     ClassDoc c = env.getClassDoc((ClassSymbol)e.sym);
   779                     return c;
   780                 }
   781             }
   783             s = compenv.toplevel.starImportScope;
   784             for (Scope.Entry e = s.lookup(names.fromString(className)); e.scope != null; e = e.next()) {
   785                 if (e.sym.kind == Kinds.TYP) {
   786                     ClassDoc c = env.getClassDoc((ClassSymbol)e.sym);
   787                     return c;
   788                 }
   789             }
   790         }
   792         return null; // not found
   793     }
   796     private boolean hasParameterTypes(MethodSymbol method, String[] argTypes) {
   798         if (argTypes == null) {
   799             // wildcard
   800             return true;
   801         }
   803         int i = 0;
   804         List<Type> types = method.type.getParameterTypes();
   806         if (argTypes.length != types.length()) {
   807             return false;
   808         }
   810         for (Type t : types) {
   811             String argType = argTypes[i++];
   812             // For vararg method, "T..." matches type T[].
   813             if (i == argTypes.length) {
   814                 argType = argType.replace("...", "[]");
   815             }
   816             if (!hasTypeName(env.types.erasure(t), argType)) {  //###(gj)
   817                 return false;
   818             }
   819         }
   820         return true;
   821     }
   822     // where
   823     private boolean hasTypeName(Type t, String name) {
   824         return
   825             name.equals(TypeMaker.getTypeName(t, true))
   826             ||
   827             name.equals(TypeMaker.getTypeName(t, false))
   828             ||
   829             (qualifiedName() + "." + name).equals(TypeMaker.getTypeName(t, true));
   830     }
   834     /**
   835      * Find a method in this class scope.
   836      * Search order: this class, interfaces, superclasses, outerclasses.
   837      * Note that this is not necessarily what the compiler would do!
   838      *
   839      * @param methodName the unqualified name to search for.
   840      * @param paramTypeArray the array of Strings for method parameter types.
   841      * @return the first MethodDocImpl which matches, null if not found.
   842      */
   843     public MethodDocImpl findMethod(String methodName, String[] paramTypes) {
   844         // Use hash table 'searched' to avoid searching same class twice.
   845         //### It is not clear how this could happen.
   846         return searchMethod(methodName, paramTypes, new HashSet<ClassDocImpl>());
   847     }
   849     private MethodDocImpl searchMethod(String methodName,
   850                                        String[] paramTypes, Set<ClassDocImpl> searched) {
   851         //### Note that this search is not necessarily what the compiler would do!
   853         Names names = tsym.name.table.names;
   854         // do not match constructors
   855         if (names.init.contentEquals(methodName)) {
   856             return null;
   857         }
   859         ClassDocImpl cdi;
   860         MethodDocImpl mdi;
   862         if (searched.contains(this)) {
   863             return null;
   864         }
   865         searched.add(this);
   867         //DEBUG
   868         /*---------------------------------*
   869          System.out.print("searching " + this + " for " + methodName);
   870          if (paramTypes == null) {
   871          System.out.println("()");
   872          } else {
   873          System.out.print("(");
   874          for (int k=0; k < paramTypes.length; k++) {
   875          System.out.print(paramTypes[k]);
   876          if ((k + 1) < paramTypes.length) {
   877          System.out.print(", ");
   878          }
   879          }
   880          System.out.println(")");
   881          }
   882          *---------------------------------*/
   884         // search current class
   885         Scope.Entry e = tsym.members().lookup(names.fromString(methodName));
   887         //### Using modifier filter here isn't really correct,
   888         //### but emulates the old behavior.  Instead, we should
   889         //### apply the normal rules of visibility and inheritance.
   891         if (paramTypes == null) {
   892             // If no parameters specified, we are allowed to return
   893             // any method with a matching name.  In practice, the old
   894             // code returned the first method, which is now the last!
   895             // In order to provide textually identical results, we
   896             // attempt to emulate the old behavior.
   897             MethodSymbol lastFound = null;
   898             for (; e.scope != null; e = e.next()) {
   899                 if (e.sym.kind == Kinds.MTH) {
   900                     //### Should intern methodName as Name.
   901                     if (e.sym.name.toString().equals(methodName)) {
   902                         lastFound = (MethodSymbol)e.sym;
   903                     }
   904                 }
   905             }
   906             if (lastFound != null) {
   907                 return env.getMethodDoc(lastFound);
   908             }
   909         } else {
   910             for (; e.scope != null; e = e.next()) {
   911                 if (e.sym != null &&
   912                     e.sym.kind == Kinds.MTH) {
   913                     //### Should intern methodName as Name.
   914                     if (hasParameterTypes((MethodSymbol)e.sym, paramTypes)) {
   915                         return env.getMethodDoc((MethodSymbol)e.sym);
   916                     }
   917                 }
   918             }
   919         }
   921         //### If we found a MethodDoc above, but which did not pass
   922         //### the modifier filter, we should return failure here!
   924         // search superclass
   925         cdi = (ClassDocImpl)superclass();
   926         if (cdi != null) {
   927             mdi = cdi.searchMethod(methodName, paramTypes, searched);
   928             if (mdi != null) {
   929                 return mdi;
   930             }
   931         }
   933         // search interfaces
   934         ClassDoc intf[] = interfaces();
   935         for (int i = 0; i < intf.length; i++) {
   936             cdi = (ClassDocImpl)intf[i];
   937             mdi = cdi.searchMethod(methodName, paramTypes, searched);
   938             if (mdi != null) {
   939                 return mdi;
   940             }
   941         }
   943         // search enclosing class
   944         cdi = (ClassDocImpl)containingClass();
   945         if (cdi != null) {
   946             mdi = cdi.searchMethod(methodName, paramTypes, searched);
   947             if (mdi != null) {
   948                 return mdi;
   949             }
   950         }
   952         //###(gj) As a temporary measure until type variables are better
   953         //### handled, try again without the parameter types.
   954         //### This should most often find the right method, and occassionally
   955         //### find the wrong one.
   956         //if (paramTypes != null) {
   957         //    return findMethod(methodName, null);
   958         //}
   960         return null;
   961     }
   963     /**
   964      * Find constructor in this class.
   965      *
   966      * @param constrName the unqualified name to search for.
   967      * @param paramTypeArray the array of Strings for constructor parameters.
   968      * @return the first ConstructorDocImpl which matches, null if not found.
   969      */
   970     public ConstructorDoc findConstructor(String constrName,
   971                                           String[] paramTypes) {
   972         Names names = tsym.name.table.names;
   973         for (Scope.Entry e = tsym.members().lookup(names.fromString("<init>")); e.scope != null; e = e.next()) {
   974             if (e.sym.kind == Kinds.MTH) {
   975                 if (hasParameterTypes((MethodSymbol)e.sym, paramTypes)) {
   976                     return env.getConstructorDoc((MethodSymbol)e.sym);
   977                 }
   978             }
   979         }
   981         //###(gj) As a temporary measure until type variables are better
   982         //### handled, try again without the parameter types.
   983         //### This will often find the right constructor, and occassionally
   984         //### find the wrong one.
   985         //if (paramTypes != null) {
   986         //    return findConstructor(constrName, null);
   987         //}
   989         return null;
   990     }
   992     /**
   993      * Find a field in this class scope.
   994      * Search order: this class, outerclasses, interfaces,
   995      * superclasses. IMP: If see tag is defined in an inner class,
   996      * which extends a super class and if outerclass and the super
   997      * class have a visible field in common then Java compiler cribs
   998      * about the ambiguity, but the following code will search in the
   999      * above given search order.
  1001      * @param fieldName the unqualified name to search for.
  1002      * @return the first FieldDocImpl which matches, null if not found.
  1003      */
  1004     public FieldDoc findField(String fieldName) {
  1005         return searchField(fieldName, new HashSet<ClassDocImpl>());
  1008     private FieldDocImpl searchField(String fieldName, Set<ClassDocImpl> searched) {
  1009         Names names = tsym.name.table.names;
  1010         if (searched.contains(this)) {
  1011             return null;
  1013         searched.add(this);
  1015         for (Scope.Entry e = tsym.members().lookup(names.fromString(fieldName)); e.scope != null; e = e.next()) {
  1016             if (e.sym.kind == Kinds.VAR) {
  1017                 //### Should intern fieldName as Name.
  1018                 return env.getFieldDoc((VarSymbol)e.sym);
  1022         //### If we found a FieldDoc above, but which did not pass
  1023         //### the modifier filter, we should return failure here!
  1025         ClassDocImpl cdi = (ClassDocImpl)containingClass();
  1026         if (cdi != null) {
  1027             FieldDocImpl fdi = cdi.searchField(fieldName, searched);
  1028             if (fdi != null) {
  1029                 return fdi;
  1033         // search superclass
  1034         cdi = (ClassDocImpl)superclass();
  1035         if (cdi != null) {
  1036             FieldDocImpl fdi = cdi.searchField(fieldName, searched);
  1037             if (fdi != null) {
  1038                 return fdi;
  1042         // search interfaces
  1043         ClassDoc intf[] = interfaces();
  1044         for (int i = 0; i < intf.length; i++) {
  1045             cdi = (ClassDocImpl)intf[i];
  1046             FieldDocImpl fdi = cdi.searchField(fieldName, searched);
  1047             if (fdi != null) {
  1048                 return fdi;
  1052         return null;
  1055     /**
  1056      * Get the list of classes declared as imported.
  1057      * These are called "single-type-import declarations" in the JLS.
  1058      * This method is deprecated in the ClassDoc interface.
  1060      * @return an array of ClassDocImpl representing the imported classes.
  1062      * @deprecated  Import declarations are implementation details that
  1063      *          should not be exposed here.  In addition, not all imported
  1064      *          classes are imported through single-type-import declarations.
  1065      */
  1066     @Deprecated
  1067     public ClassDoc[] importedClasses() {
  1068         // information is not available for binary classfiles
  1069         if (tsym.sourcefile == null) return new ClassDoc[0];
  1071         ListBuffer<ClassDocImpl> importedClasses = new ListBuffer<ClassDocImpl>();
  1073         Env<AttrContext> compenv = env.enter.getEnv(tsym);
  1074         if (compenv == null) return new ClassDocImpl[0];
  1076         Name asterisk = tsym.name.table.names.asterisk;
  1077         for (JCTree t : compenv.toplevel.defs) {
  1078             if (t.getTag() == JCTree.IMPORT) {
  1079                 JCTree imp = ((JCImport) t).qualid;
  1080                 if ((TreeInfo.name(imp) != asterisk) &&
  1081                         (imp.type.tsym.kind & Kinds.TYP) != 0) {
  1082                     importedClasses.append(
  1083                             env.getClassDoc((ClassSymbol)imp.type.tsym));
  1088         return importedClasses.toArray(new ClassDocImpl[importedClasses.length()]);
  1091     /**
  1092      * Get the list of packages declared as imported.
  1093      * These are called "type-import-on-demand declarations" in the JLS.
  1094      * This method is deprecated in the ClassDoc interface.
  1096      * @return an array of PackageDocImpl representing the imported packages.
  1098      * ###NOTE: the syntax supports importing all inner classes from a class as well.
  1099      * @deprecated  Import declarations are implementation details that
  1100      *          should not be exposed here.  In addition, this method's
  1101      *          return type does not allow for all type-import-on-demand
  1102      *          declarations to be returned.
  1103      */
  1104     @Deprecated
  1105     public PackageDoc[] importedPackages() {
  1106         // information is not available for binary classfiles
  1107         if (tsym.sourcefile == null) return new PackageDoc[0];
  1109         ListBuffer<PackageDocImpl> importedPackages = new ListBuffer<PackageDocImpl>();
  1111         //### Add the implicit "import java.lang.*" to the result
  1112         Names names = tsym.name.table.names;
  1113         importedPackages.append(env.getPackageDoc(env.reader.enterPackage(names.java_lang)));
  1115         Env<AttrContext> compenv = env.enter.getEnv(tsym);
  1116         if (compenv == null) return new PackageDocImpl[0];
  1118         for (JCTree t : compenv.toplevel.defs) {
  1119             if (t.getTag() == JCTree.IMPORT) {
  1120                 JCTree imp = ((JCImport) t).qualid;
  1121                 if (TreeInfo.name(imp) == names.asterisk) {
  1122                     JCFieldAccess sel = (JCFieldAccess)imp;
  1123                     Symbol s = sel.selected.type.tsym;
  1124                     PackageDocImpl pdoc = env.getPackageDoc(s.packge());
  1125                     if (!importedPackages.contains(pdoc))
  1126                         importedPackages.append(pdoc);
  1131         return importedPackages.toArray(new PackageDocImpl[importedPackages.length()]);
  1134     /**
  1135      * Return the type's dimension information.
  1136      * Always return "", as this is not an array type.
  1137      */
  1138     public String dimension() {
  1139         return "";
  1142     /**
  1143      * Return this type as a class, which it already is.
  1144      */
  1145     public ClassDoc asClassDoc() {
  1146         return this;
  1149     /**
  1150      * Return null (unless overridden), as this is not an annotation type.
  1151      */
  1152     public AnnotationTypeDoc asAnnotationTypeDoc() {
  1153         return null;
  1156     /**
  1157      * Return null, as this is not a class instantiation.
  1158      */
  1159     public ParameterizedType asParameterizedType() {
  1160         return null;
  1163     /**
  1164      * Return null, as this is not a type variable.
  1165      */
  1166     public TypeVariable asTypeVariable() {
  1167         return null;
  1170     /**
  1171      * Return null, as this is not a wildcard type.
  1172      */
  1173     public WildcardType asWildcardType() {
  1174         return null;
  1177     /**
  1178      * Return false, as this is not a primitive type.
  1179      */
  1180     public boolean isPrimitive() {
  1181         return false;
  1184     //--- Serialization ---
  1186     //### These methods ignore modifier filter.
  1188     /**
  1189      * Return true if this class implements <code>java.io.Serializable</code>.
  1191      * Since <code>java.io.Externalizable</code> extends
  1192      * <code>java.io.Serializable</code>,
  1193      * Externalizable objects are also Serializable.
  1194      */
  1195     public boolean isSerializable() {
  1196         try {
  1197             return env.types.isSubtype(type, env.syms.serializableType);
  1198         } catch (CompletionFailure ex) {
  1199             // quietly ignore completion failures
  1200             return false;
  1204     /**
  1205      * Return true if this class implements
  1206      * <code>java.io.Externalizable</code>.
  1207      */
  1208     public boolean isExternalizable() {
  1209         try {
  1210             return env.types.isSubtype(type, env.externalizableSym.type);
  1211         } catch (CompletionFailure ex) {
  1212             // quietly ignore completion failures
  1213             return false;
  1217     /**
  1218      * Return the serialization methods for this class.
  1220      * @return an array of <code>MethodDocImpl</code> that represents
  1221      * the serialization methods for this class.
  1222      */
  1223     public MethodDoc[] serializationMethods() {
  1224         if (serializedForm == null) {
  1225             serializedForm = new SerializedForm(env, tsym, this);
  1227         //### Clone this?
  1228         return serializedForm.methods();
  1231     /**
  1232      * Return the Serializable fields of class.<p>
  1234      * Return either a list of default fields documented by
  1235      * <code>serial</code> tag<br>
  1236      * or return a single <code>FieldDoc</code> for
  1237      * <code>serialPersistentField</code> member.
  1238      * There should be a <code>serialField</code> tag for
  1239      * each Serializable field defined by an <code>ObjectStreamField</code>
  1240      * array component of <code>serialPersistentField</code>.
  1242      * @returns an array of <code>FieldDoc</code> for the Serializable fields
  1243      * of this class.
  1245      * @see #definesSerializableFields()
  1246      * @see SerialFieldTagImpl
  1247      */
  1248     public FieldDoc[] serializableFields() {
  1249         if (serializedForm == null) {
  1250             serializedForm = new SerializedForm(env, tsym, this);
  1252         //### Clone this?
  1253         return serializedForm.fields();
  1256     /**
  1257      * Return true if Serializable fields are explicitly defined with
  1258      * the special class member <code>serialPersistentFields</code>.
  1260      * @see #serializableFields()
  1261      * @see SerialFieldTagImpl
  1262      */
  1263     public boolean definesSerializableFields() {
  1264         if (!isSerializable() || isExternalizable()) {
  1265             return false;
  1266         } else {
  1267             if (serializedForm == null) {
  1268                 serializedForm = new SerializedForm(env, tsym, this);
  1270             //### Clone this?
  1271             return serializedForm.definesSerializableFields();
  1275     /**
  1276      * Determine if a class is a RuntimeException.
  1277      * <p>
  1278      * Used only by ThrowsTagImpl.
  1279      */
  1280     boolean isRuntimeException() {
  1281         return tsym.isSubClass(env.syms.runtimeExceptionType.tsym, env.types);
  1284     /**
  1285      * Return the source position of the entity, or null if
  1286      * no position is available.
  1287      */
  1288     public SourcePosition position() {
  1289         if (tsym.sourcefile == null) return null;
  1290         return SourcePositionImpl.make(tsym.sourcefile,
  1291                                        (tree==null) ? Position.NOPOS : tree.pos,
  1292                                        lineMap);

mercurial