Thu, 28 Mar 2013 10:49:39 -0700
8006346: doclint should make allowance for headers generated by standard doclet
Reviewed-by: mcimadamore
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 */
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;
35 import javax.tools.FileObject;
36 import javax.tools.JavaFileManager.Location;
37 import javax.tools.StandardJavaFileManager;
38 import javax.tools.StandardLocation;
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.comp.AttrContext;
50 import com.sun.tools.javac.comp.Env;
51 import com.sun.tools.javac.tree.JCTree;
52 import com.sun.tools.javac.tree.JCTree.JCFieldAccess;
53 import com.sun.tools.javac.tree.JCTree.JCImport;
54 import com.sun.tools.javac.tree.TreeInfo;
55 import com.sun.tools.javac.util.List;
56 import com.sun.tools.javac.util.ListBuffer;
57 import com.sun.tools.javac.util.Name;
58 import com.sun.tools.javac.util.Names;
59 import com.sun.tools.javac.util.Position;
60 import static com.sun.tools.javac.code.Kinds.*;
61 import static com.sun.tools.javac.code.TypeTag.CLASS;
62 import static com.sun.tools.javac.tree.JCTree.Tag.*;
64 /**
65 * Represents a java class and provides access to information
66 * about the class, the class' comment and tags, and the
67 * members of the class. A ClassDocImpl only exists if it was
68 * processed in this run of javadoc. References to classes
69 * which may or may not have been processed in this run are
70 * referred to using Type (which can be converted to ClassDocImpl,
71 * if possible).
72 *
73 * <p><b>This is NOT part of any supported API.
74 * If you write code that depends on this, you do so at your own risk.
75 * This code and its internal interfaces are subject to change or
76 * deletion without notice.</b>
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);
100 }
102 /**
103 * Constructor
104 */
105 public ClassDocImpl(DocEnv env, ClassSymbol sym, TreePath treePath) {
106 super(env, sym, treePath);
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.hasTag(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.hasTag(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.hasTag(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.hasTag(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 public boolean isFunctionalInterface() {
280 return env.types.isFunctionalInterface(tsym);
281 }
283 /**
284 * Return the package that this class is contained in.
285 */
286 @Override
287 public PackageDoc containingPackage() {
288 PackageDocImpl p = env.getPackageDoc(tsym.packge());
289 if (p.setDocPath == false) {
290 FileObject docPath;
291 try {
292 Location location = env.fileManager.hasLocation(StandardLocation.SOURCE_PATH)
293 ? StandardLocation.SOURCE_PATH : StandardLocation.CLASS_PATH;
295 docPath = env.fileManager.getFileForInput(
296 location, p.qualifiedName(), "package.html");
297 } catch (IOException e) {
298 docPath = null;
299 }
301 if (docPath == null) {
302 // fall back on older semantics of looking in same directory as
303 // source file for this class
304 SourcePosition po = position();
305 if (env.fileManager instanceof StandardJavaFileManager &&
306 po instanceof SourcePositionImpl) {
307 URI uri = ((SourcePositionImpl) po).filename.toUri();
308 if ("file".equals(uri.getScheme())) {
309 File f = new File(uri);
310 File dir = f.getParentFile();
311 if (dir != null) {
312 File pf = new File(dir, "package.html");
313 if (pf.exists()) {
314 StandardJavaFileManager sfm = (StandardJavaFileManager) env.fileManager;
315 docPath = sfm.getJavaFileObjects(pf).iterator().next();
316 }
317 }
319 }
320 }
321 }
323 p.setDocPath(docPath);
324 }
325 return p;
326 }
328 /**
329 * Return the class name without package qualifier - but with
330 * enclosing class qualifier - as a String.
331 * <pre>
332 * Examples:
333 * for java.util.Hashtable
334 * return Hashtable
335 * for java.util.Map.Entry
336 * return Map.Entry
337 * </pre>
338 */
339 public String name() {
340 return getClassName(tsym, false);
341 }
343 /**
344 * Return the qualified class name as a String.
345 * <pre>
346 * Example:
347 * for java.util.Hashtable
348 * return java.util.Hashtable
349 * if no qualifier, just return flat name
350 * </pre>
351 */
352 public String qualifiedName() {
353 return getClassName(tsym, true);
354 }
356 /**
357 * Return unqualified name of type excluding any dimension information.
358 * <p>
359 * For example, a two dimensional array of String returns 'String'.
360 */
361 public String typeName() {
362 return name();
363 }
365 /**
366 * Return qualified name of type excluding any dimension information.
367 *<p>
368 * For example, a two dimensional array of String
369 * returns 'java.lang.String'.
370 */
371 public String qualifiedTypeName() {
372 return qualifiedName();
373 }
375 /**
376 * Return the simple name of this type.
377 */
378 public String simpleTypeName() {
379 return tsym.name.toString();
380 }
382 /**
383 * Return the qualified name and any type parameters.
384 * Each parameter is a type variable with optional bounds.
385 */
386 @Override
387 public String toString() {
388 return classToString(env, tsym, true);
389 }
391 /**
392 * Return the class name as a string. If "full" is true the name is
393 * qualified, otherwise it is qualified by its enclosing class(es) only.
394 */
395 static String getClassName(ClassSymbol c, boolean full) {
396 if (full) {
397 return c.getQualifiedName().toString();
398 } else {
399 String n = "";
400 for ( ; c != null; c = c.owner.enclClass()) {
401 n = c.name + (n.equals("") ? "" : ".") + n;
402 }
403 return n;
404 }
405 }
407 /**
408 * Return the class name with any type parameters as a string.
409 * Each parameter is a type variable with optional bounds.
410 * If "full" is true all names are qualified, otherwise they are
411 * qualified by their enclosing class(es) only.
412 */
413 static String classToString(DocEnv env, ClassSymbol c, boolean full) {
414 StringBuilder s = new StringBuilder();
415 if (!c.isInner()) { // if c is not an inner class
416 s.append(getClassName(c, full));
417 } else {
418 // c is an inner class, so include type params of outer.
419 ClassSymbol encl = c.owner.enclClass();
420 s.append(classToString(env, encl, full))
421 .append('.')
422 .append(c.name);
423 }
424 s.append(TypeMaker.typeParametersString(env, c, full));
425 return s.toString();
426 }
428 /**
429 * Is this class (or any enclosing class) generic? That is, does
430 * it have type parameters?
431 */
432 static boolean isGeneric(ClassSymbol c) {
433 return c.type.allparams().nonEmpty();
434 }
436 /**
437 * Return the formal type parameters of this class or interface.
438 * Return an empty array if there are none.
439 */
440 public TypeVariable[] typeParameters() {
441 if (env.legacyDoclet) {
442 return new TypeVariable[0];
443 }
444 TypeVariable res[] = new TypeVariable[type.getTypeArguments().length()];
445 TypeMaker.getTypes(env, type.getTypeArguments(), res);
446 return res;
447 }
449 /**
450 * Return the type parameter tags of this class or interface.
451 */
452 public ParamTag[] typeParamTags() {
453 return (env.legacyDoclet)
454 ? new ParamTag[0]
455 : comment().typeParamTags();
456 }
458 /**
459 * Return the modifier string for this class. If it's an interface
460 * exclude 'abstract' keyword from the modifier string
461 */
462 @Override
463 public String modifiers() {
464 return Modifier.toString(modifierSpecifier());
465 }
467 @Override
468 public int modifierSpecifier() {
469 int modifiers = getModifiers();
470 return (isInterface() || isAnnotationType())
471 ? modifiers & ~Modifier.ABSTRACT
472 : modifiers;
473 }
475 /**
476 * Return the superclass of this class
477 *
478 * @return the ClassDocImpl for the superclass of this class, null
479 * if there is no superclass.
480 */
481 public ClassDoc superclass() {
482 if (isInterface() || isAnnotationType()) return null;
483 if (tsym == env.syms.objectType.tsym) return null;
484 ClassSymbol c = (ClassSymbol)env.types.supertype(type).tsym;
485 if (c == null || c == tsym) c = (ClassSymbol)env.syms.objectType.tsym;
486 return env.getClassDoc(c);
487 }
489 /**
490 * Return the superclass of this class. Return null if this is an
491 * interface. A superclass is represented by either a
492 * <code>ClassDoc</code> or a <code>ParameterizedType</code>.
493 */
494 public com.sun.javadoc.Type superclassType() {
495 if (isInterface() || isAnnotationType() ||
496 (tsym == env.syms.objectType.tsym))
497 return null;
498 Type sup = env.types.supertype(type);
499 return TypeMaker.getType(env,
500 (sup != type) ? sup : env.syms.objectType);
501 }
503 /**
504 * Test whether this class is a subclass of the specified class.
505 *
506 * @param cd the candidate superclass.
507 * @return true if cd is a superclass of this class.
508 */
509 public boolean subclassOf(ClassDoc cd) {
510 return tsym.isSubClass(((ClassDocImpl)cd).tsym, env.types);
511 }
513 /**
514 * Return interfaces implemented by this class or interfaces
515 * extended by this interface.
516 *
517 * @return An array of ClassDocImpl representing the interfaces.
518 * Return an empty array if there are no interfaces.
519 */
520 public ClassDoc[] interfaces() {
521 ListBuffer<ClassDocImpl> ta = new ListBuffer<ClassDocImpl>();
522 for (Type t : env.types.interfaces(type)) {
523 ta.append(env.getClassDoc((ClassSymbol)t.tsym));
524 }
525 //### Cache ta here?
526 return ta.toArray(new ClassDocImpl[ta.length()]);
527 }
529 /**
530 * Return interfaces implemented by this class or interfaces extended
531 * by this interface. Includes only directly-declared interfaces, not
532 * inherited interfaces.
533 * Return an empty array if there are no interfaces.
534 */
535 public com.sun.javadoc.Type[] interfaceTypes() {
536 //### Cache result here?
537 return TypeMaker.getTypes(env, env.types.interfaces(type));
538 }
540 /**
541 * Return fields in class.
542 * @param filter include only the included fields if filter==true
543 */
544 public FieldDoc[] fields(boolean filter) {
545 return fields(filter, false);
546 }
548 /**
549 * Return included fields in class.
550 */
551 public FieldDoc[] fields() {
552 return fields(true, false);
553 }
555 /**
556 * Return the enum constants if this is an enum type.
557 */
558 public FieldDoc[] enumConstants() {
559 return fields(false, true);
560 }
562 /**
563 * Return fields in class.
564 * @param filter if true, return only the included fields
565 * @param enumConstants if true, return the enum constants instead
566 */
567 private FieldDoc[] fields(boolean filter, boolean enumConstants) {
568 List<FieldDocImpl> fields = List.nil();
569 for (Scope.Entry e = tsym.members().elems; e != null; e = e.sibling) {
570 if (e.sym != null && e.sym.kind == VAR) {
571 VarSymbol s = (VarSymbol)e.sym;
572 boolean isEnum = ((s.flags() & Flags.ENUM) != 0) &&
573 !env.legacyDoclet;
574 if (isEnum == enumConstants &&
575 (!filter || env.shouldDocument(s))) {
576 fields = fields.prepend(env.getFieldDoc(s));
577 }
578 }
579 }
580 return fields.toArray(new FieldDocImpl[fields.length()]);
581 }
583 /**
584 * Return methods in class.
585 * This method is overridden by AnnotationTypeDocImpl.
586 *
587 * @param filter include only the included methods if filter==true
588 * @return an array of MethodDocImpl for representing the visible
589 * methods in this class. Does not include constructors.
590 */
591 public MethodDoc[] methods(boolean filter) {
592 Names names = tsym.name.table.names;
593 List<MethodDocImpl> methods = List.nil();
594 for (Scope.Entry e = tsym.members().elems; e != null; e = e.sibling) {
595 if (e.sym != null &&
596 e.sym.kind == Kinds.MTH && e.sym.name != names.init) {
597 MethodSymbol s = (MethodSymbol)e.sym;
598 if (!filter || env.shouldDocument(s)) {
599 methods = methods.prepend(env.getMethodDoc(s));
600 }
601 }
602 }
603 //### Cache methods here?
604 return methods.toArray(new MethodDocImpl[methods.length()]);
605 }
607 /**
608 * Return included methods in class.
609 *
610 * @return an array of MethodDocImpl for representing the visible
611 * methods in this class. Does not include constructors.
612 */
613 public MethodDoc[] methods() {
614 return methods(true);
615 }
617 /**
618 * Return constructors in class.
619 *
620 * @param filter include only the included constructors if filter==true
621 * @return an array of ConstructorDocImpl for representing the visible
622 * constructors in this class.
623 */
624 public ConstructorDoc[] constructors(boolean filter) {
625 Names names = tsym.name.table.names;
626 List<ConstructorDocImpl> constructors = List.nil();
627 for (Scope.Entry e = tsym.members().elems; e != null; e = e.sibling) {
628 if (e.sym != null &&
629 e.sym.kind == Kinds.MTH && e.sym.name == names.init) {
630 MethodSymbol s = (MethodSymbol)e.sym;
631 if (!filter || env.shouldDocument(s)) {
632 constructors = constructors.prepend(env.getConstructorDoc(s));
633 }
634 }
635 }
636 //### Cache constructors here?
637 return constructors.toArray(new ConstructorDocImpl[constructors.length()]);
638 }
640 /**
641 * Return included constructors in class.
642 *
643 * @return an array of ConstructorDocImpl for representing the visible
644 * constructors in this class.
645 */
646 public ConstructorDoc[] constructors() {
647 return constructors(true);
648 }
650 /**
651 * Adds all inner classes of this class, and their
652 * inner classes recursively, to the list l.
653 */
654 void addAllClasses(ListBuffer<ClassDocImpl> l, boolean filtered) {
655 try {
656 if (isSynthetic()) return;
657 // sometimes synthetic classes are not marked synthetic
658 if (!JavadocTool.isValidClassName(tsym.name.toString())) return;
659 if (filtered && !env.shouldDocument(tsym)) return;
660 if (l.contains(this)) return;
661 l.append(this);
662 List<ClassDocImpl> more = List.nil();
663 for (Scope.Entry e = tsym.members().elems; e != null;
664 e = e.sibling) {
665 if (e.sym != null && e.sym.kind == Kinds.TYP) {
666 ClassSymbol s = (ClassSymbol)e.sym;
667 ClassDocImpl c = env.getClassDoc(s);
668 if (c.isSynthetic()) continue;
669 if (c != null) more = more.prepend(c);
670 }
671 }
672 // this extra step preserves the ordering from oldjavadoc
673 for (; more.nonEmpty(); more=more.tail) {
674 more.head.addAllClasses(l, filtered);
675 }
676 } catch (CompletionFailure e) {
677 // quietly ignore completion failures
678 }
679 }
681 /**
682 * Return inner classes within this class.
683 *
684 * @param filter include only the included inner classes if filter==true.
685 * @return an array of ClassDocImpl for representing the visible
686 * classes defined in this class. Anonymous and local classes
687 * are not included.
688 */
689 public ClassDoc[] innerClasses(boolean filter) {
690 ListBuffer<ClassDocImpl> innerClasses = new ListBuffer<ClassDocImpl>();
691 for (Scope.Entry e = tsym.members().elems; e != null; e = e.sibling) {
692 if (e.sym != null && e.sym.kind == Kinds.TYP) {
693 ClassSymbol s = (ClassSymbol)e.sym;
694 if ((s.flags_field & Flags.SYNTHETIC) != 0) continue;
695 if (!filter || env.isVisible(s)) {
696 innerClasses.prepend(env.getClassDoc(s));
697 }
698 }
699 }
700 //### Cache classes here?
701 return innerClasses.toArray(new ClassDocImpl[innerClasses.length()]);
702 }
704 /**
705 * Return included inner classes within this class.
706 *
707 * @return an array of ClassDocImpl for representing the visible
708 * classes defined in this class. Anonymous and local classes
709 * are not included.
710 */
711 public ClassDoc[] innerClasses() {
712 return innerClasses(true);
713 }
715 /**
716 * Find a class within the context of this class.
717 * Search order: qualified name, in this class (inner),
718 * in this package, in the class imports, in the package
719 * imports.
720 * Return the ClassDocImpl if found, null if not found.
721 */
722 //### The specified search order is not the normal rule the
723 //### compiler would use. Leave as specified or change it?
724 public ClassDoc findClass(String className) {
725 ClassDoc searchResult = searchClass(className);
726 if (searchResult == null) {
727 ClassDocImpl enclosingClass = (ClassDocImpl)containingClass();
728 //Expand search space to include enclosing class.
729 while (enclosingClass != null && enclosingClass.containingClass() != null) {
730 enclosingClass = (ClassDocImpl)enclosingClass.containingClass();
731 }
732 searchResult = enclosingClass == null ?
733 null : enclosingClass.searchClass(className);
734 }
735 return searchResult;
736 }
738 private ClassDoc searchClass(String className) {
739 Names names = tsym.name.table.names;
741 // search by qualified name first
742 ClassDoc cd = env.lookupClass(className);
743 if (cd != null) {
744 return cd;
745 }
747 // search inner classes
748 //### Add private entry point to avoid creating array?
749 //### Replicate code in innerClasses here to avoid consing?
750 for (ClassDoc icd : innerClasses()) {
751 if (icd.name().equals(className) ||
752 //### This is from original javadoc but it looks suspicious to me...
753 //### I believe it is attempting to compensate for the confused
754 //### convention of including the nested class qualifiers in the
755 //### 'name' of the inner class, rather than the true simple name.
756 icd.name().endsWith("." + className)) {
757 return icd;
758 } else {
759 ClassDoc innercd = ((ClassDocImpl) icd).searchClass(className);
760 if (innercd != null) {
761 return innercd;
762 }
763 }
764 }
766 // check in this package
767 cd = containingPackage().findClass(className);
768 if (cd != null) {
769 return cd;
770 }
772 // make sure that this symbol has been completed
773 if (tsym.completer != null) {
774 tsym.complete();
775 }
777 // search imports
779 if (tsym.sourcefile != null) {
781 //### This information is available only for source classes.
783 Env<AttrContext> compenv = env.enter.getEnv(tsym);
784 if (compenv == null) return null;
786 Scope s = compenv.toplevel.namedImportScope;
787 for (Scope.Entry e = s.lookup(names.fromString(className)); e.scope != null; e = e.next()) {
788 if (e.sym.kind == Kinds.TYP) {
789 ClassDoc c = env.getClassDoc((ClassSymbol)e.sym);
790 return c;
791 }
792 }
794 s = compenv.toplevel.starImportScope;
795 for (Scope.Entry e = s.lookup(names.fromString(className)); e.scope != null; e = e.next()) {
796 if (e.sym.kind == Kinds.TYP) {
797 ClassDoc c = env.getClassDoc((ClassSymbol)e.sym);
798 return c;
799 }
800 }
801 }
803 return null; // not found
804 }
807 private boolean hasParameterTypes(MethodSymbol method, String[] argTypes) {
809 if (argTypes == null) {
810 // wildcard
811 return true;
812 }
814 int i = 0;
815 List<Type> types = method.type.getParameterTypes();
817 if (argTypes.length != types.length()) {
818 return false;
819 }
821 for (Type t : types) {
822 String argType = argTypes[i++];
823 // For vararg method, "T..." matches type T[].
824 if (i == argTypes.length) {
825 argType = argType.replace("...", "[]");
826 }
827 if (!hasTypeName(env.types.erasure(t), argType)) { //###(gj)
828 return false;
829 }
830 }
831 return true;
832 }
833 // where
834 private boolean hasTypeName(Type t, String name) {
835 return
836 name.equals(TypeMaker.getTypeName(t, true))
837 ||
838 name.equals(TypeMaker.getTypeName(t, false))
839 ||
840 (qualifiedName() + "." + name).equals(TypeMaker.getTypeName(t, true));
841 }
845 /**
846 * Find a method in this class scope.
847 * Search order: this class, interfaces, superclasses, outerclasses.
848 * Note that this is not necessarily what the compiler would do!
849 *
850 * @param methodName the unqualified name to search for.
851 * @param paramTypes the array of Strings for method parameter types.
852 * @return the first MethodDocImpl which matches, null if not found.
853 */
854 public MethodDocImpl findMethod(String methodName, String[] paramTypes) {
855 // Use hash table 'searched' to avoid searching same class twice.
856 //### It is not clear how this could happen.
857 return searchMethod(methodName, paramTypes, new HashSet<ClassDocImpl>());
858 }
860 private MethodDocImpl searchMethod(String methodName,
861 String[] paramTypes, Set<ClassDocImpl> searched) {
862 //### Note that this search is not necessarily what the compiler would do!
864 Names names = tsym.name.table.names;
865 // do not match constructors
866 if (names.init.contentEquals(methodName)) {
867 return null;
868 }
870 ClassDocImpl cdi;
871 MethodDocImpl mdi;
873 if (searched.contains(this)) {
874 return null;
875 }
876 searched.add(this);
878 //DEBUG
879 /*---------------------------------*
880 System.out.print("searching " + this + " for " + methodName);
881 if (paramTypes == null) {
882 System.out.println("()");
883 } else {
884 System.out.print("(");
885 for (int k=0; k < paramTypes.length; k++) {
886 System.out.print(paramTypes[k]);
887 if ((k + 1) < paramTypes.length) {
888 System.out.print(", ");
889 }
890 }
891 System.out.println(")");
892 }
893 *---------------------------------*/
895 // search current class
896 Scope.Entry e = tsym.members().lookup(names.fromString(methodName));
898 //### Using modifier filter here isn't really correct,
899 //### but emulates the old behavior. Instead, we should
900 //### apply the normal rules of visibility and inheritance.
902 if (paramTypes == null) {
903 // If no parameters specified, we are allowed to return
904 // any method with a matching name. In practice, the old
905 // code returned the first method, which is now the last!
906 // In order to provide textually identical results, we
907 // attempt to emulate the old behavior.
908 MethodSymbol lastFound = null;
909 for (; e.scope != null; e = e.next()) {
910 if (e.sym.kind == Kinds.MTH) {
911 //### Should intern methodName as Name.
912 if (e.sym.name.toString().equals(methodName)) {
913 lastFound = (MethodSymbol)e.sym;
914 }
915 }
916 }
917 if (lastFound != null) {
918 return env.getMethodDoc(lastFound);
919 }
920 } else {
921 for (; e.scope != null; e = e.next()) {
922 if (e.sym != null &&
923 e.sym.kind == Kinds.MTH) {
924 //### Should intern methodName as Name.
925 if (hasParameterTypes((MethodSymbol)e.sym, paramTypes)) {
926 return env.getMethodDoc((MethodSymbol)e.sym);
927 }
928 }
929 }
930 }
932 //### If we found a MethodDoc above, but which did not pass
933 //### the modifier filter, we should return failure here!
935 // search superclass
936 cdi = (ClassDocImpl)superclass();
937 if (cdi != null) {
938 mdi = cdi.searchMethod(methodName, paramTypes, searched);
939 if (mdi != null) {
940 return mdi;
941 }
942 }
944 // search interfaces
945 ClassDoc intf[] = interfaces();
946 for (int i = 0; i < intf.length; i++) {
947 cdi = (ClassDocImpl)intf[i];
948 mdi = cdi.searchMethod(methodName, paramTypes, searched);
949 if (mdi != null) {
950 return mdi;
951 }
952 }
954 // search enclosing class
955 cdi = (ClassDocImpl)containingClass();
956 if (cdi != null) {
957 mdi = cdi.searchMethod(methodName, paramTypes, searched);
958 if (mdi != null) {
959 return mdi;
960 }
961 }
963 //###(gj) As a temporary measure until type variables are better
964 //### handled, try again without the parameter types.
965 //### This should most often find the right method, and occassionally
966 //### find the wrong one.
967 //if (paramTypes != null) {
968 // return findMethod(methodName, null);
969 //}
971 return null;
972 }
974 /**
975 * Find constructor in this class.
976 *
977 * @param constrName the unqualified name to search for.
978 * @param paramTypes the array of Strings for constructor parameters.
979 * @return the first ConstructorDocImpl which matches, null if not found.
980 */
981 public ConstructorDoc findConstructor(String constrName,
982 String[] paramTypes) {
983 Names names = tsym.name.table.names;
984 for (Scope.Entry e = tsym.members().lookup(names.fromString("<init>")); e.scope != null; e = e.next()) {
985 if (e.sym.kind == Kinds.MTH) {
986 if (hasParameterTypes((MethodSymbol)e.sym, paramTypes)) {
987 return env.getConstructorDoc((MethodSymbol)e.sym);
988 }
989 }
990 }
992 //###(gj) As a temporary measure until type variables are better
993 //### handled, try again without the parameter types.
994 //### This will often find the right constructor, and occassionally
995 //### find the wrong one.
996 //if (paramTypes != null) {
997 // return findConstructor(constrName, null);
998 //}
1000 return null;
1001 }
1003 /**
1004 * Find a field in this class scope.
1005 * Search order: this class, outerclasses, interfaces,
1006 * superclasses. IMP: If see tag is defined in an inner class,
1007 * which extends a super class and if outerclass and the super
1008 * class have a visible field in common then Java compiler cribs
1009 * about the ambiguity, but the following code will search in the
1010 * above given search order.
1011 *
1012 * @param fieldName the unqualified name to search for.
1013 * @return the first FieldDocImpl which matches, null if not found.
1014 */
1015 public FieldDoc findField(String fieldName) {
1016 return searchField(fieldName, new HashSet<ClassDocImpl>());
1017 }
1019 private FieldDocImpl searchField(String fieldName, Set<ClassDocImpl> searched) {
1020 Names names = tsym.name.table.names;
1021 if (searched.contains(this)) {
1022 return null;
1023 }
1024 searched.add(this);
1026 for (Scope.Entry e = tsym.members().lookup(names.fromString(fieldName)); e.scope != null; e = e.next()) {
1027 if (e.sym.kind == Kinds.VAR) {
1028 //### Should intern fieldName as Name.
1029 return env.getFieldDoc((VarSymbol)e.sym);
1030 }
1031 }
1033 //### If we found a FieldDoc above, but which did not pass
1034 //### the modifier filter, we should return failure here!
1036 ClassDocImpl cdi = (ClassDocImpl)containingClass();
1037 if (cdi != null) {
1038 FieldDocImpl fdi = cdi.searchField(fieldName, searched);
1039 if (fdi != null) {
1040 return fdi;
1041 }
1042 }
1044 // search superclass
1045 cdi = (ClassDocImpl)superclass();
1046 if (cdi != null) {
1047 FieldDocImpl fdi = cdi.searchField(fieldName, searched);
1048 if (fdi != null) {
1049 return fdi;
1050 }
1051 }
1053 // search interfaces
1054 ClassDoc intf[] = interfaces();
1055 for (int i = 0; i < intf.length; i++) {
1056 cdi = (ClassDocImpl)intf[i];
1057 FieldDocImpl fdi = cdi.searchField(fieldName, searched);
1058 if (fdi != null) {
1059 return fdi;
1060 }
1061 }
1063 return null;
1064 }
1066 /**
1067 * Get the list of classes declared as imported.
1068 * These are called "single-type-import declarations" in the JLS.
1069 * This method is deprecated in the ClassDoc interface.
1070 *
1071 * @return an array of ClassDocImpl representing the imported classes.
1072 *
1073 * @deprecated Import declarations are implementation details that
1074 * should not be exposed here. In addition, not all imported
1075 * classes are imported through single-type-import declarations.
1076 */
1077 @Deprecated
1078 public ClassDoc[] importedClasses() {
1079 // information is not available for binary classfiles
1080 if (tsym.sourcefile == null) return new ClassDoc[0];
1082 ListBuffer<ClassDocImpl> importedClasses = new ListBuffer<ClassDocImpl>();
1084 Env<AttrContext> compenv = env.enter.getEnv(tsym);
1085 if (compenv == null) return new ClassDocImpl[0];
1087 Name asterisk = tsym.name.table.names.asterisk;
1088 for (JCTree t : compenv.toplevel.defs) {
1089 if (t.hasTag(IMPORT)) {
1090 JCTree imp = ((JCImport) t).qualid;
1091 if ((TreeInfo.name(imp) != asterisk) &&
1092 (imp.type.tsym.kind & Kinds.TYP) != 0) {
1093 importedClasses.append(
1094 env.getClassDoc((ClassSymbol)imp.type.tsym));
1095 }
1096 }
1097 }
1099 return importedClasses.toArray(new ClassDocImpl[importedClasses.length()]);
1100 }
1102 /**
1103 * Get the list of packages declared as imported.
1104 * These are called "type-import-on-demand declarations" in the JLS.
1105 * This method is deprecated in the ClassDoc interface.
1106 *
1107 * @return an array of PackageDocImpl representing the imported packages.
1108 *
1109 * ###NOTE: the syntax supports importing all inner classes from a class as well.
1110 * @deprecated Import declarations are implementation details that
1111 * should not be exposed here. In addition, this method's
1112 * return type does not allow for all type-import-on-demand
1113 * declarations to be returned.
1114 */
1115 @Deprecated
1116 public PackageDoc[] importedPackages() {
1117 // information is not available for binary classfiles
1118 if (tsym.sourcefile == null) return new PackageDoc[0];
1120 ListBuffer<PackageDocImpl> importedPackages = new ListBuffer<PackageDocImpl>();
1122 //### Add the implicit "import java.lang.*" to the result
1123 Names names = tsym.name.table.names;
1124 importedPackages.append(env.getPackageDoc(env.reader.enterPackage(names.java_lang)));
1126 Env<AttrContext> compenv = env.enter.getEnv(tsym);
1127 if (compenv == null) return new PackageDocImpl[0];
1129 for (JCTree t : compenv.toplevel.defs) {
1130 if (t.hasTag(IMPORT)) {
1131 JCTree imp = ((JCImport) t).qualid;
1132 if (TreeInfo.name(imp) == names.asterisk) {
1133 JCFieldAccess sel = (JCFieldAccess)imp;
1134 Symbol s = sel.selected.type.tsym;
1135 PackageDocImpl pdoc = env.getPackageDoc(s.packge());
1136 if (!importedPackages.contains(pdoc))
1137 importedPackages.append(pdoc);
1138 }
1139 }
1140 }
1142 return importedPackages.toArray(new PackageDocImpl[importedPackages.length()]);
1143 }
1145 /**
1146 * Return the type's dimension information.
1147 * Always return "", as this is not an array type.
1148 */
1149 public String dimension() {
1150 return "";
1151 }
1153 /**
1154 * Return this type as a class, which it already is.
1155 */
1156 public ClassDoc asClassDoc() {
1157 return this;
1158 }
1160 /**
1161 * Return null (unless overridden), as this is not an annotation type.
1162 */
1163 public AnnotationTypeDoc asAnnotationTypeDoc() {
1164 return null;
1165 }
1167 /**
1168 * Return null, as this is not a class instantiation.
1169 */
1170 public ParameterizedType asParameterizedType() {
1171 return null;
1172 }
1174 /**
1175 * Return null, as this is not a type variable.
1176 */
1177 public TypeVariable asTypeVariable() {
1178 return null;
1179 }
1181 /**
1182 * Return null, as this is not a wildcard type.
1183 */
1184 public WildcardType asWildcardType() {
1185 return null;
1186 }
1188 /**
1189 * Returns null, as this is not an annotated type.
1190 */
1191 public AnnotatedType asAnnotatedType() {
1192 return null;
1193 }
1195 /**
1196 * Return false, as this is not a primitive type.
1197 */
1198 public boolean isPrimitive() {
1199 return false;
1200 }
1202 //--- Serialization ---
1204 //### These methods ignore modifier filter.
1206 /**
1207 * Return true if this class implements <code>java.io.Serializable</code>.
1208 *
1209 * Since <code>java.io.Externalizable</code> extends
1210 * <code>java.io.Serializable</code>,
1211 * Externalizable objects are also Serializable.
1212 */
1213 public boolean isSerializable() {
1214 try {
1215 return env.types.isSubtype(type, env.syms.serializableType);
1216 } catch (CompletionFailure ex) {
1217 // quietly ignore completion failures
1218 return false;
1219 }
1220 }
1222 /**
1223 * Return true if this class implements
1224 * <code>java.io.Externalizable</code>.
1225 */
1226 public boolean isExternalizable() {
1227 try {
1228 return env.types.isSubtype(type, env.externalizableSym.type);
1229 } catch (CompletionFailure ex) {
1230 // quietly ignore completion failures
1231 return false;
1232 }
1233 }
1235 /**
1236 * Return the serialization methods for this class.
1237 *
1238 * @return an array of <code>MethodDocImpl</code> that represents
1239 * the serialization methods for this class.
1240 */
1241 public MethodDoc[] serializationMethods() {
1242 if (serializedForm == null) {
1243 serializedForm = new SerializedForm(env, tsym, this);
1244 }
1245 //### Clone this?
1246 return serializedForm.methods();
1247 }
1249 /**
1250 * Return the Serializable fields of class.<p>
1251 *
1252 * Return either a list of default fields documented by
1253 * <code>serial</code> tag<br>
1254 * or return a single <code>FieldDoc</code> for
1255 * <code>serialPersistentField</code> member.
1256 * There should be a <code>serialField</code> tag for
1257 * each Serializable field defined by an <code>ObjectStreamField</code>
1258 * array component of <code>serialPersistentField</code>.
1259 *
1260 * @returns an array of <code>FieldDoc</code> for the Serializable fields
1261 * of this class.
1262 *
1263 * @see #definesSerializableFields()
1264 * @see SerialFieldTagImpl
1265 */
1266 public FieldDoc[] serializableFields() {
1267 if (serializedForm == null) {
1268 serializedForm = new SerializedForm(env, tsym, this);
1269 }
1270 //### Clone this?
1271 return serializedForm.fields();
1272 }
1274 /**
1275 * Return true if Serializable fields are explicitly defined with
1276 * the special class member <code>serialPersistentFields</code>.
1277 *
1278 * @see #serializableFields()
1279 * @see SerialFieldTagImpl
1280 */
1281 public boolean definesSerializableFields() {
1282 if (!isSerializable() || isExternalizable()) {
1283 return false;
1284 } else {
1285 if (serializedForm == null) {
1286 serializedForm = new SerializedForm(env, tsym, this);
1287 }
1288 //### Clone this?
1289 return serializedForm.definesSerializableFields();
1290 }
1291 }
1293 /**
1294 * Determine if a class is a RuntimeException.
1295 * <p>
1296 * Used only by ThrowsTagImpl.
1297 */
1298 boolean isRuntimeException() {
1299 return tsym.isSubClass(env.syms.runtimeExceptionType.tsym, env.types);
1300 }
1302 /**
1303 * Return the source position of the entity, or null if
1304 * no position is available.
1305 */
1306 @Override
1307 public SourcePosition position() {
1308 if (tsym.sourcefile == null) return null;
1309 return SourcePositionImpl.make(tsym.sourcefile,
1310 (tree==null) ? Position.NOPOS : tree.pos,
1311 lineMap);
1312 }
1313 }