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