OSDN Git Service

am 7ebafd5a: Merge change 9009 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         data.setValue("class.since", getSince());
911
912         // the containing package -- note that this can be passed to type_link,
913         // but it also contains the list of all of the packages
914         containingPackage().makeClassLinkListHDF(data, "class.package");
915
916         // inheritance hierarchy
917         Vector<ClassInfo> superClasses = new Vector<ClassInfo>();
918         superClasses.add(this);
919         ClassInfo supr = superclass();
920         while (supr != null) {
921             superClasses.add(supr);
922             supr = supr.superclass();
923         }
924         n = superClasses.size();
925         for (i=0; i<n; i++) {
926             supr = superClasses.elementAt(n-i-1);
927
928             supr.asTypeInfo().makeQualifiedHDF(data, "class.inheritance." + i + ".class");
929             supr.asTypeInfo().makeHDF(data, "class.inheritance." + i + ".short_class");
930             j = 0;
931             for (TypeInfo t: supr.interfaceTypes()) {
932                 t.makeHDF(data, "class.inheritance." + i + ".interfaces." + j);
933                 j++;
934             }
935         }
936
937         // class description
938         TagInfo.makeHDF(data, "class.descr", inlineTags());
939         TagInfo.makeHDF(data, "class.seeAlso", comment().seeTags());
940         TagInfo.makeHDF(data, "class.deprecated", deprecatedTags());
941
942         // known subclasses
943         TreeMap<String, ClassInfo> direct = new TreeMap<String, ClassInfo>();
944         TreeMap<String, ClassInfo> indirect = new TreeMap<String, ClassInfo>();
945         ClassInfo[] all = Converter.rootClasses();
946         for (ClassInfo cl: all) {
947             if (cl.superclass() != null && cl.superclass().equals(this)) {
948                 direct.put(cl.name(), cl);
949             }
950             else if (cl.isDerivedFrom(this)) {
951                 indirect.put(cl.name(), cl);
952             }
953         }
954         // direct
955         i = 0;
956         for (ClassInfo cl: direct.values()) {
957             if (cl.checkLevel()) {
958                 cl.makeShortDescrHDF(data, "class.subclasses.direct." + i);
959             }
960             i++;
961         }
962         // indirect
963         i = 0;
964         for (ClassInfo cl: indirect.values()) {
965             if (cl.checkLevel()) {
966                 cl.makeShortDescrHDF(data, "class.subclasses.indirect." + i);
967             }
968             i++;
969         }
970
971         // nested classes
972         i=0;
973         for (ClassInfo inner: inners) {
974             if (inner.checkLevel()) {
975                 inner.makeShortDescrHDF(data, "class.inners." + i);
976             }
977             i++;
978         }
979
980         // enum constants
981         i=0;
982         for (FieldInfo field: enumConstants) {
983             if (field.isConstant()) {
984                 field.makeHDF(data, "class.enumConstants." + i);
985                 i++;
986             }
987         }
988
989         // constants
990         i=0;
991         for (FieldInfo field: fields) {
992             if (field.isConstant()) {
993                 field.makeHDF(data, "class.constants." + i);
994                 i++;
995             }
996         }
997
998         // fields
999         i=0;
1000         for (FieldInfo field: fields) {
1001             if (!field.isConstant()) {
1002                 field.makeHDF(data, "class.fields." + i);
1003                 i++;
1004             }
1005         }
1006
1007         // public constructors
1008         i=0;
1009         for (MethodInfo ctor: ctors) {
1010             if (ctor.isPublic()) {
1011                 ctor.makeHDF(data, "class.ctors.public." + i);
1012                 i++;
1013             }
1014         }
1015
1016         // protected constructors
1017         if (DroidDoc.checkLevel(DroidDoc.SHOW_PROTECTED)) {
1018             i=0;
1019             for (MethodInfo ctor: ctors) {
1020                 if (ctor.isProtected()) {
1021                     ctor.makeHDF(data, "class.ctors.protected." + i);
1022                     i++;
1023                 }
1024             }
1025         }
1026
1027         // package private constructors
1028         if (DroidDoc.checkLevel(DroidDoc.SHOW_PACKAGE)) {
1029             i=0;
1030             for (MethodInfo ctor: ctors) {
1031                 if (ctor.isPackagePrivate()) {
1032                     ctor.makeHDF(data, "class.ctors.package." + i);
1033                     i++;
1034                 }
1035             }
1036         }
1037
1038         // private constructors
1039         if (DroidDoc.checkLevel(DroidDoc.SHOW_PRIVATE)) {
1040             i=0;
1041             for (MethodInfo ctor: ctors) {
1042                 if (ctor.isPrivate()) {
1043                     ctor.makeHDF(data, "class.ctors.private." + i);
1044                     i++;
1045                 }
1046             }
1047         }
1048
1049         // public methods
1050         i=0;
1051         for (MethodInfo method: methods) {
1052             if (method.isPublic()) {
1053                 method.makeHDF(data, "class.methods.public." + i);
1054                 i++;
1055             }
1056         }
1057
1058         // protected methods
1059         if (DroidDoc.checkLevel(DroidDoc.SHOW_PROTECTED)) {
1060             i=0;
1061             for (MethodInfo method: methods) {
1062                 if (method.isProtected()) {
1063                     method.makeHDF(data, "class.methods.protected." + i);
1064                     i++;
1065                 }
1066             }
1067         }
1068
1069         // package private methods
1070         if (DroidDoc.checkLevel(DroidDoc.SHOW_PACKAGE)) {
1071             i=0;
1072             for (MethodInfo method: methods) {
1073                 if (method.isPackagePrivate()) {
1074                     method.makeHDF(data, "class.methods.package." + i);
1075                     i++;
1076                 }
1077             }
1078         }
1079
1080         // private methods
1081         if (DroidDoc.checkLevel(DroidDoc.SHOW_PRIVATE)) {
1082             i=0;
1083             for (MethodInfo method: methods) {
1084                 if (method.isPrivate()) {
1085                     method.makeHDF(data, "class.methods.private." + i);
1086                     i++;
1087                 }
1088             }
1089         }
1090
1091         // xml attributes
1092         i=0;
1093         for (AttributeInfo attr: selfAttributes) {
1094             if (attr.checkLevel()) {
1095                 attr.makeHDF(data, "class.attrs." + i);
1096                 i++;
1097             }
1098         }
1099
1100         // inherited methods
1101         Set<ClassInfo> interfaces = new TreeSet<ClassInfo>();
1102         addInterfaces(interfaces(), interfaces);
1103         ClassInfo cl = superclass();
1104         i=0;
1105         while (cl != null) {
1106             addInterfaces(cl.interfaces(), interfaces);
1107             makeInheritedHDF(data, i, cl);
1108             cl = cl.superclass();
1109             i++;
1110         }
1111         for (ClassInfo iface: interfaces) {
1112             makeInheritedHDF(data, i, iface);
1113             i++;
1114         }
1115     }
1116
1117     private static void addInterfaces(ClassInfo[] ifaces, Set<ClassInfo> out)
1118     {
1119         for (ClassInfo cl: ifaces) {
1120             out.add(cl);
1121             addInterfaces(cl.interfaces(), out);
1122         }
1123     }
1124
1125     private static void makeInheritedHDF(HDF data, int index, ClassInfo cl)
1126     {
1127         int i;
1128
1129         String base = "class.inherited." + index;
1130         data.setValue(base + ".qualified", cl.qualifiedName());
1131         if (cl.checkLevel()) {
1132             data.setValue(base + ".link", cl.htmlPage());
1133         }
1134         String kind = cl.kind();
1135         if (kind != null) {
1136             data.setValue(base + ".kind", kind);
1137         }
1138         
1139         // xml attributes
1140         i=0;
1141         for (AttributeInfo attr: cl.selfAttributes()) {
1142             attr.makeHDF(data, base + ".attrs." + i);
1143             i++;
1144         }
1145
1146         // methods
1147         i=0;
1148         for (MethodInfo method: cl.selfMethods()) {
1149             method.makeHDF(data, base + ".methods." + i);
1150             i++;
1151         }
1152
1153         // fields
1154         i=0;
1155         for (FieldInfo field: cl.selfFields()) {
1156             if (!field.isConstant()) {
1157                 field.makeHDF(data, base + ".fields." + i);
1158                 i++;
1159             }
1160         }
1161
1162         // constants
1163         i=0;
1164         for (FieldInfo field: cl.selfFields()) {
1165             if (field.isConstant()) {
1166                 field.makeHDF(data, base + ".constants." + i);
1167                 i++;
1168             }
1169         }
1170     }
1171
1172     public boolean isHidden()
1173     {
1174         int val = mHidden;
1175         if (val >= 0) {
1176             return val != 0;
1177         } else {
1178             boolean v = isHiddenImpl();
1179             mHidden = v ? 1 : 0;
1180             return v;
1181         }
1182     }
1183
1184     public boolean isHiddenImpl()
1185     {
1186         ClassInfo cl = this;
1187         while (cl != null) {
1188             PackageInfo pkg = cl.containingPackage();
1189             if (pkg != null && pkg.isHidden()) {
1190                 return true;
1191             }
1192             if (cl.comment().isHidden()) {
1193                 return true;
1194             }
1195             cl = cl.containingClass();
1196         }
1197         return false;
1198     }
1199
1200     private MethodInfo matchMethod(MethodInfo[] methods, String name,
1201                                     String[] params, String[] dimensions)
1202     {
1203         int len = methods.length;
1204         for (int i=0; i<len; i++) {
1205             MethodInfo method = methods[i];
1206             if (method.name().equals(name)) {
1207                 if (params == null) {
1208                     return method;
1209                 } else {
1210                     if (method.matchesParams(params, dimensions)) {
1211                         return method;
1212                     }
1213                 }
1214             }
1215         }
1216         return null;
1217     }
1218
1219     public MethodInfo findMethod(String name,
1220                                     String[] params, String[] dimensions)
1221     {
1222         // first look on our class, and our superclasses
1223
1224         // for methods
1225         MethodInfo rv;
1226         rv = matchMethod(methods(), name, params, dimensions);
1227
1228         if (rv != null) {
1229             return rv;
1230         }
1231
1232         // for constructors
1233         rv = matchMethod(constructors(), name, params, dimensions);
1234         if (rv != null) {
1235             return rv;
1236         }
1237
1238         // then recursively look at our containing class
1239         ClassInfo containing = containingClass();
1240         if (containing != null) {
1241             return containing.findMethod(name, params, dimensions);
1242         }
1243
1244         return null;
1245     }
1246
1247     private ClassInfo searchInnerClasses(String[] nameParts, int index)
1248     {
1249         String part = nameParts[index];
1250
1251         ClassInfo[] inners = mInnerClasses;
1252         for (ClassInfo in: inners) {
1253             String[] innerParts = in.nameParts();
1254             if (part.equals(innerParts[innerParts.length-1])) {
1255                 if (index == nameParts.length-1) {
1256                     return in;
1257                 } else {
1258                     return in.searchInnerClasses(nameParts, index+1);
1259                 }
1260             }
1261         }
1262         return null;
1263     }
1264
1265     public ClassInfo extendedFindClass(String className)
1266     {
1267         // ClassDoc.findClass has this bug that we're working around here:
1268         // If you have a class PackageManager with an inner class PackageInfo
1269         // and you call it with "PackageInfo" it doesn't find it.
1270         return searchInnerClasses(className.split("\\."), 0);
1271     }
1272
1273     public ClassInfo findClass(String className)
1274     {
1275         return Converter.obtainClass(mClass.findClass(className));
1276     }
1277
1278     public ClassInfo findInnerClass(String className)
1279     {
1280         // ClassDoc.findClass won't find inner classes.  To deal with that,
1281         // we try what they gave us first, but if that didn't work, then
1282         // we see if there are any periods in className, and start searching
1283         // from there.
1284         String[] nodes = className.split("\\.");
1285         ClassDoc cl = mClass;
1286         for (String n: nodes) {
1287             cl = cl.findClass(n);
1288             if (cl == null) {
1289                 return null;
1290             }
1291         }
1292         return Converter.obtainClass(cl);
1293     }
1294
1295     public FieldInfo findField(String name)
1296     {
1297         // first look on our class, and our superclasses
1298         for (FieldInfo f: fields()) {
1299             if (f.name().equals(name)) {
1300                 return f;
1301             }
1302         }
1303         
1304         // then look at our enum constants (these are really fields, maybe
1305         // they should be mixed into fields().  not sure)
1306         for (FieldInfo f: enumConstants()) {
1307             if (f.name().equals(name)) {
1308                 return f;
1309             }
1310         }
1311
1312         // then recursively look at our containing class
1313         ClassInfo containing = containingClass();
1314         if (containing != null) {
1315             return containing.findField(name);
1316         }
1317
1318         return null;
1319     }
1320
1321     public static ClassInfo[] sortByName(ClassInfo[] classes)
1322     {
1323         int i;
1324         Sorter[] sorted = new Sorter[classes.length];
1325         for (i=0; i<sorted.length; i++) {
1326             ClassInfo cl = classes[i];
1327             sorted[i] = new Sorter(cl.name(), cl);
1328         }
1329
1330         Arrays.sort(sorted);
1331
1332         ClassInfo[] rv = new ClassInfo[classes.length];
1333         for (i=0; i<rv.length; i++) {
1334             rv[i] = (ClassInfo)sorted[i].data;
1335         }
1336
1337         return rv;
1338     }
1339
1340     public boolean equals(ClassInfo that)
1341     {
1342         if (that != null) {
1343             return this.qualifiedName().equals(that.qualifiedName());
1344         } else {
1345             return false;
1346         }
1347     }
1348     
1349     public void setNonWrittenConstructors(MethodInfo[] nonWritten) {
1350         mNonWrittenConstructors = nonWritten;
1351     }
1352     
1353     public MethodInfo[] getNonWrittenConstructors() {
1354         return mNonWrittenConstructors;
1355     }
1356
1357     public String kind()
1358     {
1359         if (isOrdinaryClass()) {
1360             return "class";
1361         }
1362         else if (isInterface()) {
1363             return "interface";
1364         }
1365         else if (isEnum()) {
1366             return "enum";
1367         }
1368         else if (isError()) {
1369             return "class";
1370         }
1371         else if (isException()) {
1372             return "class";
1373         }
1374         else if (isAnnotation()) {
1375             return "@interface";
1376         }
1377         return null;
1378     }
1379     
1380     public void setHiddenMethods(MethodInfo[] mInfo){
1381         mHiddenMethods = mInfo;
1382     }
1383     public MethodInfo[] getHiddenMethods(){
1384         return mHiddenMethods;
1385     }
1386     public String toString(){
1387         return this.qualifiedName();
1388     }
1389     
1390     public void setReasonIncluded(String reason) {
1391         mReasonIncluded = reason;
1392     }
1393     
1394     public String getReasonIncluded() {
1395         return mReasonIncluded; 
1396     }
1397
1398     private ClassDoc mClass;
1399
1400     // ctor
1401     private boolean mIsPublic;
1402     private boolean mIsProtected;
1403     private boolean mIsPackagePrivate;
1404     private boolean mIsPrivate;
1405     private boolean mIsStatic;
1406     private boolean mIsInterface;
1407     private boolean mIsAbstract;
1408     private boolean mIsOrdinaryClass;
1409     private boolean mIsException;
1410     private boolean mIsError;
1411     private boolean mIsEnum;
1412     private boolean mIsAnnotation;
1413     private boolean mIsFinal;
1414     private boolean mIsIncluded;
1415     private String mName;
1416     private String mQualifiedName;
1417     private String mQualifiedTypeName;
1418     private boolean mIsPrimitive;
1419     private TypeInfo mTypeInfo;
1420     private String[] mNameParts;
1421
1422     // init
1423     private ClassInfo[] mRealInterfaces;
1424     private ClassInfo[] mInterfaces;
1425     private TypeInfo[] mRealInterfaceTypes;
1426     private ClassInfo[] mInnerClasses;
1427     private MethodInfo[] mAllConstructors;
1428     private MethodInfo[] mAllSelfMethods;
1429     private MethodInfo[] mAnnotationElements; // if this class is an annotation
1430     private FieldInfo[] mAllSelfFields;
1431     private FieldInfo[] mEnumConstants;
1432     private PackageInfo mContainingPackage;
1433     private ClassInfo mContainingClass;
1434     private ClassInfo mRealSuperclass;
1435     private TypeInfo mRealSuperclassType;
1436     private ClassInfo mSuperclass;
1437     private AnnotationInstanceInfo[] mAnnotations;
1438     private boolean mSuperclassInit;
1439     private boolean mDeprecatedKnown;
1440
1441     // lazy
1442     private MethodInfo[] mConstructors;
1443     private ClassInfo[] mRealInnerClasses;
1444     private MethodInfo[] mSelfMethods;
1445     private FieldInfo[] mSelfFields;
1446     private AttributeInfo[] mSelfAttributes;
1447     private MethodInfo[] mMethods;
1448     private FieldInfo[] mFields;
1449     private TypeInfo[] mTypeParameters;
1450     private MethodInfo[] mHiddenMethods;
1451     private int mHidden = -1;
1452     private int mCheckLevel = -1;
1453     private String mReasonIncluded;
1454     private MethodInfo[] mNonWrittenConstructors;
1455     private boolean mIsDeprecated;
1456 }