OSDN Git Service

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