OSDN Git Service

am edb6829f: Merge change 4654 into donut
[android-x86/build.git] / tools / droiddoc / src / ClassInfo.java
1 /*
2  * Copyright (C) 2008 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 import com.sun.javadoc.*;
18 import com.sun.tools.doclets.*;
19 import org.clearsilver.HDF;
20 import org.clearsilver.CS;
21 import java.util.*;
22 import java.io.*;
23
24 public class ClassInfo extends DocInfo implements ContainerInfo, Comparable, Scoped
25 {
26     public static final Comparator<ClassInfo> comparator = new Comparator<ClassInfo>() {
27         public int compare(ClassInfo a, ClassInfo b) {
28             return a.name().compareTo(b.name());
29         }
30     };
31
32     public static final Comparator<ClassInfo> qualifiedComparator = new Comparator<ClassInfo>() {
33         public int compare(ClassInfo a, ClassInfo b) {
34             return a.qualifiedName().compareTo(b.qualifiedName());
35         }
36     };
37
38     public ClassInfo(
39             ClassDoc cl,
40             String rawCommentText, SourcePositionInfo position,
41             boolean isPublic, boolean isProtected, boolean isPackagePrivate,
42             boolean isPrivate, boolean isStatic,
43             boolean isInterface, boolean isAbstract, boolean isOrdinaryClass,
44             boolean isException, boolean isError, boolean isEnum, boolean isAnnotation,
45             boolean isFinal, boolean isIncluded, String name,
46             String qualifiedName, String qualifiedTypeName, boolean isPrimitive)
47     {
48         super(rawCommentText, position);
49
50         mClass = cl;
51         mIsPublic = isPublic;
52         mIsProtected = isProtected;
53         mIsPackagePrivate = isPackagePrivate;
54         mIsPrivate = isPrivate;
55         mIsStatic = isStatic;
56         mIsInterface = isInterface;
57         mIsAbstract = isAbstract;
58         mIsOrdinaryClass = isOrdinaryClass;
59         mIsException = isException;
60         mIsError = isError;
61         mIsEnum = isEnum;
62         mIsAnnotation = isAnnotation;
63         mIsFinal = isFinal;
64         mIsIncluded = isIncluded;
65         mName = name;
66         mQualifiedName = qualifiedName;
67         mQualifiedTypeName = qualifiedTypeName;
68         mIsPrimitive = isPrimitive;
69         mNameParts = name.split("\\.");
70     }
71
72     public void init(TypeInfo typeInfo, ClassInfo[] interfaces, TypeInfo[] interfaceTypes,
73             ClassInfo[] innerClasses,
74             MethodInfo[] constructors, MethodInfo[] methods, MethodInfo[] annotationElements,
75             FieldInfo[] fields, FieldInfo[] enumConstants,
76             PackageInfo containingPackage, ClassInfo containingClass,
77             ClassInfo superclass, TypeInfo superclassType, AnnotationInstanceInfo[] annotations)
78     {
79         mTypeInfo = typeInfo;
80         mRealInterfaces = interfaces;
81         mRealInterfaceTypes = interfaceTypes;
82         mInnerClasses = innerClasses;
83         mAllConstructors = constructors;
84         mAllSelfMethods = methods;
85         mAnnotationElements = annotationElements;
86         mAllSelfFields = fields;
87         mEnumConstants = enumConstants;
88         mContainingPackage = containingPackage;
89         mContainingClass = containingClass;
90         mRealSuperclass = superclass;
91         mRealSuperclassType = superclassType;
92         mAnnotations = annotations;
93
94         // after providing new methods and new superclass info,clear any cached
95         // lists of self + superclass methods, ctors, etc.
96         mSuperclassInit = false;
97         mConstructors = null;
98         mMethods = null;
99         mSelfMethods = null;
100         mFields = null;
101         mSelfFields = null;
102         mSelfAttributes = null;
103         mDeprecatedKnown = false;
104         
105         Arrays.sort(mEnumConstants, FieldInfo.comparator);
106         Arrays.sort(mInnerClasses, ClassInfo.comparator);
107     }
108
109     public void init2() {
110         // calling this here forces the AttrTagInfo objects to be linked to the AttribtueInfo
111         // objects
112         selfAttributes();
113     }
114     
115     public void init3(TypeInfo[] types, ClassInfo[] realInnerClasses){
116       mTypeParameters = types;
117       mRealInnerClasses = realInnerClasses;
118     }
119     
120     public ClassInfo[] getRealInnerClasses(){
121       return mRealInnerClasses;
122     }
123     
124     public TypeInfo[] getTypeParameters(){
125       return mTypeParameters;
126     }
127
128     public boolean checkLevel()
129     {
130         int val = mCheckLevel;
131         if (val >= 0) {
132             return val != 0;
133         } else {
134             boolean v = DroidDoc.checkLevel(mIsPublic, mIsProtected,
135                                                 mIsPackagePrivate, mIsPrivate, isHidden());
136             mCheckLevel = v ? 1 : 0;
137             return v;
138         }
139     }
140
141     public int compareTo(Object that) {
142         if (that instanceof ClassInfo) {
143             return mQualifiedName.compareTo(((ClassInfo)that).mQualifiedName);
144         } else {
145             return this.hashCode() - that.hashCode();
146         }
147     }
148
149     public ContainerInfo parent()
150     {
151         return this;
152     }
153
154     public boolean isPublic()
155     {
156         return mIsPublic;
157     }
158
159     public boolean isProtected()
160     {
161         return mIsProtected;
162     }
163
164     public boolean isPackagePrivate()
165     {
166         return mIsPackagePrivate;
167     }
168
169     public boolean isPrivate()
170     {
171         return mIsPrivate;
172     }
173
174     public boolean isStatic()
175     {
176         return mIsStatic;
177     }
178
179     public boolean isInterface()
180     {
181         return mIsInterface;
182     }
183
184     public boolean isAbstract()
185     {
186         return mIsAbstract;
187     }
188
189     public PackageInfo containingPackage()
190     {
191         return mContainingPackage;
192     }
193
194     public ClassInfo containingClass()
195     {
196         return mContainingClass;
197     }
198
199     public boolean isOrdinaryClass()
200     {
201         return mIsOrdinaryClass;
202     }
203
204     public boolean isException()
205     {
206         return mIsException;
207     }
208
209     public boolean isError()
210     {
211         return mIsError;
212     }
213
214     public boolean isEnum()
215     {
216         return mIsEnum;
217     }
218
219     public boolean isAnnotation()
220     {
221         return mIsAnnotation;
222     }
223
224     public boolean isFinal()
225     {
226         return mIsFinal;
227     }
228
229     public boolean isIncluded()
230     {
231         return mIsIncluded;
232     }
233
234     public HashSet<String> typeVariables()
235     {
236         HashSet<String> result = TypeInfo.typeVariables(mTypeInfo.typeArguments());
237         ClassInfo cl = containingClass();
238         while (cl != null) {
239             TypeInfo[] types = cl.asTypeInfo().typeArguments();
240             if (types != null) {
241                 TypeInfo.typeVariables(types, result);
242             }
243             cl = cl.containingClass();
244         }
245         return result;
246     }
247
248     private static void gatherHiddenInterfaces(ClassInfo cl, HashSet<ClassInfo> interfaces) {
249         for (ClassInfo iface: cl.mRealInterfaces) {
250             if (iface.checkLevel()) {
251                 interfaces.add(iface);
252             } else {
253                 gatherHiddenInterfaces(iface, interfaces);
254             }
255         }
256     }
257
258     public ClassInfo[] interfaces()
259     {
260         if (mInterfaces == null) {
261             if (checkLevel()) {
262                 HashSet<ClassInfo> interfaces = new HashSet<ClassInfo>();
263                 ClassInfo superclass = mRealSuperclass;
264                 while (superclass != null && !superclass.checkLevel()) {
265                     gatherHiddenInterfaces(superclass, interfaces);
266                     superclass = superclass.mRealSuperclass;
267                 }
268                 gatherHiddenInterfaces(this, interfaces);
269                 mInterfaces = interfaces.toArray(new ClassInfo[interfaces.size()]);
270             } else {
271                 // put something here in case someone uses it
272                 mInterfaces = mRealInterfaces;
273             }
274             Arrays.sort(mInterfaces, ClassInfo.qualifiedComparator);
275         }
276         return mInterfaces;
277     }
278
279     public ClassInfo[] realInterfaces()
280     {
281         return mRealInterfaces;
282     }
283
284     TypeInfo[] realInterfaceTypes()
285     {
286         return mRealInterfaceTypes;
287     }
288
289     public String name()
290     {
291         return mName;
292     }
293
294     public String[] nameParts()
295     {
296         return mNameParts;
297     }
298
299     public String leafName()
300     {
301         return mNameParts[mNameParts.length-1];
302     }
303
304     public String qualifiedName()
305     {
306         return mQualifiedName;
307     }
308
309     public String qualifiedTypeName()
310     {
311         return mQualifiedTypeName;
312     }
313
314     public boolean isPrimitive()
315     {
316         return mIsPrimitive;
317     }
318
319     public MethodInfo[] allConstructors() {
320         return mAllConstructors;
321     }
322
323     public MethodInfo[] constructors()
324     {
325         if (mConstructors == null) {
326             MethodInfo[] methods = mAllConstructors;
327             ArrayList<MethodInfo> ctors = new ArrayList<MethodInfo>();
328             for (int i=0; i<methods.length; i++) {
329                 MethodInfo m = methods[i];
330                 if (!m.isHidden()) {
331                     ctors.add(m);
332                 }
333             }
334             mConstructors = ctors.toArray(new MethodInfo[ctors.size()]);
335             Arrays.sort(mConstructors, MethodInfo.comparator);
336         }
337         return mConstructors;
338     }
339
340     public ClassInfo[] innerClasses()
341     {
342         return mInnerClasses;
343     }
344
345     public TagInfo[] inlineTags()
346     {
347         return comment().tags();
348     }
349
350     public TagInfo[] firstSentenceTags()
351     {
352         return comment().briefTags();
353     }
354     
355     public boolean isDeprecated() {
356         boolean deprecated = false;
357         if (!mDeprecatedKnown) {
358             boolean commentDeprecated = (comment().deprecatedTags().length > 0);
359             boolean annotationDeprecated = false;
360             for (AnnotationInstanceInfo annotation : annotations()) {
361                 if (annotation.type().qualifiedName().equals("java.lang.Deprecated")) {
362                     annotationDeprecated = true;
363                     break;
364                 }
365             }
366
367             if (commentDeprecated != annotationDeprecated) {
368                 Errors.error(Errors.DEPRECATION_MISMATCH, position(),
369                         "Class " + qualifiedName()
370                         + ": @Deprecated annotation and @deprecated comment do not match");
371             }
372
373             mIsDeprecated = commentDeprecated | annotationDeprecated;
374             mDeprecatedKnown = true;
375         }
376         return mIsDeprecated;
377     }
378
379     public TagInfo[] deprecatedTags()
380     {
381         // Should we also do the interfaces?
382         return comment().deprecatedTags();
383     }
384
385     public MethodInfo[] methods()
386     {
387         if (mMethods == null) {
388             TreeMap<String,MethodInfo> all = new TreeMap<String,MethodInfo>();
389
390             ClassInfo[] ifaces = interfaces();
391             for (ClassInfo iface: ifaces) {
392                 if (iface != null) {
393                     MethodInfo[] inhereted = iface.methods();
394                     for (MethodInfo method: inhereted) {
395                         String key = method.name() + method.signature();
396                         all.put(key, method);
397                     }
398                 }
399             }
400
401             ClassInfo superclass = superclass();
402             if (superclass != null) {
403                 MethodInfo[] inhereted = superclass.methods();
404                 for (MethodInfo method: inhereted) {
405                     String key = method.name() + method.signature();
406                     all.put(key, method);
407                 }
408             }
409
410             MethodInfo[] methods = selfMethods();
411             for (MethodInfo method: methods) {
412                 String key = method.name() + method.signature();
413                 MethodInfo old = all.put(key, method);
414             }
415
416             mMethods = all.values().toArray(new MethodInfo[all.size()]);
417         }
418         return mMethods;
419     }
420
421     public MethodInfo[] annotationElements()
422     {
423         return mAnnotationElements;
424     }
425
426     public AnnotationInstanceInfo[] annotations()
427     {
428         return mAnnotations;
429     }
430
431     private static void addFields(ClassInfo cl, TreeMap<String,FieldInfo> all)
432     {
433         FieldInfo[] fields = cl.fields();
434         int N = fields.length;
435         for (int i=0; i<N; i++) {
436             FieldInfo f = fields[i];
437             all.put(f.name(), f);
438         }
439     }
440
441     public FieldInfo[] fields()
442     {
443         if (mFields == null) {
444             int N;
445             TreeMap<String,FieldInfo> all = new TreeMap<String,FieldInfo>();
446
447             ClassInfo[] interfaces = interfaces();
448             N = interfaces.length;
449             for (int i=0; i<N; i++) {
450                 addFields(interfaces[i], all);
451             }
452
453             ClassInfo superclass = superclass();
454             if (superclass != null) {
455                 addFields(superclass, all);
456             }
457
458             FieldInfo[] fields = selfFields();
459             N = fields.length;
460             for (int i=0; i<N; i++) {
461                 FieldInfo f = fields[i];
462                 if (!f.isHidden()) {
463                     String key = f.name();
464                     all.put(key, f);
465                 }
466             }
467
468             mFields = all.values().toArray(new FieldInfo[0]);
469         }
470         return mFields;
471     }
472
473     public void gatherFields(ClassInfo owner, ClassInfo cl, HashMap<String,FieldInfo> fields) {
474         FieldInfo[] flds = cl.selfFields();
475         for (FieldInfo f: flds) {
476             if (f.checkLevel()) {
477                 fields.put(f.name(), f.cloneForClass(owner));
478             }
479         }
480     }
481
482     public FieldInfo[] selfFields()
483     {
484         if (mSelfFields == null) {
485             HashMap<String,FieldInfo> fields = new HashMap<String,FieldInfo>();
486             // our hidden parents
487             if (mRealSuperclass != null && !mRealSuperclass.checkLevel()) {
488                 gatherFields(this, mRealSuperclass, fields);
489             }
490             for (ClassInfo iface: mRealInterfaces) {
491                 if (!iface.checkLevel()) {
492                     gatherFields(this, iface, fields);
493                 }
494             }
495             // mine
496             FieldInfo[] selfFields = mAllSelfFields;
497             for (int i=0; i<selfFields.length; i++) {
498                 FieldInfo f = selfFields[i];
499                 if (!f.isHidden()) {
500                     fields.put(f.name(), f);
501                 }
502             }
503             // combine and return in
504             mSelfFields = fields.values().toArray(new FieldInfo[fields.size()]);
505             Arrays.sort(mSelfFields, FieldInfo.comparator);
506         }
507         return mSelfFields;
508     }
509
510     public FieldInfo[] allSelfFields() {
511         return mAllSelfFields;
512     }
513
514     public void gatherMethods(ClassInfo owner, ClassInfo cl, HashMap<String,MethodInfo> methods) {
515         MethodInfo[] meth = cl.selfMethods();
516         for (MethodInfo m: meth) {
517             if (m.checkLevel()) {
518                 methods.put(m.name()+m.signature(), m.cloneForClass(owner));
519             }
520         }
521     }
522
523     public MethodInfo[] selfMethods()
524     {
525         if (mSelfMethods == null) {
526             HashMap<String,MethodInfo> methods = new HashMap<String,MethodInfo>();
527             // our hidden parents
528             if (mRealSuperclass != null && !mRealSuperclass.checkLevel()) {
529                 gatherMethods(this, mRealSuperclass, methods);
530             }
531             for (ClassInfo iface: mRealInterfaces) {
532                 if (!iface.checkLevel()) {
533                     gatherMethods(this, iface, methods);
534                 }
535             }
536             // mine
537             MethodInfo[] selfMethods = mAllSelfMethods;
538             for (int i=0; i<selfMethods.length; i++) {
539                 MethodInfo m = selfMethods[i];
540                 if (m.checkLevel()) {
541                     methods.put(m.name()+m.signature(), m);
542                 }
543             }
544             // combine and return it
545             mSelfMethods = methods.values().toArray(new MethodInfo[methods.size()]);
546             Arrays.sort(mSelfMethods, MethodInfo.comparator);
547         }
548         return mSelfMethods;
549     }
550
551     public MethodInfo[] allSelfMethods() {
552         return mAllSelfMethods;
553     }
554     
555     public void addMethod(MethodInfo method) {
556         MethodInfo[] methods = new MethodInfo[mAllSelfMethods.length + 1];
557         int i = 0;
558         for (MethodInfo m : mAllSelfMethods) {
559             methods[i] = m;
560             i++;
561         }
562         methods[i] = method;
563         mAllSelfMethods = methods;
564     }
565
566     public AttributeInfo[] selfAttributes()
567     {
568         if (mSelfAttributes == null) {
569             TreeMap<FieldInfo,AttributeInfo> attrs = new TreeMap<FieldInfo,AttributeInfo>();
570
571             // the ones in the class comment won't have any methods
572             for (AttrTagInfo tag: comment().attrTags()) {
573                 FieldInfo field = tag.reference();
574                 if (field != null) {
575                     AttributeInfo attr = attrs.get(field);
576                     if (attr == null) {
577                         attr = new AttributeInfo(this, field);
578                         attrs.put(field, attr);
579                     }
580                     tag.setAttribute(attr);
581                 }
582             }
583
584             // in the methods
585             for (MethodInfo m: selfMethods()) {
586                 for (AttrTagInfo tag: m.comment().attrTags()) {
587                     FieldInfo field = tag.reference();
588                     if (field != null) {
589                         AttributeInfo attr = attrs.get(field);
590                         if (attr == null) {
591                             attr = new AttributeInfo(this, field);
592                             attrs.put(field, attr);
593                         }
594                         tag.setAttribute(attr);
595                         attr.methods.add(m);
596                     }
597                 }
598             }
599             
600             //constructors too
601            for (MethodInfo m: constructors()) {
602               for (AttrTagInfo tag: m.comment().attrTags()) {
603                   FieldInfo field = tag.reference();
604                   if (field != null) {
605                       AttributeInfo attr = attrs.get(field);
606                       if (attr == null) {
607                           attr = new AttributeInfo(this, field);
608                           attrs.put(field, attr);
609                       }
610                       tag.setAttribute(attr);
611                       attr.methods.add(m);
612                   }
613               }
614           }
615
616             mSelfAttributes = attrs.values().toArray(new AttributeInfo[attrs.size()]);
617             Arrays.sort(mSelfAttributes, AttributeInfo.comparator);
618         }
619         return mSelfAttributes;
620     }
621
622     public FieldInfo[] enumConstants()
623     {
624         return mEnumConstants;
625     }
626
627     public ClassInfo superclass()
628     {
629         if (!mSuperclassInit) {
630             if (this.checkLevel()) {
631                 // rearrange our little inheritance hierarchy, because we need to hide classes that
632                 // don't pass checkLevel
633                 ClassInfo superclass = mRealSuperclass;
634                 while (superclass != null && !superclass.checkLevel()) {
635                     superclass = superclass.mRealSuperclass;
636                 }
637                 mSuperclass = superclass;
638             } else {
639                 mSuperclass = mRealSuperclass;
640             }
641         }
642         return mSuperclass;
643     }
644
645     public ClassInfo realSuperclass()
646     {
647         return mRealSuperclass;
648     }
649
650     /** always the real superclass, not the collapsed one we get through superclass(),
651      * also has the type parameter info if it's generic.
652      */
653     public TypeInfo superclassType()
654     {
655         return mRealSuperclassType;
656     }
657
658     public TypeInfo asTypeInfo()
659     {
660         return mTypeInfo;
661     }
662
663     TypeInfo[] interfaceTypes()
664     {
665         ClassInfo[] infos = interfaces();
666         int len = infos.length;
667         TypeInfo[] types = new TypeInfo[len];
668         for (int i=0; i<len; i++) {
669             types[i] = infos[i].asTypeInfo();
670         }
671         return types;
672     }
673
674     public String htmlPage()
675     {
676         String s = containingPackage().name();
677         s = s.replace('.', '/');
678         s += '/';
679         s += name();
680         s += ".html";
681         s = DroidDoc.javadocDir + s;
682         return s;
683     }
684
685     /** Even indirectly */
686     public boolean isDerivedFrom(ClassInfo cl)
687     {
688         ClassInfo dad = this.superclass();
689         if (dad != null) {
690             if (dad.equals(cl)) {
691                 return true;
692             } else {
693                 if (dad.isDerivedFrom(cl)) {
694                     return true;
695                 }
696             }
697         }
698         for (ClassInfo iface: interfaces()) {
699             if (iface.equals(cl)) {
700                 return true;
701             } else {
702                 if (iface.isDerivedFrom(cl)) {
703                     return true;
704                 }
705             }
706         }
707         return false;
708     }
709
710     public void makeKeywordEntries(List<KeywordEntry> keywords)
711     {
712         if (!checkLevel()) {
713             return;
714         }
715
716         String htmlPage = htmlPage();
717         String qualifiedName = qualifiedName();
718
719         keywords.add(new KeywordEntry(name(), htmlPage,
720                 "class in " + containingPackage().name()));
721
722         FieldInfo[] fields = selfFields();
723         FieldInfo[] enumConstants = enumConstants();
724         MethodInfo[] ctors = constructors();
725         MethodInfo[] methods = selfMethods();
726
727         // enum constants
728         for (FieldInfo field: enumConstants()) {
729             if (field.checkLevel()) {
730                 keywords.add(new KeywordEntry(field.name(),
731                             htmlPage + "#" + field.anchor(),
732                             "enum constant in " + qualifiedName));
733             }
734         }
735
736         // constants
737         for (FieldInfo field: fields) {
738             if (field.isConstant() && field.checkLevel()) {
739                 keywords.add(new KeywordEntry(field.name(),
740                             htmlPage + "#" + field.anchor(),
741                             "constant in " + qualifiedName));
742             }
743         }
744
745         // fields
746         for (FieldInfo field: fields) {
747             if (!field.isConstant() && field.checkLevel()) {
748                 keywords.add(new KeywordEntry(field.name(),
749                             htmlPage + "#" + field.anchor(),
750                             "field in " + qualifiedName));
751             }
752         }
753
754         // public constructors
755         for (MethodInfo m: ctors) {
756             if (m.isPublic() && m.checkLevel()) {
757                 keywords.add(new KeywordEntry(m.name() + m.prettySignature(),
758                             htmlPage + "#" + m.anchor(),
759                             "constructor in " + qualifiedName));
760             }
761         }
762
763         // protected constructors
764         if (DroidDoc.checkLevel(DroidDoc.SHOW_PROTECTED)) {
765             for (MethodInfo m: ctors) {
766                 if (m.isProtected() && m.checkLevel()) {
767                     keywords.add(new KeywordEntry(m.name() + m.prettySignature(),
768                                 htmlPage + "#" + m.anchor(),
769                                 "constructor in " + qualifiedName));
770                 }
771             }
772         }
773
774         // package private constructors
775         if (DroidDoc.checkLevel(DroidDoc.SHOW_PACKAGE)) {
776             for (MethodInfo m: ctors) {
777                 if (m.isPackagePrivate() && m.checkLevel()) {
778                     keywords.add(new KeywordEntry(m.name() + m.prettySignature(),
779                                 htmlPage + "#" + m.anchor(),
780                                 "constructor in " + qualifiedName));
781                 }
782             }
783         }
784
785         // private constructors
786         if (DroidDoc.checkLevel(DroidDoc.SHOW_PRIVATE)) {
787             for (MethodInfo m: ctors) {
788                 if (m.isPrivate() && m.checkLevel()) {
789                     keywords.add(new KeywordEntry(m.name() + m.prettySignature(),
790                                 htmlPage + "#" + m.anchor(),
791                                 "constructor in " + qualifiedName));
792                 }
793             }
794         }
795
796         // public methods
797         for (MethodInfo m: methods) {
798             if (m.isPublic() && m.checkLevel()) {
799                 keywords.add(new KeywordEntry(m.name() + m.prettySignature(),
800                             htmlPage + "#" + m.anchor(),
801                             "method in " + qualifiedName));
802             }
803         }
804
805         // protected methods
806         if (DroidDoc.checkLevel(DroidDoc.SHOW_PROTECTED)) {
807             for (MethodInfo m: methods) {
808                 if (m.isProtected() && m.checkLevel()) {
809                     keywords.add(new KeywordEntry(m.name() + m.prettySignature(),
810                                 htmlPage + "#" + m.anchor(),
811                                 "method in " + qualifiedName));
812                 }
813             }
814         }
815
816         // package private methods
817         if (DroidDoc.checkLevel(DroidDoc.SHOW_PACKAGE)) {
818             for (MethodInfo m: methods) {
819                 if (m.isPackagePrivate() && m.checkLevel()) {
820                     keywords.add(new KeywordEntry(m.name() + m.prettySignature(),
821                                 htmlPage + "#" + m.anchor(),
822                                 "method in " + qualifiedName));
823                 }
824             }
825         }
826
827         // private methods
828         if (DroidDoc.checkLevel(DroidDoc.SHOW_PRIVATE)) {
829             for (MethodInfo m: methods) {
830                 if (m.isPrivate() && m.checkLevel()) {
831                     keywords.add(new KeywordEntry(m.name() + m.prettySignature(),
832                                 htmlPage + "#" + m.anchor(),
833                                 "method in " + qualifiedName));
834                 }
835             }
836         }
837     }
838
839     public void makeLink(HDF data, String base)
840     {
841         data.setValue(base + ".label", this.name());
842         if (!this.isPrimitive() && this.isIncluded() && this.checkLevel()) {
843             data.setValue(base + ".link", this.htmlPage());
844         }
845     }
846
847     public static void makeLinkListHDF(HDF data, String base, ClassInfo[] classes) {
848         final int N = classes.length;
849         for (int i=0; i<N; i++) {
850             ClassInfo cl = classes[i];
851             if (cl.checkLevel()) {
852                 cl.asTypeInfo().makeHDF(data, base + "." + i);
853             }
854         }
855     }
856
857     /**
858      * Used in lists of this class (packages, nested classes, known subclasses)
859      */
860     public void makeShortDescrHDF(HDF data, String base)
861     {
862         mTypeInfo.makeHDF(data, base + ".type");
863         data.setValue(base + ".kind", this.kind());
864         TagInfo.makeHDF(data, base + ".shortDescr", this.firstSentenceTags());
865         TagInfo.makeHDF(data, base + ".deprecated", deprecatedTags());
866     }
867
868     /**
869      * Turns into the main class page
870      */
871     public void makeHDF(HDF data)
872     {
873         int i, j, n;
874         String name = name();
875         String qualified = qualifiedName();
876         AttributeInfo[] selfAttributes = selfAttributes();
877         MethodInfo[] methods = selfMethods();
878         FieldInfo[] fields = selfFields();
879         FieldInfo[] enumConstants = enumConstants();
880         MethodInfo[] ctors = constructors();
881         ClassInfo[] inners = innerClasses();
882
883         // class name
884         mTypeInfo.makeHDF(data, "class.type");
885         mTypeInfo.makeQualifiedHDF(data, "class.qualifiedType");
886         data.setValue("class.name", name);
887         data.setValue("class.qualified", qualified);
888         String scope = "";
889         if (isProtected()) {
890             data.setValue("class.scope", "protected");
891         }
892         else if (isPublic()) {
893             data.setValue("class.scope", "public");
894         }
895         if (isStatic()) {
896             data.setValue("class.static", "static");
897         }
898         if (isFinal()) {
899             data.setValue("class.final", "final");
900         }
901         if (isAbstract() && !isInterface()) {
902             data.setValue("class.abstract", "abstract");
903         }
904
905         // class info
906         String kind = kind();
907         if (kind != null) {
908             data.setValue("class.kind", kind);
909         }
910
911         // the containing package -- note that this can be passed to type_link,
912         // but it also contains the list of all of the packages
913         containingPackage().makeClassLinkListHDF(data, "class.package");
914
915         // inheritance hierarchy
916         Vector<ClassInfo> superClasses = new Vector<ClassInfo>();
917         superClasses.add(this);
918         ClassInfo supr = superclass();
919         while (supr != null) {
920             superClasses.add(supr);
921             supr = supr.superclass();
922         }
923         n = superClasses.size();
924         for (i=0; i<n; i++) {
925             supr = superClasses.elementAt(n-i-1);
926
927             supr.asTypeInfo().makeQualifiedHDF(data, "class.inheritance." + i + ".class");
928             supr.asTypeInfo().makeHDF(data, "class.inheritance." + i + ".short_class");
929             j = 0;
930             for (TypeInfo t: supr.interfaceTypes()) {
931                 t.makeHDF(data, "class.inheritance." + i + ".interfaces." + j);
932                 j++;
933             }
934         }
935
936         // class description
937         TagInfo.makeHDF(data, "class.descr", inlineTags());
938         TagInfo.makeHDF(data, "class.seeAlso", comment().seeTags());
939         TagInfo.makeHDF(data, "class.deprecated", deprecatedTags());
940
941         // known subclasses
942         TreeMap<String, ClassInfo> direct = new TreeMap<String, ClassInfo>();
943         TreeMap<String, ClassInfo> indirect = new TreeMap<String, ClassInfo>();
944         ClassInfo[] all = Converter.rootClasses();
945         for (ClassInfo cl: all) {
946             if (cl.superclass() != null && cl.superclass().equals(this)) {
947                 direct.put(cl.name(), cl);
948             }
949             else if (cl.isDerivedFrom(this)) {
950                 indirect.put(cl.name(), cl);
951             }
952         }
953         // direct
954         i = 0;
955         for (ClassInfo cl: direct.values()) {
956             if (cl.checkLevel()) {
957                 cl.makeShortDescrHDF(data, "class.subclasses.direct." + i);
958             }
959             i++;
960         }
961         // indirect
962         i = 0;
963         for (ClassInfo cl: indirect.values()) {
964             if (cl.checkLevel()) {
965                 cl.makeShortDescrHDF(data, "class.subclasses.indirect." + i);
966             }
967             i++;
968         }
969
970         // nested classes
971         i=0;
972         for (ClassInfo inner: inners) {
973             if (inner.checkLevel()) {
974                 inner.makeShortDescrHDF(data, "class.inners." + i);
975             }
976             i++;
977         }
978
979         // enum constants
980         i=0;
981         for (FieldInfo field: enumConstants) {
982             if (field.isConstant()) {
983                 field.makeHDF(data, "class.enumConstants." + i);
984                 i++;
985             }
986         }
987
988         // constants
989         i=0;
990         for (FieldInfo field: fields) {
991             if (field.isConstant()) {
992                 field.makeHDF(data, "class.constants." + i);
993                 i++;
994             }
995         }
996
997         // fields
998         i=0;
999         for (FieldInfo field: fields) {
1000             if (!field.isConstant()) {
1001                 field.makeHDF(data, "class.fields." + i);
1002                 i++;
1003             }
1004         }
1005
1006         // public constructors
1007         i=0;
1008         for (MethodInfo ctor: ctors) {
1009             if (ctor.isPublic()) {
1010                 ctor.makeHDF(data, "class.ctors.public." + i);
1011                 i++;
1012             }
1013         }
1014
1015         // protected constructors
1016         if (DroidDoc.checkLevel(DroidDoc.SHOW_PROTECTED)) {
1017             i=0;
1018             for (MethodInfo ctor: ctors) {
1019                 if (ctor.isProtected()) {
1020                     ctor.makeHDF(data, "class.ctors.protected." + i);
1021                     i++;
1022                 }
1023             }
1024         }
1025
1026         // package private constructors
1027         if (DroidDoc.checkLevel(DroidDoc.SHOW_PACKAGE)) {
1028             i=0;
1029             for (MethodInfo ctor: ctors) {
1030                 if (ctor.isPackagePrivate()) {
1031                     ctor.makeHDF(data, "class.ctors.package." + i);
1032                     i++;
1033                 }
1034             }
1035         }
1036
1037         // private constructors
1038         if (DroidDoc.checkLevel(DroidDoc.SHOW_PRIVATE)) {
1039             i=0;
1040             for (MethodInfo ctor: ctors) {
1041                 if (ctor.isPrivate()) {
1042                     ctor.makeHDF(data, "class.ctors.private." + i);
1043                     i++;
1044                 }
1045             }
1046         }
1047
1048         // public methods
1049         i=0;
1050         for (MethodInfo method: methods) {
1051             if (method.isPublic()) {
1052                 method.makeHDF(data, "class.methods.public." + i);
1053                 i++;
1054             }
1055         }
1056
1057         // protected methods
1058         if (DroidDoc.checkLevel(DroidDoc.SHOW_PROTECTED)) {
1059             i=0;
1060             for (MethodInfo method: methods) {
1061                 if (method.isProtected()) {
1062                     method.makeHDF(data, "class.methods.protected." + i);
1063                     i++;
1064                 }
1065             }
1066         }
1067
1068         // package private methods
1069         if (DroidDoc.checkLevel(DroidDoc.SHOW_PACKAGE)) {
1070             i=0;
1071             for (MethodInfo method: methods) {
1072                 if (method.isPackagePrivate()) {
1073                     method.makeHDF(data, "class.methods.package." + i);
1074                     i++;
1075                 }
1076             }
1077         }
1078
1079         // private methods
1080         if (DroidDoc.checkLevel(DroidDoc.SHOW_PRIVATE)) {
1081             i=0;
1082             for (MethodInfo method: methods) {
1083                 if (method.isPrivate()) {
1084                     method.makeHDF(data, "class.methods.private." + i);
1085                     i++;
1086                 }
1087             }
1088         }
1089
1090         // xml attributes
1091         i=0;
1092         for (AttributeInfo attr: selfAttributes) {
1093             if (attr.checkLevel()) {
1094                 attr.makeHDF(data, "class.attrs." + i);
1095                 i++;
1096             }
1097         }
1098
1099         // inherited methods
1100         Set<ClassInfo> interfaces = new TreeSet<ClassInfo>();
1101         addInterfaces(interfaces(), interfaces);
1102         ClassInfo cl = superclass();
1103         i=0;
1104         while (cl != null) {
1105             addInterfaces(cl.interfaces(), interfaces);
1106             makeInheritedHDF(data, i, cl);
1107             cl = cl.superclass();
1108             i++;
1109         }
1110         for (ClassInfo iface: interfaces) {
1111             makeInheritedHDF(data, i, iface);
1112             i++;
1113         }
1114     }
1115
1116     private static void addInterfaces(ClassInfo[] ifaces, Set<ClassInfo> out)
1117     {
1118         for (ClassInfo cl: ifaces) {
1119             out.add(cl);
1120             addInterfaces(cl.interfaces(), out);
1121         }
1122     }
1123
1124     private static void makeInheritedHDF(HDF data, int index, ClassInfo cl)
1125     {
1126         int i;
1127
1128         String base = "class.inherited." + index;
1129         data.setValue(base + ".qualified", cl.qualifiedName());
1130         if (cl.checkLevel()) {
1131             data.setValue(base + ".link", cl.htmlPage());
1132         }
1133         String kind = cl.kind();
1134         if (kind != null) {
1135             data.setValue(base + ".kind", kind);
1136         }
1137         
1138         // xml attributes
1139         i=0;
1140         for (AttributeInfo attr: cl.selfAttributes()) {
1141             attr.makeHDF(data, base + ".attrs." + i);
1142             i++;
1143         }
1144
1145         // methods
1146         i=0;
1147         for (MethodInfo method: cl.selfMethods()) {
1148             method.makeHDF(data, base + ".methods." + i);
1149             i++;
1150         }
1151
1152         // fields
1153         i=0;
1154         for (FieldInfo field: cl.selfFields()) {
1155             if (!field.isConstant()) {
1156                 field.makeHDF(data, base + ".fields." + i);
1157                 i++;
1158             }
1159         }
1160
1161         // constants
1162         i=0;
1163         for (FieldInfo field: cl.selfFields()) {
1164             if (field.isConstant()) {
1165                 field.makeHDF(data, base + ".constants." + i);
1166                 i++;
1167             }
1168         }
1169     }
1170
1171     public boolean isHidden()
1172     {
1173         int val = mHidden;
1174         if (val >= 0) {
1175             return val != 0;
1176         } else {
1177             boolean v = isHiddenImpl();
1178             mHidden = v ? 1 : 0;
1179             return v;
1180         }
1181     }
1182
1183     public boolean isHiddenImpl()
1184     {
1185         ClassInfo cl = this;
1186         while (cl != null) {
1187             PackageInfo pkg = cl.containingPackage();
1188             if (pkg != null && pkg.isHidden()) {
1189                 return true;
1190             }
1191             if (cl.comment().isHidden()) {
1192                 return true;
1193             }
1194             cl = cl.containingClass();
1195         }
1196         return false;
1197     }
1198
1199     private MethodInfo matchMethod(MethodInfo[] methods, String name,
1200                                     String[] params, String[] dimensions)
1201     {
1202         int len = methods.length;
1203         for (int i=0; i<len; i++) {
1204             MethodInfo method = methods[i];
1205             if (method.name().equals(name)) {
1206                 if (params == null) {
1207                     return method;
1208                 } else {
1209                     if (method.matchesParams(params, dimensions)) {
1210                         return method;
1211                     }
1212                 }
1213             }
1214         }
1215         return null;
1216     }
1217
1218     public MethodInfo findMethod(String name,
1219                                     String[] params, String[] dimensions)
1220     {
1221         // first look on our class, and our superclasses
1222
1223         // for methods
1224         MethodInfo rv;
1225         rv = matchMethod(methods(), name, params, dimensions);
1226
1227         if (rv != null) {
1228             return rv;
1229         }
1230
1231         // for constructors
1232         rv = matchMethod(constructors(), name, params, dimensions);
1233         if (rv != null) {
1234             return rv;
1235         }
1236
1237         // then recursively look at our containing class
1238         ClassInfo containing = containingClass();
1239         if (containing != null) {
1240             return containing.findMethod(name, params, dimensions);
1241         }
1242
1243         return null;
1244     }
1245
1246     private ClassInfo searchInnerClasses(String[] nameParts, int index)
1247     {
1248         String part = nameParts[index];
1249
1250         ClassInfo[] inners = mInnerClasses;
1251         for (ClassInfo in: inners) {
1252             String[] innerParts = in.nameParts();
1253             if (part.equals(innerParts[innerParts.length-1])) {
1254                 if (index == nameParts.length-1) {
1255                     return in;
1256                 } else {
1257                     return in.searchInnerClasses(nameParts, index+1);
1258                 }
1259             }
1260         }
1261         return null;
1262     }
1263
1264     public ClassInfo extendedFindClass(String className)
1265     {
1266         // ClassDoc.findClass has this bug that we're working around here:
1267         // If you have a class PackageManager with an inner class PackageInfo
1268         // and you call it with "PackageInfo" it doesn't find it.
1269         return searchInnerClasses(className.split("\\."), 0);
1270     }
1271
1272     public ClassInfo findClass(String className)
1273     {
1274         return Converter.obtainClass(mClass.findClass(className));
1275     }
1276
1277     public ClassInfo findInnerClass(String className)
1278     {
1279         // ClassDoc.findClass won't find inner classes.  To deal with that,
1280         // we try what they gave us first, but if that didn't work, then
1281         // we see if there are any periods in className, and start searching
1282         // from there.
1283         String[] nodes = className.split("\\.");
1284         ClassDoc cl = mClass;
1285         for (String n: nodes) {
1286             cl = cl.findClass(n);
1287             if (cl == null) {
1288                 return null;
1289             }
1290         }
1291         return Converter.obtainClass(cl);
1292     }
1293
1294     public FieldInfo findField(String name)
1295     {
1296         // first look on our class, and our superclasses
1297         for (FieldInfo f: fields()) {
1298             if (f.name().equals(name)) {
1299                 return f;
1300             }
1301         }
1302         
1303         // then look at our enum constants (these are really fields, maybe
1304         // they should be mixed into fields().  not sure)
1305         for (FieldInfo f: enumConstants()) {
1306             if (f.name().equals(name)) {
1307                 return f;
1308             }
1309         }
1310
1311         // then recursively look at our containing class
1312         ClassInfo containing = containingClass();
1313         if (containing != null) {
1314             return containing.findField(name);
1315         }
1316
1317         return null;
1318     }
1319
1320     public static ClassInfo[] sortByName(ClassInfo[] classes)
1321     {
1322         int i;
1323         Sorter[] sorted = new Sorter[classes.length];
1324         for (i=0; i<sorted.length; i++) {
1325             ClassInfo cl = classes[i];
1326             sorted[i] = new Sorter(cl.name(), cl);
1327         }
1328
1329         Arrays.sort(sorted);
1330
1331         ClassInfo[] rv = new ClassInfo[classes.length];
1332         for (i=0; i<rv.length; i++) {
1333             rv[i] = (ClassInfo)sorted[i].data;
1334         }
1335
1336         return rv;
1337     }
1338
1339     public boolean equals(ClassInfo that)
1340     {
1341         if (that != null) {
1342             return this.qualifiedName().equals(that.qualifiedName());
1343         } else {
1344             return false;
1345         }
1346     }
1347     
1348     public void setNonWrittenConstructors(MethodInfo[] nonWritten) {
1349         mNonWrittenConstructors = nonWritten;
1350     }
1351     
1352     public MethodInfo[] getNonWrittenConstructors() {
1353         return mNonWrittenConstructors;
1354     }
1355
1356     public String kind()
1357     {
1358         if (isOrdinaryClass()) {
1359             return "class";
1360         }
1361         else if (isInterface()) {
1362             return "interface";
1363         }
1364         else if (isEnum()) {
1365             return "enum";
1366         }
1367         else if (isError()) {
1368             return "class";
1369         }
1370         else if (isException()) {
1371             return "class";
1372         }
1373         else if (isAnnotation()) {
1374             return "@interface";
1375         }
1376         return null;
1377     }
1378     
1379     public void setHiddenMethods(MethodInfo[] mInfo){
1380         mHiddenMethods = mInfo;
1381     }
1382     public MethodInfo[] getHiddenMethods(){
1383         return mHiddenMethods;
1384     }
1385     public String toString(){
1386         return this.qualifiedName();
1387     }
1388     
1389     public void setReasonIncluded(String reason) {
1390         mReasonIncluded = reason;
1391     }
1392     
1393     public String getReasonIncluded() {
1394         return mReasonIncluded; 
1395     }
1396
1397     private ClassDoc mClass;
1398
1399     // ctor
1400     private boolean mIsPublic;
1401     private boolean mIsProtected;
1402     private boolean mIsPackagePrivate;
1403     private boolean mIsPrivate;
1404     private boolean mIsStatic;
1405     private boolean mIsInterface;
1406     private boolean mIsAbstract;
1407     private boolean mIsOrdinaryClass;
1408     private boolean mIsException;
1409     private boolean mIsError;
1410     private boolean mIsEnum;
1411     private boolean mIsAnnotation;
1412     private boolean mIsFinal;
1413     private boolean mIsIncluded;
1414     private String mName;
1415     private String mQualifiedName;
1416     private String mQualifiedTypeName;
1417     private boolean mIsPrimitive;
1418     private TypeInfo mTypeInfo;
1419     private String[] mNameParts;
1420
1421     // init
1422     private ClassInfo[] mRealInterfaces;
1423     private ClassInfo[] mInterfaces;
1424     private TypeInfo[] mRealInterfaceTypes;
1425     private ClassInfo[] mInnerClasses;
1426     private MethodInfo[] mAllConstructors;
1427     private MethodInfo[] mAllSelfMethods;
1428     private MethodInfo[] mAnnotationElements; // if this class is an annotation
1429     private FieldInfo[] mAllSelfFields;
1430     private FieldInfo[] mEnumConstants;
1431     private PackageInfo mContainingPackage;
1432     private ClassInfo mContainingClass;
1433     private ClassInfo mRealSuperclass;
1434     private TypeInfo mRealSuperclassType;
1435     private ClassInfo mSuperclass;
1436     private AnnotationInstanceInfo[] mAnnotations;
1437     private boolean mSuperclassInit;
1438     private boolean mDeprecatedKnown;
1439
1440     // lazy
1441     private MethodInfo[] mConstructors;
1442     private ClassInfo[] mRealInnerClasses;
1443     private MethodInfo[] mSelfMethods;
1444     private FieldInfo[] mSelfFields;
1445     private AttributeInfo[] mSelfAttributes;
1446     private MethodInfo[] mMethods;
1447     private FieldInfo[] mFields;
1448     private TypeInfo[] mTypeParameters;
1449     private MethodInfo[] mHiddenMethods;
1450     private int mHidden = -1;
1451     private int mCheckLevel = -1;
1452     private String mReasonIncluded;
1453     private MethodInfo[] mNonWrittenConstructors;
1454     private boolean mIsDeprecated;
1455 }