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