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