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