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