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

Thu, 24 May 2018 16:48:51 +0800

author
aoqi
date
Thu, 24 May 2018 16:48:51 +0800
changeset 3295
859dc787b52b
parent 2906
d3a51adc115f
parent 2525
2eb010b6cb22
permissions
-rw-r--r--

Merge

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

mercurial