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

Sat, 13 Apr 2013 18:48:29 -0700

author
bpatel
date
Sat, 13 Apr 2013 18:48:29 -0700
changeset 1691
f10cffab99b4
parent 1521
71f35e4b93a5
child 1706
95d29b99e5b3
permissions
-rw-r--r--

8009686: Generated javadoc documentation should be able to display type annotation on an array
Reviewed-by: jjg

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

mercurial