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

Thu, 30 Jun 2011 14:33:45 -0700

author
ksrini
date
Thu, 30 Jun 2011 14:33:45 -0700
changeset 1051
b0909f992710
parent 910
ebf7c13df6c0
child 1065
e9f118c2bd3c
permissions
-rw-r--r--

7059905: (javadoc) promote method visibility for netbeans usage
Reviewed-by: jjg, bpatel

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

mercurial