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