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

Thu, 28 Mar 2013 10:49:39 -0700

author
jjg
date
Thu, 28 Mar 2013 10:49:39 -0700
changeset 1668
991f11e13598
parent 1521
71f35e4b93a5
child 1691
f10cffab99b4
permissions
-rw-r--r--

8006346: doclint should make allowance for headers generated by standard doclet
Reviewed-by: mcimadamore

     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     /**
   112      * Returns the flags in terms of javac's flags
   113      */
   114     protected long getFlags() {
   115         return getFlags(tsym);
   116     }
   118     /**
   119      * Returns the flags of a ClassSymbol in terms of javac's flags
   120      */
   121     static long getFlags(ClassSymbol clazz) {
   122         while (true) {
   123             try {
   124                 return clazz.flags();
   125             } catch (CompletionFailure ex) {
   126                 // quietly ignore completion failures
   127             }
   128         }
   129     }
   131     /**
   132      * Is a ClassSymbol an annotation type?
   133      */
   134     static boolean isAnnotationType(ClassSymbol clazz) {
   135         return (getFlags(clazz) & Flags.ANNOTATION) != 0;
   136     }
   138     /**
   139      * Identify the containing class
   140      */
   141     protected ClassSymbol getContainingClass() {
   142         return tsym.owner.enclClass();
   143     }
   145     /**
   146      * Return true if this is a class, not an interface.
   147      */
   148     @Override
   149     public boolean isClass() {
   150         return !Modifier.isInterface(getModifiers());
   151     }
   153     /**
   154      * Return true if this is a ordinary class,
   155      * not an enumeration, exception, an error, or an interface.
   156      */
   157     @Override
   158     public boolean isOrdinaryClass() {
   159         if (isEnum() || isInterface() || isAnnotationType()) {
   160             return false;
   161         }
   162         for (Type t = type; t.hasTag(CLASS); t = env.types.supertype(t)) {
   163             if (t.tsym == env.syms.errorType.tsym ||
   164                 t.tsym == env.syms.exceptionType.tsym) {
   165                 return false;
   166             }
   167         }
   168         return true;
   169     }
   171     /**
   172      * Return true if this is an enumeration.
   173      * (For legacy doclets, return false.)
   174      */
   175     @Override
   176     public boolean isEnum() {
   177         return (getFlags() & Flags.ENUM) != 0
   178                &&
   179                !env.legacyDoclet;
   180     }
   182     /**
   183      * Return true if this is an interface, but not an annotation type.
   184      * Overridden by AnnotationTypeDocImpl.
   185      */
   186     @Override
   187     public boolean isInterface() {
   188         return Modifier.isInterface(getModifiers());
   189     }
   191     /**
   192      * Return true if this is an exception class
   193      */
   194     @Override
   195     public boolean isException() {
   196         if (isEnum() || isInterface() || isAnnotationType()) {
   197             return false;
   198         }
   199         for (Type t = type; t.hasTag(CLASS); t = env.types.supertype(t)) {
   200             if (t.tsym == env.syms.exceptionType.tsym) {
   201                 return true;
   202             }
   203         }
   204         return false;
   205     }
   207     /**
   208      * Return true if this is an error class
   209      */
   210     @Override
   211     public boolean isError() {
   212         if (isEnum() || isInterface() || isAnnotationType()) {
   213             return false;
   214         }
   215         for (Type t = type; t.hasTag(CLASS); t = env.types.supertype(t)) {
   216             if (t.tsym == env.syms.errorType.tsym) {
   217                 return true;
   218             }
   219         }
   220         return false;
   221     }
   223     /**
   224      * Return true if this is a throwable class
   225      */
   226     public boolean isThrowable() {
   227         if (isEnum() || isInterface() || isAnnotationType()) {
   228             return false;
   229         }
   230         for (Type t = type; t.hasTag(CLASS); t = env.types.supertype(t)) {
   231             if (t.tsym == env.syms.throwableType.tsym) {
   232                 return true;
   233             }
   234         }
   235         return false;
   236     }
   238     /**
   239      * Return true if this class is abstract
   240      */
   241     public boolean isAbstract() {
   242         return Modifier.isAbstract(getModifiers());
   243     }
   245     /**
   246      * Returns true if this class was synthesized by the compiler.
   247      */
   248     public boolean isSynthetic() {
   249         return (getFlags() & Flags.SYNTHETIC) != 0;
   250     }
   252     /**
   253      * Return true if this class is included in the active set.
   254      * A ClassDoc is included iff either it is specified on the
   255      * commandline, or if it's containing package is specified
   256      * on the command line, or if it is a member class of an
   257      * included class.
   258      */
   260     public boolean isIncluded() {
   261         if (isIncluded) {
   262             return true;
   263         }
   264         if (env.shouldDocument(tsym)) {
   265             // Class is nameable from top-level and
   266             // the class and all enclosing classes
   267             // pass the modifier filter.
   268             if (containingPackage().isIncluded()) {
   269                 return isIncluded=true;
   270             }
   271             ClassDoc outer = containingClass();
   272             if (outer != null && outer.isIncluded()) {
   273                 return isIncluded=true;
   274             }
   275         }
   276         return false;
   277     }
   279     public boolean isFunctionalInterface() {
   280         return env.types.isFunctionalInterface(tsym);
   281     }
   283     /**
   284      * Return the package that this class is contained in.
   285      */
   286     @Override
   287     public PackageDoc containingPackage() {
   288         PackageDocImpl p = env.getPackageDoc(tsym.packge());
   289         if (p.setDocPath == false) {
   290             FileObject docPath;
   291             try {
   292                 Location location = env.fileManager.hasLocation(StandardLocation.SOURCE_PATH)
   293                     ? StandardLocation.SOURCE_PATH : StandardLocation.CLASS_PATH;
   295                 docPath = env.fileManager.getFileForInput(
   296                         location, p.qualifiedName(), "package.html");
   297             } catch (IOException e) {
   298                 docPath = null;
   299             }
   301             if (docPath == null) {
   302                 // fall back on older semantics of looking in same directory as
   303                 // source file for this class
   304                 SourcePosition po = position();
   305                 if (env.fileManager instanceof StandardJavaFileManager &&
   306                         po instanceof SourcePositionImpl) {
   307                     URI uri = ((SourcePositionImpl) po).filename.toUri();
   308                     if ("file".equals(uri.getScheme())) {
   309                         File f = new File(uri);
   310                         File dir = f.getParentFile();
   311                         if (dir != null) {
   312                             File pf = new File(dir, "package.html");
   313                             if (pf.exists()) {
   314                                 StandardJavaFileManager sfm = (StandardJavaFileManager) env.fileManager;
   315                                 docPath = sfm.getJavaFileObjects(pf).iterator().next();
   316                             }
   317                         }
   319                     }
   320                 }
   321             }
   323             p.setDocPath(docPath);
   324         }
   325         return p;
   326     }
   328     /**
   329      * Return the class name without package qualifier - but with
   330      * enclosing class qualifier - as a String.
   331      * <pre>
   332      * Examples:
   333      *  for java.util.Hashtable
   334      *  return Hashtable
   335      *  for java.util.Map.Entry
   336      *  return Map.Entry
   337      * </pre>
   338      */
   339     public String name() {
   340         return getClassName(tsym, false);
   341     }
   343     /**
   344      * Return the qualified class name as a String.
   345      * <pre>
   346      * Example:
   347      *  for java.util.Hashtable
   348      *  return java.util.Hashtable
   349      *  if no qualifier, just return flat name
   350      * </pre>
   351      */
   352     public String qualifiedName() {
   353         return getClassName(tsym, true);
   354     }
   356     /**
   357      * Return unqualified name of type excluding any dimension information.
   358      * <p>
   359      * For example, a two dimensional array of String returns 'String'.
   360      */
   361     public String typeName() {
   362         return name();
   363     }
   365     /**
   366      * Return qualified name of type excluding any dimension information.
   367      *<p>
   368      * For example, a two dimensional array of String
   369      * returns 'java.lang.String'.
   370      */
   371     public String qualifiedTypeName() {
   372         return qualifiedName();
   373     }
   375     /**
   376      * Return the simple name of this type.
   377      */
   378     public String simpleTypeName() {
   379         return tsym.name.toString();
   380     }
   382     /**
   383      * Return the qualified name and any type parameters.
   384      * Each parameter is a type variable with optional bounds.
   385      */
   386     @Override
   387     public String toString() {
   388         return classToString(env, tsym, true);
   389     }
   391     /**
   392      * Return the class name as a string.  If "full" is true the name is
   393      * qualified, otherwise it is qualified by its enclosing class(es) only.
   394      */
   395     static String getClassName(ClassSymbol c, boolean full) {
   396         if (full) {
   397             return c.getQualifiedName().toString();
   398         } else {
   399             String n = "";
   400             for ( ; c != null; c = c.owner.enclClass()) {
   401                 n = c.name + (n.equals("") ? "" : ".") + n;
   402             }
   403             return n;
   404         }
   405     }
   407     /**
   408      * Return the class name with any type parameters as a string.
   409      * Each parameter is a type variable with optional bounds.
   410      * If "full" is true all names are qualified, otherwise they are
   411      * qualified by their enclosing class(es) only.
   412      */
   413     static String classToString(DocEnv env, ClassSymbol c, boolean full) {
   414         StringBuilder s = new StringBuilder();
   415         if (!c.isInner()) {             // if c is not an inner class
   416             s.append(getClassName(c, full));
   417         } else {
   418             // c is an inner class, so include type params of outer.
   419             ClassSymbol encl = c.owner.enclClass();
   420             s.append(classToString(env, encl, full))
   421              .append('.')
   422              .append(c.name);
   423         }
   424         s.append(TypeMaker.typeParametersString(env, c, full));
   425         return s.toString();
   426     }
   428     /**
   429      * Is this class (or any enclosing class) generic?  That is, does
   430      * it have type parameters?
   431      */
   432     static boolean isGeneric(ClassSymbol c) {
   433         return c.type.allparams().nonEmpty();
   434     }
   436     /**
   437      * Return the formal type parameters of this class or interface.
   438      * Return an empty array if there are none.
   439      */
   440     public TypeVariable[] typeParameters() {
   441         if (env.legacyDoclet) {
   442             return new TypeVariable[0];
   443         }
   444         TypeVariable res[] = new TypeVariable[type.getTypeArguments().length()];
   445         TypeMaker.getTypes(env, type.getTypeArguments(), res);
   446         return res;
   447     }
   449     /**
   450      * Return the type parameter tags of this class or interface.
   451      */
   452     public ParamTag[] typeParamTags() {
   453         return (env.legacyDoclet)
   454             ? new ParamTag[0]
   455             : comment().typeParamTags();
   456     }
   458     /**
   459      * Return the modifier string for this class. If it's an interface
   460      * exclude 'abstract' keyword from the modifier string
   461      */
   462     @Override
   463     public String modifiers() {
   464         return Modifier.toString(modifierSpecifier());
   465     }
   467     @Override
   468     public int modifierSpecifier() {
   469         int modifiers = getModifiers();
   470         return (isInterface() || isAnnotationType())
   471                 ? modifiers & ~Modifier.ABSTRACT
   472                 : modifiers;
   473     }
   475     /**
   476      * Return the superclass of this class
   477      *
   478      * @return the ClassDocImpl for the superclass of this class, null
   479      * if there is no superclass.
   480      */
   481     public ClassDoc superclass() {
   482         if (isInterface() || isAnnotationType()) return null;
   483         if (tsym == env.syms.objectType.tsym) return null;
   484         ClassSymbol c = (ClassSymbol)env.types.supertype(type).tsym;
   485         if (c == null || c == tsym) c = (ClassSymbol)env.syms.objectType.tsym;
   486         return env.getClassDoc(c);
   487     }
   489     /**
   490      * Return the superclass of this class.  Return null if this is an
   491      * interface.  A superclass is represented by either a
   492      * <code>ClassDoc</code> or a <code>ParameterizedType</code>.
   493      */
   494     public com.sun.javadoc.Type superclassType() {
   495         if (isInterface() || isAnnotationType() ||
   496                 (tsym == env.syms.objectType.tsym))
   497             return null;
   498         Type sup = env.types.supertype(type);
   499         return TypeMaker.getType(env,
   500                                  (sup != type) ? sup : env.syms.objectType);
   501     }
   503     /**
   504      * Test whether this class is a subclass of the specified class.
   505      *
   506      * @param cd the candidate superclass.
   507      * @return true if cd is a superclass of this class.
   508      */
   509     public boolean subclassOf(ClassDoc cd) {
   510         return tsym.isSubClass(((ClassDocImpl)cd).tsym, env.types);
   511     }
   513     /**
   514      * Return interfaces implemented by this class or interfaces
   515      * extended by this interface.
   516      *
   517      * @return An array of ClassDocImpl representing the interfaces.
   518      * Return an empty array if there are no interfaces.
   519      */
   520     public ClassDoc[] interfaces() {
   521         ListBuffer<ClassDocImpl> ta = new ListBuffer<ClassDocImpl>();
   522         for (Type t : env.types.interfaces(type)) {
   523             ta.append(env.getClassDoc((ClassSymbol)t.tsym));
   524         }
   525         //### Cache ta here?
   526         return ta.toArray(new ClassDocImpl[ta.length()]);
   527     }
   529     /**
   530      * Return interfaces implemented by this class or interfaces extended
   531      * by this interface. Includes only directly-declared interfaces, not
   532      * inherited interfaces.
   533      * Return an empty array if there are no interfaces.
   534      */
   535     public com.sun.javadoc.Type[] interfaceTypes() {
   536         //### Cache result here?
   537         return TypeMaker.getTypes(env, env.types.interfaces(type));
   538     }
   540     /**
   541      * Return fields in class.
   542      * @param filter include only the included fields if filter==true
   543      */
   544     public FieldDoc[] fields(boolean filter) {
   545         return fields(filter, false);
   546     }
   548     /**
   549      * Return included fields in class.
   550      */
   551     public FieldDoc[] fields() {
   552         return fields(true, false);
   553     }
   555     /**
   556      * Return the enum constants if this is an enum type.
   557      */
   558     public FieldDoc[] enumConstants() {
   559         return fields(false, true);
   560     }
   562     /**
   563      * Return fields in class.
   564      * @param filter  if true, return only the included fields
   565      * @param enumConstants  if true, return the enum constants instead
   566      */
   567     private FieldDoc[] fields(boolean filter, boolean enumConstants) {
   568         List<FieldDocImpl> fields = List.nil();
   569         for (Scope.Entry e = tsym.members().elems; e != null; e = e.sibling) {
   570             if (e.sym != null && e.sym.kind == VAR) {
   571                 VarSymbol s = (VarSymbol)e.sym;
   572                 boolean isEnum = ((s.flags() & Flags.ENUM) != 0) &&
   573                                  !env.legacyDoclet;
   574                 if (isEnum == enumConstants &&
   575                         (!filter || env.shouldDocument(s))) {
   576                     fields = fields.prepend(env.getFieldDoc(s));
   577                 }
   578             }
   579         }
   580         return fields.toArray(new FieldDocImpl[fields.length()]);
   581     }
   583     /**
   584      * Return methods in class.
   585      * This method is overridden by AnnotationTypeDocImpl.
   586      *
   587      * @param filter include only the included methods if filter==true
   588      * @return an array of MethodDocImpl for representing the visible
   589      * methods in this class.  Does not include constructors.
   590      */
   591     public MethodDoc[] methods(boolean filter) {
   592         Names names = tsym.name.table.names;
   593         List<MethodDocImpl> methods = List.nil();
   594         for (Scope.Entry e = tsym.members().elems; e != null; e = e.sibling) {
   595             if (e.sym != null &&
   596                 e.sym.kind == Kinds.MTH && e.sym.name != names.init) {
   597                 MethodSymbol s = (MethodSymbol)e.sym;
   598                 if (!filter || env.shouldDocument(s)) {
   599                     methods = methods.prepend(env.getMethodDoc(s));
   600                 }
   601             }
   602         }
   603         //### Cache methods here?
   604         return methods.toArray(new MethodDocImpl[methods.length()]);
   605     }
   607     /**
   608      * Return included methods in class.
   609      *
   610      * @return an array of MethodDocImpl for representing the visible
   611      * methods in this class.  Does not include constructors.
   612      */
   613     public MethodDoc[] methods() {
   614         return methods(true);
   615     }
   617     /**
   618      * Return constructors in class.
   619      *
   620      * @param filter include only the included constructors if filter==true
   621      * @return an array of ConstructorDocImpl for representing the visible
   622      * constructors in this class.
   623      */
   624     public ConstructorDoc[] constructors(boolean filter) {
   625         Names names = tsym.name.table.names;
   626         List<ConstructorDocImpl> constructors = List.nil();
   627         for (Scope.Entry e = tsym.members().elems; e != null; e = e.sibling) {
   628             if (e.sym != null &&
   629                 e.sym.kind == Kinds.MTH && e.sym.name == names.init) {
   630                 MethodSymbol s = (MethodSymbol)e.sym;
   631                 if (!filter || env.shouldDocument(s)) {
   632                     constructors = constructors.prepend(env.getConstructorDoc(s));
   633                 }
   634             }
   635         }
   636         //### Cache constructors here?
   637         return constructors.toArray(new ConstructorDocImpl[constructors.length()]);
   638     }
   640     /**
   641      * Return included constructors in class.
   642      *
   643      * @return an array of ConstructorDocImpl for representing the visible
   644      * constructors in this class.
   645      */
   646     public ConstructorDoc[] constructors() {
   647         return constructors(true);
   648     }
   650     /**
   651      * Adds all inner classes of this class, and their
   652      * inner classes recursively, to the list l.
   653      */
   654     void addAllClasses(ListBuffer<ClassDocImpl> l, boolean filtered) {
   655         try {
   656             if (isSynthetic()) return;
   657             // sometimes synthetic classes are not marked synthetic
   658             if (!JavadocTool.isValidClassName(tsym.name.toString())) return;
   659             if (filtered && !env.shouldDocument(tsym)) return;
   660             if (l.contains(this)) return;
   661             l.append(this);
   662             List<ClassDocImpl> more = List.nil();
   663             for (Scope.Entry e = tsym.members().elems; e != null;
   664                  e = e.sibling) {
   665                 if (e.sym != null && e.sym.kind == Kinds.TYP) {
   666                     ClassSymbol s = (ClassSymbol)e.sym;
   667                     ClassDocImpl c = env.getClassDoc(s);
   668                     if (c.isSynthetic()) continue;
   669                     if (c != null) more = more.prepend(c);
   670                 }
   671             }
   672             // this extra step preserves the ordering from oldjavadoc
   673             for (; more.nonEmpty(); more=more.tail) {
   674                 more.head.addAllClasses(l, filtered);
   675             }
   676         } catch (CompletionFailure e) {
   677             // quietly ignore completion failures
   678         }
   679     }
   681     /**
   682      * Return inner classes within this class.
   683      *
   684      * @param filter include only the included inner classes if filter==true.
   685      * @return an array of ClassDocImpl for representing the visible
   686      * classes defined in this class. Anonymous and local classes
   687      * are not included.
   688      */
   689     public ClassDoc[] innerClasses(boolean filter) {
   690         ListBuffer<ClassDocImpl> innerClasses = new ListBuffer<ClassDocImpl>();
   691         for (Scope.Entry e = tsym.members().elems; e != null; e = e.sibling) {
   692             if (e.sym != null && e.sym.kind == Kinds.TYP) {
   693                 ClassSymbol s = (ClassSymbol)e.sym;
   694                 if ((s.flags_field & Flags.SYNTHETIC) != 0) continue;
   695                 if (!filter || env.isVisible(s)) {
   696                     innerClasses.prepend(env.getClassDoc(s));
   697                 }
   698             }
   699         }
   700         //### Cache classes here?
   701         return innerClasses.toArray(new ClassDocImpl[innerClasses.length()]);
   702     }
   704     /**
   705      * Return included inner classes within this class.
   706      *
   707      * @return an array of ClassDocImpl for representing the visible
   708      * classes defined in this class. Anonymous and local classes
   709      * are not included.
   710      */
   711     public ClassDoc[] innerClasses() {
   712         return innerClasses(true);
   713     }
   715     /**
   716      * Find a class within the context of this class.
   717      * Search order: qualified name, in this class (inner),
   718      * in this package, in the class imports, in the package
   719      * imports.
   720      * Return the ClassDocImpl if found, null if not found.
   721      */
   722     //### The specified search order is not the normal rule the
   723     //### compiler would use.  Leave as specified or change it?
   724     public ClassDoc findClass(String className) {
   725         ClassDoc searchResult = searchClass(className);
   726         if (searchResult == null) {
   727             ClassDocImpl enclosingClass = (ClassDocImpl)containingClass();
   728             //Expand search space to include enclosing class.
   729             while (enclosingClass != null && enclosingClass.containingClass() != null) {
   730                 enclosingClass = (ClassDocImpl)enclosingClass.containingClass();
   731             }
   732             searchResult = enclosingClass == null ?
   733                 null : enclosingClass.searchClass(className);
   734         }
   735         return searchResult;
   736     }
   738     private ClassDoc searchClass(String className) {
   739         Names names = tsym.name.table.names;
   741         // search by qualified name first
   742         ClassDoc cd = env.lookupClass(className);
   743         if (cd != null) {
   744             return cd;
   745         }
   747         // search inner classes
   748         //### Add private entry point to avoid creating array?
   749         //### Replicate code in innerClasses here to avoid consing?
   750         for (ClassDoc icd : innerClasses()) {
   751             if (icd.name().equals(className) ||
   752                     //### This is from original javadoc but it looks suspicious to me...
   753                     //### I believe it is attempting to compensate for the confused
   754                     //### convention of including the nested class qualifiers in the
   755                     //### 'name' of the inner class, rather than the true simple name.
   756                     icd.name().endsWith("." + className)) {
   757                 return icd;
   758             } else {
   759                 ClassDoc innercd = ((ClassDocImpl) icd).searchClass(className);
   760                 if (innercd != null) {
   761                     return innercd;
   762                 }
   763             }
   764         }
   766         // check in this package
   767         cd = containingPackage().findClass(className);
   768         if (cd != null) {
   769             return cd;
   770         }
   772         // make sure that this symbol has been completed
   773         if (tsym.completer != null) {
   774             tsym.complete();
   775         }
   777         // search imports
   779         if (tsym.sourcefile != null) {
   781             //### This information is available only for source classes.
   783             Env<AttrContext> compenv = env.enter.getEnv(tsym);
   784             if (compenv == null) return null;
   786             Scope s = compenv.toplevel.namedImportScope;
   787             for (Scope.Entry e = s.lookup(names.fromString(className)); e.scope != null; e = e.next()) {
   788                 if (e.sym.kind == Kinds.TYP) {
   789                     ClassDoc c = env.getClassDoc((ClassSymbol)e.sym);
   790                     return c;
   791                 }
   792             }
   794             s = compenv.toplevel.starImportScope;
   795             for (Scope.Entry e = s.lookup(names.fromString(className)); e.scope != null; e = e.next()) {
   796                 if (e.sym.kind == Kinds.TYP) {
   797                     ClassDoc c = env.getClassDoc((ClassSymbol)e.sym);
   798                     return c;
   799                 }
   800             }
   801         }
   803         return null; // not found
   804     }
   807     private boolean hasParameterTypes(MethodSymbol method, String[] argTypes) {
   809         if (argTypes == null) {
   810             // wildcard
   811             return true;
   812         }
   814         int i = 0;
   815         List<Type> types = method.type.getParameterTypes();
   817         if (argTypes.length != types.length()) {
   818             return false;
   819         }
   821         for (Type t : types) {
   822             String argType = argTypes[i++];
   823             // For vararg method, "T..." matches type T[].
   824             if (i == argTypes.length) {
   825                 argType = argType.replace("...", "[]");
   826             }
   827             if (!hasTypeName(env.types.erasure(t), argType)) {  //###(gj)
   828                 return false;
   829             }
   830         }
   831         return true;
   832     }
   833     // where
   834     private boolean hasTypeName(Type t, String name) {
   835         return
   836             name.equals(TypeMaker.getTypeName(t, true))
   837             ||
   838             name.equals(TypeMaker.getTypeName(t, false))
   839             ||
   840             (qualifiedName() + "." + name).equals(TypeMaker.getTypeName(t, true));
   841     }
   845     /**
   846      * Find a method in this class scope.
   847      * Search order: this class, interfaces, superclasses, outerclasses.
   848      * Note that this is not necessarily what the compiler would do!
   849      *
   850      * @param methodName the unqualified name to search for.
   851      * @param paramTypes the array of Strings for method parameter types.
   852      * @return the first MethodDocImpl which matches, null if not found.
   853      */
   854     public MethodDocImpl findMethod(String methodName, String[] paramTypes) {
   855         // Use hash table 'searched' to avoid searching same class twice.
   856         //### It is not clear how this could happen.
   857         return searchMethod(methodName, paramTypes, new HashSet<ClassDocImpl>());
   858     }
   860     private MethodDocImpl searchMethod(String methodName,
   861                                        String[] paramTypes, Set<ClassDocImpl> searched) {
   862         //### Note that this search is not necessarily what the compiler would do!
   864         Names names = tsym.name.table.names;
   865         // do not match constructors
   866         if (names.init.contentEquals(methodName)) {
   867             return null;
   868         }
   870         ClassDocImpl cdi;
   871         MethodDocImpl mdi;
   873         if (searched.contains(this)) {
   874             return null;
   875         }
   876         searched.add(this);
   878         //DEBUG
   879         /*---------------------------------*
   880          System.out.print("searching " + this + " for " + methodName);
   881          if (paramTypes == null) {
   882          System.out.println("()");
   883          } else {
   884          System.out.print("(");
   885          for (int k=0; k < paramTypes.length; k++) {
   886          System.out.print(paramTypes[k]);
   887          if ((k + 1) < paramTypes.length) {
   888          System.out.print(", ");
   889          }
   890          }
   891          System.out.println(")");
   892          }
   893          *---------------------------------*/
   895         // search current class
   896         Scope.Entry e = tsym.members().lookup(names.fromString(methodName));
   898         //### Using modifier filter here isn't really correct,
   899         //### but emulates the old behavior.  Instead, we should
   900         //### apply the normal rules of visibility and inheritance.
   902         if (paramTypes == null) {
   903             // If no parameters specified, we are allowed to return
   904             // any method with a matching name.  In practice, the old
   905             // code returned the first method, which is now the last!
   906             // In order to provide textually identical results, we
   907             // attempt to emulate the old behavior.
   908             MethodSymbol lastFound = null;
   909             for (; e.scope != null; e = e.next()) {
   910                 if (e.sym.kind == Kinds.MTH) {
   911                     //### Should intern methodName as Name.
   912                     if (e.sym.name.toString().equals(methodName)) {
   913                         lastFound = (MethodSymbol)e.sym;
   914                     }
   915                 }
   916             }
   917             if (lastFound != null) {
   918                 return env.getMethodDoc(lastFound);
   919             }
   920         } else {
   921             for (; e.scope != null; e = e.next()) {
   922                 if (e.sym != null &&
   923                     e.sym.kind == Kinds.MTH) {
   924                     //### Should intern methodName as Name.
   925                     if (hasParameterTypes((MethodSymbol)e.sym, paramTypes)) {
   926                         return env.getMethodDoc((MethodSymbol)e.sym);
   927                     }
   928                 }
   929             }
   930         }
   932         //### If we found a MethodDoc above, but which did not pass
   933         //### the modifier filter, we should return failure here!
   935         // search superclass
   936         cdi = (ClassDocImpl)superclass();
   937         if (cdi != null) {
   938             mdi = cdi.searchMethod(methodName, paramTypes, searched);
   939             if (mdi != null) {
   940                 return mdi;
   941             }
   942         }
   944         // search interfaces
   945         ClassDoc intf[] = interfaces();
   946         for (int i = 0; i < intf.length; i++) {
   947             cdi = (ClassDocImpl)intf[i];
   948             mdi = cdi.searchMethod(methodName, paramTypes, searched);
   949             if (mdi != null) {
   950                 return mdi;
   951             }
   952         }
   954         // search enclosing class
   955         cdi = (ClassDocImpl)containingClass();
   956         if (cdi != null) {
   957             mdi = cdi.searchMethod(methodName, paramTypes, searched);
   958             if (mdi != null) {
   959                 return mdi;
   960             }
   961         }
   963         //###(gj) As a temporary measure until type variables are better
   964         //### handled, try again without the parameter types.
   965         //### This should most often find the right method, and occassionally
   966         //### find the wrong one.
   967         //if (paramTypes != null) {
   968         //    return findMethod(methodName, null);
   969         //}
   971         return null;
   972     }
   974     /**
   975      * Find constructor in this class.
   976      *
   977      * @param constrName the unqualified name to search for.
   978      * @param paramTypes the array of Strings for constructor parameters.
   979      * @return the first ConstructorDocImpl which matches, null if not found.
   980      */
   981     public ConstructorDoc findConstructor(String constrName,
   982                                           String[] paramTypes) {
   983         Names names = tsym.name.table.names;
   984         for (Scope.Entry e = tsym.members().lookup(names.fromString("<init>")); e.scope != null; e = e.next()) {
   985             if (e.sym.kind == Kinds.MTH) {
   986                 if (hasParameterTypes((MethodSymbol)e.sym, paramTypes)) {
   987                     return env.getConstructorDoc((MethodSymbol)e.sym);
   988                 }
   989             }
   990         }
   992         //###(gj) As a temporary measure until type variables are better
   993         //### handled, try again without the parameter types.
   994         //### This will often find the right constructor, and occassionally
   995         //### find the wrong one.
   996         //if (paramTypes != null) {
   997         //    return findConstructor(constrName, null);
   998         //}
  1000         return null;
  1003     /**
  1004      * Find a field in this class scope.
  1005      * Search order: this class, outerclasses, interfaces,
  1006      * superclasses. IMP: If see tag is defined in an inner class,
  1007      * which extends a super class and if outerclass and the super
  1008      * class have a visible field in common then Java compiler cribs
  1009      * about the ambiguity, but the following code will search in the
  1010      * above given search order.
  1012      * @param fieldName the unqualified name to search for.
  1013      * @return the first FieldDocImpl which matches, null if not found.
  1014      */
  1015     public FieldDoc findField(String fieldName) {
  1016         return searchField(fieldName, new HashSet<ClassDocImpl>());
  1019     private FieldDocImpl searchField(String fieldName, Set<ClassDocImpl> searched) {
  1020         Names names = tsym.name.table.names;
  1021         if (searched.contains(this)) {
  1022             return null;
  1024         searched.add(this);
  1026         for (Scope.Entry e = tsym.members().lookup(names.fromString(fieldName)); e.scope != null; e = e.next()) {
  1027             if (e.sym.kind == Kinds.VAR) {
  1028                 //### Should intern fieldName as Name.
  1029                 return env.getFieldDoc((VarSymbol)e.sym);
  1033         //### If we found a FieldDoc above, but which did not pass
  1034         //### the modifier filter, we should return failure here!
  1036         ClassDocImpl cdi = (ClassDocImpl)containingClass();
  1037         if (cdi != null) {
  1038             FieldDocImpl fdi = cdi.searchField(fieldName, searched);
  1039             if (fdi != null) {
  1040                 return fdi;
  1044         // search superclass
  1045         cdi = (ClassDocImpl)superclass();
  1046         if (cdi != null) {
  1047             FieldDocImpl fdi = cdi.searchField(fieldName, searched);
  1048             if (fdi != null) {
  1049                 return fdi;
  1053         // search interfaces
  1054         ClassDoc intf[] = interfaces();
  1055         for (int i = 0; i < intf.length; i++) {
  1056             cdi = (ClassDocImpl)intf[i];
  1057             FieldDocImpl fdi = cdi.searchField(fieldName, searched);
  1058             if (fdi != null) {
  1059                 return fdi;
  1063         return null;
  1066     /**
  1067      * Get the list of classes declared as imported.
  1068      * These are called "single-type-import declarations" in the JLS.
  1069      * This method is deprecated in the ClassDoc interface.
  1071      * @return an array of ClassDocImpl representing the imported classes.
  1073      * @deprecated  Import declarations are implementation details that
  1074      *          should not be exposed here.  In addition, not all imported
  1075      *          classes are imported through single-type-import declarations.
  1076      */
  1077     @Deprecated
  1078     public ClassDoc[] importedClasses() {
  1079         // information is not available for binary classfiles
  1080         if (tsym.sourcefile == null) return new ClassDoc[0];
  1082         ListBuffer<ClassDocImpl> importedClasses = new ListBuffer<ClassDocImpl>();
  1084         Env<AttrContext> compenv = env.enter.getEnv(tsym);
  1085         if (compenv == null) return new ClassDocImpl[0];
  1087         Name asterisk = tsym.name.table.names.asterisk;
  1088         for (JCTree t : compenv.toplevel.defs) {
  1089             if (t.hasTag(IMPORT)) {
  1090                 JCTree imp = ((JCImport) t).qualid;
  1091                 if ((TreeInfo.name(imp) != asterisk) &&
  1092                         (imp.type.tsym.kind & Kinds.TYP) != 0) {
  1093                     importedClasses.append(
  1094                             env.getClassDoc((ClassSymbol)imp.type.tsym));
  1099         return importedClasses.toArray(new ClassDocImpl[importedClasses.length()]);
  1102     /**
  1103      * Get the list of packages declared as imported.
  1104      * These are called "type-import-on-demand declarations" in the JLS.
  1105      * This method is deprecated in the ClassDoc interface.
  1107      * @return an array of PackageDocImpl representing the imported packages.
  1109      * ###NOTE: the syntax supports importing all inner classes from a class as well.
  1110      * @deprecated  Import declarations are implementation details that
  1111      *          should not be exposed here.  In addition, this method's
  1112      *          return type does not allow for all type-import-on-demand
  1113      *          declarations to be returned.
  1114      */
  1115     @Deprecated
  1116     public PackageDoc[] importedPackages() {
  1117         // information is not available for binary classfiles
  1118         if (tsym.sourcefile == null) return new PackageDoc[0];
  1120         ListBuffer<PackageDocImpl> importedPackages = new ListBuffer<PackageDocImpl>();
  1122         //### Add the implicit "import java.lang.*" to the result
  1123         Names names = tsym.name.table.names;
  1124         importedPackages.append(env.getPackageDoc(env.reader.enterPackage(names.java_lang)));
  1126         Env<AttrContext> compenv = env.enter.getEnv(tsym);
  1127         if (compenv == null) return new PackageDocImpl[0];
  1129         for (JCTree t : compenv.toplevel.defs) {
  1130             if (t.hasTag(IMPORT)) {
  1131                 JCTree imp = ((JCImport) t).qualid;
  1132                 if (TreeInfo.name(imp) == names.asterisk) {
  1133                     JCFieldAccess sel = (JCFieldAccess)imp;
  1134                     Symbol s = sel.selected.type.tsym;
  1135                     PackageDocImpl pdoc = env.getPackageDoc(s.packge());
  1136                     if (!importedPackages.contains(pdoc))
  1137                         importedPackages.append(pdoc);
  1142         return importedPackages.toArray(new PackageDocImpl[importedPackages.length()]);
  1145     /**
  1146      * Return the type's dimension information.
  1147      * Always return "", as this is not an array type.
  1148      */
  1149     public String dimension() {
  1150         return "";
  1153     /**
  1154      * Return this type as a class, which it already is.
  1155      */
  1156     public ClassDoc asClassDoc() {
  1157         return this;
  1160     /**
  1161      * Return null (unless overridden), as this is not an annotation type.
  1162      */
  1163     public AnnotationTypeDoc asAnnotationTypeDoc() {
  1164         return null;
  1167     /**
  1168      * Return null, as this is not a class instantiation.
  1169      */
  1170     public ParameterizedType asParameterizedType() {
  1171         return null;
  1174     /**
  1175      * Return null, as this is not a type variable.
  1176      */
  1177     public TypeVariable asTypeVariable() {
  1178         return null;
  1181     /**
  1182      * Return null, as this is not a wildcard type.
  1183      */
  1184     public WildcardType asWildcardType() {
  1185         return null;
  1188     /**
  1189      * Returns null, as this is not an annotated type.
  1190      */
  1191     public AnnotatedType asAnnotatedType() {
  1192         return null;
  1195     /**
  1196      * Return false, as this is not a primitive type.
  1197      */
  1198     public boolean isPrimitive() {
  1199         return false;
  1202     //--- Serialization ---
  1204     //### These methods ignore modifier filter.
  1206     /**
  1207      * Return true if this class implements <code>java.io.Serializable</code>.
  1209      * Since <code>java.io.Externalizable</code> extends
  1210      * <code>java.io.Serializable</code>,
  1211      * Externalizable objects are also Serializable.
  1212      */
  1213     public boolean isSerializable() {
  1214         try {
  1215             return env.types.isSubtype(type, env.syms.serializableType);
  1216         } catch (CompletionFailure ex) {
  1217             // quietly ignore completion failures
  1218             return false;
  1222     /**
  1223      * Return true if this class implements
  1224      * <code>java.io.Externalizable</code>.
  1225      */
  1226     public boolean isExternalizable() {
  1227         try {
  1228             return env.types.isSubtype(type, env.externalizableSym.type);
  1229         } catch (CompletionFailure ex) {
  1230             // quietly ignore completion failures
  1231             return false;
  1235     /**
  1236      * Return the serialization methods for this class.
  1238      * @return an array of <code>MethodDocImpl</code> that represents
  1239      * the serialization methods for this class.
  1240      */
  1241     public MethodDoc[] serializationMethods() {
  1242         if (serializedForm == null) {
  1243             serializedForm = new SerializedForm(env, tsym, this);
  1245         //### Clone this?
  1246         return serializedForm.methods();
  1249     /**
  1250      * Return the Serializable fields of class.<p>
  1252      * Return either a list of default fields documented by
  1253      * <code>serial</code> tag<br>
  1254      * or return a single <code>FieldDoc</code> for
  1255      * <code>serialPersistentField</code> member.
  1256      * There should be a <code>serialField</code> tag for
  1257      * each Serializable field defined by an <code>ObjectStreamField</code>
  1258      * array component of <code>serialPersistentField</code>.
  1260      * @returns an array of <code>FieldDoc</code> for the Serializable fields
  1261      * of this class.
  1263      * @see #definesSerializableFields()
  1264      * @see SerialFieldTagImpl
  1265      */
  1266     public FieldDoc[] serializableFields() {
  1267         if (serializedForm == null) {
  1268             serializedForm = new SerializedForm(env, tsym, this);
  1270         //### Clone this?
  1271         return serializedForm.fields();
  1274     /**
  1275      * Return true if Serializable fields are explicitly defined with
  1276      * the special class member <code>serialPersistentFields</code>.
  1278      * @see #serializableFields()
  1279      * @see SerialFieldTagImpl
  1280      */
  1281     public boolean definesSerializableFields() {
  1282         if (!isSerializable() || isExternalizable()) {
  1283             return false;
  1284         } else {
  1285             if (serializedForm == null) {
  1286                 serializedForm = new SerializedForm(env, tsym, this);
  1288             //### Clone this?
  1289             return serializedForm.definesSerializableFields();
  1293     /**
  1294      * Determine if a class is a RuntimeException.
  1295      * <p>
  1296      * Used only by ThrowsTagImpl.
  1297      */
  1298     boolean isRuntimeException() {
  1299         return tsym.isSubClass(env.syms.runtimeExceptionType.tsym, env.types);
  1302     /**
  1303      * Return the source position of the entity, or null if
  1304      * no position is available.
  1305      */
  1306     @Override
  1307     public SourcePosition position() {
  1308         if (tsym.sourcefile == null) return null;
  1309         return SourcePositionImpl.make(tsym.sourcefile,
  1310                                        (tree==null) ? Position.NOPOS : tree.pos,
  1311                                        lineMap);

mercurial