• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 Google Inc.
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 package com.google.doclava;
18 
19 import com.google.clearsilver.jsilver.data.Data;
20 import com.sun.javadoc.ClassDoc;
21 
22 import java.util.ArrayList;
23 import java.util.Arrays;
24 import java.util.Collections;
25 import java.util.Comparator;
26 import java.util.HashMap;
27 import java.util.HashSet;
28 import java.util.List;
29 import java.util.Map;
30 import java.util.Set;
31 import java.util.TreeMap;
32 import java.util.TreeSet;
33 import java.util.Vector;
34 
35 public class ClassInfo extends DocInfo implements ContainerInfo, Comparable, Scoped, Resolvable {
36   public static final Comparator<ClassInfo> comparator = new Comparator<ClassInfo>() {
37     public int compare(ClassInfo a, ClassInfo b) {
38       return a.name().compareTo(b.name());
39     }
40   };
41 
42   public static final Comparator<ClassInfo> qualifiedComparator = new Comparator<ClassInfo>() {
43     public int compare(ClassInfo a, ClassInfo b) {
44       return a.qualifiedName().compareTo(b.qualifiedName());
45     }
46   };
47 
48   /**
49    * Constructs a stub representation of a class.
50    */
ClassInfo(String qualifiedName)51   public ClassInfo(String qualifiedName) {
52     super("", SourcePositionInfo.UNKNOWN);
53     mQualifiedName = qualifiedName;
54     if (qualifiedName.lastIndexOf('.') != -1) {
55       mName = qualifiedName.substring(qualifiedName.lastIndexOf('.') + 1);
56     } else {
57       mName = qualifiedName;
58     }
59   }
60 
ClassInfo(ClassDoc cl, String rawCommentText, SourcePositionInfo position, boolean isPublic, boolean isProtected, boolean isPackagePrivate, boolean isPrivate, boolean isStatic, boolean isInterface, boolean isAbstract, boolean isOrdinaryClass, boolean isException, boolean isError, boolean isEnum, boolean isAnnotation, boolean isFinal, boolean isIncluded, String name, String qualifiedName, String qualifiedTypeName, boolean isPrimitive)61   public ClassInfo(ClassDoc cl, String rawCommentText, SourcePositionInfo position,
62           boolean isPublic, boolean isProtected, boolean isPackagePrivate, boolean isPrivate,
63           boolean isStatic, boolean isInterface, boolean isAbstract, boolean isOrdinaryClass,
64           boolean isException, boolean isError, boolean isEnum, boolean isAnnotation, boolean isFinal,
65           boolean isIncluded, String name, String qualifiedName, String qualifiedTypeName,
66           boolean isPrimitive) {
67       super(rawCommentText, position);
68 
69       initialize(rawCommentText, position,
70               isPublic, isProtected, isPackagePrivate, isPrivate,
71               isStatic, isInterface, isAbstract, isOrdinaryClass,
72               isException, isError, isEnum, isAnnotation, isFinal,
73               isIncluded, qualifiedTypeName, isPrimitive, null);
74 
75       mName = name;
76       mQualifiedName = qualifiedName;
77       mNameParts = name.split("\\.");
78       mClass = cl;
79   }
80 
initialize(String rawCommentText, SourcePositionInfo position, boolean isPublic, boolean isProtected, boolean isPackagePrivate, boolean isPrivate, boolean isStatic, boolean isInterface, boolean isAbstract, boolean isOrdinaryClass, boolean isException, boolean isError, boolean isEnum, boolean isAnnotation, boolean isFinal, boolean isIncluded, String qualifiedTypeName, boolean isPrimitive, ArrayList<AnnotationInstanceInfo> annotations)81   public void initialize(String rawCommentText, SourcePositionInfo position,
82           boolean isPublic, boolean isProtected, boolean isPackagePrivate, boolean isPrivate,
83           boolean isStatic, boolean isInterface, boolean isAbstract, boolean isOrdinaryClass,
84           boolean isException, boolean isError, boolean isEnum, boolean isAnnotation, boolean isFinal,
85           boolean isIncluded, String qualifiedTypeName, boolean isPrimitive, ArrayList<AnnotationInstanceInfo> annotations) {
86 
87     // calls
88     setPosition(position);
89     setRawCommentText(rawCommentText);
90     mIsPublic = isPublic;
91     mIsProtected = isProtected;
92     mIsPackagePrivate = isPackagePrivate;
93     mIsPrivate = isPrivate;
94     mIsStatic = isStatic;
95     mIsInterface = isInterface;
96     mIsAbstract = isAbstract;
97     mIsOrdinaryClass = isOrdinaryClass;
98     mIsException = isException;
99     mIsError = isError;
100     mIsEnum = isEnum;
101     mIsAnnotation = isAnnotation;
102     mIsFinal = isFinal;
103     mIsIncluded = isIncluded;
104     mQualifiedTypeName = qualifiedTypeName;
105     mIsPrimitive = isPrimitive;
106     mAnnotations = annotations;
107   }
108 
init(TypeInfo typeInfo, ArrayList<ClassInfo> interfaces, ArrayList<TypeInfo> interfaceTypes, ArrayList<ClassInfo> innerClasses, ArrayList<MethodInfo> constructors, ArrayList<MethodInfo> methods, ArrayList<MethodInfo> annotationElements, ArrayList<FieldInfo> fields, ArrayList<FieldInfo> enumConstants, PackageInfo containingPackage, ClassInfo containingClass, ClassInfo superclass, TypeInfo superclassType, ArrayList<AnnotationInstanceInfo> annotations)109   public void init(TypeInfo typeInfo, ArrayList<ClassInfo> interfaces,
110           ArrayList<TypeInfo> interfaceTypes, ArrayList<ClassInfo> innerClasses,
111           ArrayList<MethodInfo> constructors, ArrayList<MethodInfo> methods,
112           ArrayList<MethodInfo> annotationElements, ArrayList<FieldInfo> fields,
113           ArrayList<FieldInfo> enumConstants, PackageInfo containingPackage,
114           ClassInfo containingClass, ClassInfo superclass,
115       TypeInfo superclassType, ArrayList<AnnotationInstanceInfo> annotations) {
116     mTypeInfo = typeInfo;
117     mRealInterfaces = new ArrayList<ClassInfo>(interfaces);
118     mRealInterfaceTypes = interfaceTypes;
119     mInnerClasses = innerClasses;
120     mAllConstructors = constructors;
121     mAllSelfMethods = methods;
122     mAnnotationElements = annotationElements;
123     mAllSelfFields = fields;
124     mEnumConstants = enumConstants;
125     mContainingPackage = containingPackage;
126     mContainingClass = containingClass;
127     mRealSuperclass = superclass;
128     mRealSuperclassType = superclassType;
129     mAnnotations = annotations;
130 
131     // after providing new methods and new superclass info,clear any cached
132     // lists of self + superclass methods, ctors, etc.
133     mSuperclassInit = false;
134     mConstructors = null;
135     mMethods = null;
136     mSelfMethods = null;
137     mFields = null;
138     mSelfFields = null;
139     mSelfAttributes = null;
140     mDeprecatedKnown = false;
141 
142     Collections.sort(mEnumConstants, FieldInfo.comparator);
143     Collections.sort(mInnerClasses, ClassInfo.comparator);
144   }
145 
init2()146   public void init2() {
147     // calling this here forces the AttrTagInfo objects to be linked to the AttribtueInfo
148     // objects
149     selfAttributes();
150   }
151 
init3(ArrayList<TypeInfo> types, ArrayList<ClassInfo> realInnerClasses)152   public void init3(ArrayList<TypeInfo> types, ArrayList<ClassInfo> realInnerClasses) {
153     mTypeParameters = types;
154     mRealInnerClasses = realInnerClasses;
155   }
156 
getRealInnerClasses()157   public ArrayList<ClassInfo> getRealInnerClasses() {
158     return mRealInnerClasses;
159   }
160 
getTypeParameters()161   public ArrayList<TypeInfo> getTypeParameters() {
162     return mTypeParameters;
163   }
164 
checkLevel()165   public boolean checkLevel() {
166     int val = mCheckLevel;
167     if (val >= 0) {
168       return val != 0;
169     } else {
170       boolean v =
171           Doclava.checkLevel(mIsPublic, mIsProtected, mIsPackagePrivate, mIsPrivate, isHidden());
172       mCheckLevel = v ? 1 : 0;
173       return v;
174     }
175   }
176 
compareTo(Object that)177   public int compareTo(Object that) {
178     if (that instanceof ClassInfo) {
179       return mQualifiedName.compareTo(((ClassInfo) that).mQualifiedName);
180     } else {
181       return this.hashCode() - that.hashCode();
182     }
183   }
184 
185   @Override
parent()186   public ContainerInfo parent() {
187     return this;
188   }
189 
isPublic()190   public boolean isPublic() {
191     return mIsPublic;
192   }
193 
isProtected()194   public boolean isProtected() {
195     return mIsProtected;
196   }
197 
isPackagePrivate()198   public boolean isPackagePrivate() {
199     return mIsPackagePrivate;
200   }
201 
isPrivate()202   public boolean isPrivate() {
203     return mIsPrivate;
204   }
205 
isStatic()206   public boolean isStatic() {
207     return mIsStatic;
208   }
209 
isInterface()210   public boolean isInterface() {
211     return mIsInterface;
212   }
213 
isAbstract()214   public boolean isAbstract() {
215     return mIsAbstract;
216   }
217 
containingPackage()218   public PackageInfo containingPackage() {
219     return mContainingPackage;
220   }
221 
containingClass()222   public ClassInfo containingClass() {
223     return mContainingClass;
224   }
225 
isOrdinaryClass()226   public boolean isOrdinaryClass() {
227     return mIsOrdinaryClass;
228   }
229 
isException()230   public boolean isException() {
231     return mIsException;
232   }
233 
isError()234   public boolean isError() {
235     return mIsError;
236   }
237 
isEnum()238   public boolean isEnum() {
239     return mIsEnum;
240   }
241 
isAnnotation()242   public boolean isAnnotation() {
243     return mIsAnnotation;
244   }
245 
isFinal()246   public boolean isFinal() {
247     return mIsFinal;
248   }
249 
isIncluded()250   public boolean isIncluded() {
251     return mIsIncluded;
252   }
253 
typeVariables()254   public HashSet<String> typeVariables() {
255     HashSet<String> result = TypeInfo.typeVariables(mTypeInfo.typeArguments());
256     ClassInfo cl = containingClass();
257     while (cl != null) {
258       ArrayList<TypeInfo> types = cl.asTypeInfo().typeArguments();
259       if (types != null) {
260         TypeInfo.typeVariables(types, result);
261       }
262       cl = cl.containingClass();
263     }
264     return result;
265   }
266 
gatherHiddenInterfaces(ClassInfo cl, HashSet<ClassInfo> interfaces)267   private static void gatherHiddenInterfaces(ClassInfo cl, HashSet<ClassInfo> interfaces) {
268     for (ClassInfo iface : cl.mRealInterfaces) {
269       if (iface.checkLevel()) {
270         interfaces.add(iface);
271       } else {
272         gatherHiddenInterfaces(iface, interfaces);
273       }
274     }
275   }
276 
interfaces()277   public ArrayList<ClassInfo> interfaces() {
278     if (mInterfaces == null) {
279       if (checkLevel()) {
280         HashSet<ClassInfo> interfaces = new HashSet<ClassInfo>();
281         ClassInfo superclass = mRealSuperclass;
282         while (superclass != null && !superclass.checkLevel()) {
283           gatherHiddenInterfaces(superclass, interfaces);
284           superclass = superclass.mRealSuperclass;
285         }
286         gatherHiddenInterfaces(this, interfaces);
287         mInterfaces = new ArrayList<ClassInfo>(interfaces);
288       } else {
289         // put something here in case someone uses it
290         mInterfaces = new ArrayList<ClassInfo>(mRealInterfaces);
291       }
292       Collections.sort(mInterfaces, ClassInfo.qualifiedComparator);
293     }
294     return mInterfaces;
295   }
296 
realInterfaces()297   public ArrayList<ClassInfo> realInterfaces() {
298     return mRealInterfaces;
299   }
300 
realInterfaceTypes()301   ArrayList<TypeInfo> realInterfaceTypes() {
302     return mRealInterfaceTypes;
303   }
304 
addInterfaceType(TypeInfo type)305   public void addInterfaceType(TypeInfo type) {
306       if (mRealInterfaceTypes == null) {
307           mRealInterfaceTypes = new ArrayList<TypeInfo>();
308       }
309 
310       mRealInterfaceTypes.add(type);
311   }
312 
name()313   public String name() {
314     return mName;
315   }
316 
nameParts()317   public String[] nameParts() {
318     return mNameParts;
319   }
320 
leafName()321   public String leafName() {
322     return mNameParts[mNameParts.length - 1];
323   }
324 
qualifiedName()325   public String qualifiedName() {
326     return mQualifiedName;
327   }
328 
qualifiedTypeName()329   public String qualifiedTypeName() {
330     return mQualifiedTypeName;
331   }
332 
isPrimitive()333   public boolean isPrimitive() {
334     return mIsPrimitive;
335   }
336 
allConstructors()337   public ArrayList<MethodInfo> allConstructors() {
338     return mAllConstructors;
339   }
340 
constructors()341   public ArrayList<MethodInfo> constructors() {
342     if (mConstructors == null) {
343       if (mAllConstructors == null) {
344         return new ArrayList<MethodInfo>();
345       }
346 
347       mConstructors = new ArrayList<MethodInfo>();
348       for (MethodInfo m : mAllConstructors) {
349         if (!m.isHidden()) {
350             mConstructors.add(m);
351         }
352       }
353 
354       Collections.sort(mConstructors, MethodInfo.comparator);
355     }
356     return mConstructors;
357   }
358 
innerClasses()359   public ArrayList<ClassInfo> innerClasses() {
360     return mInnerClasses;
361   }
362 
inlineTags()363   public TagInfo[] inlineTags() {
364     return comment().tags();
365   }
366 
firstSentenceTags()367   public TagInfo[] firstSentenceTags() {
368     return comment().briefTags();
369   }
370 
setDeprecated(boolean deprecated)371   public void setDeprecated(boolean deprecated) {
372     mDeprecatedKnown = true;
373     mIsDeprecated = deprecated;
374   }
375 
isDeprecated()376   public boolean isDeprecated() {
377     if (!mDeprecatedKnown) {
378       boolean commentDeprecated = comment().isDeprecated();
379       boolean annotationDeprecated = false;
380       for (AnnotationInstanceInfo annotation : annotations()) {
381         if (annotation.type().qualifiedName().equals("java.lang.Deprecated")) {
382           annotationDeprecated = true;
383           break;
384         }
385       }
386 
387       if (commentDeprecated != annotationDeprecated) {
388         Errors.error(Errors.DEPRECATION_MISMATCH, position(), "Class " + qualifiedName()
389             + ": @Deprecated annotation and @deprecated comment do not match");
390       }
391 
392       mIsDeprecated = commentDeprecated | annotationDeprecated;
393       mDeprecatedKnown = true;
394     }
395     return mIsDeprecated;
396   }
397 
deprecatedTags()398   public TagInfo[] deprecatedTags() {
399     // Should we also do the interfaces?
400     return comment().deprecatedTags();
401   }
402 
methods()403   public ArrayList<MethodInfo> methods() {
404       if (mMethods == null) {
405           TreeMap<String, MethodInfo> all = new TreeMap<String, MethodInfo>();
406 
407           ArrayList<ClassInfo> interfaces = interfaces();
408           for (ClassInfo iface : interfaces) {
409             if (iface != null) {
410               for (MethodInfo method : iface.methods()) {
411                 all.put(method.getHashableName(), method);
412               }
413             }
414           }
415 
416           ClassInfo superclass = superclass();
417           if (superclass != null) {
418             for (MethodInfo method : superclass.methods()) {
419                 all.put(method.getHashableName(), method);
420             }
421           }
422 
423           for (MethodInfo method : selfMethods()) {
424               all.put(method.getHashableName(), method);
425           }
426 
427           mMethods = new ArrayList<MethodInfo>(all.values());
428           Collections.sort(mMethods, MethodInfo.comparator);
429       }
430     return mMethods;
431   }
432 
annotationElements()433   public ArrayList<MethodInfo> annotationElements() {
434     return mAnnotationElements;
435   }
436 
annotations()437   public ArrayList<AnnotationInstanceInfo> annotations() {
438     return mAnnotations;
439   }
440 
addFields(ClassInfo cl, TreeMap<String, FieldInfo> all)441   private static void addFields(ClassInfo cl, TreeMap<String, FieldInfo> all) {
442     for (FieldInfo field : cl.fields()) {
443         all.put(field.name(), field);
444     }
445   }
446 
fields()447   public ArrayList<FieldInfo> fields() {
448     if (mFields == null) {
449       TreeMap<String, FieldInfo> all = new TreeMap<String, FieldInfo>();
450 
451       for (ClassInfo iface : interfaces()) {
452         addFields(iface, all);
453       }
454 
455       ClassInfo superclass = superclass();
456       if (superclass != null) {
457         addFields(superclass, all);
458       }
459 
460       for (FieldInfo field : selfFields()) {
461         if (!field.isHidden()) {
462             all.put(field.name(), field);
463         }
464       }
465 
466       mFields = new ArrayList<FieldInfo>(all.values());
467     }
468     return mFields;
469   }
470 
gatherFields(ClassInfo owner, ClassInfo cl, HashMap<String, FieldInfo> fields)471   public void gatherFields(ClassInfo owner, ClassInfo cl, HashMap<String, FieldInfo> fields) {
472     for (FieldInfo f : cl.selfFields()) {
473       if (f.checkLevel()) {
474         fields.put(f.name(), f.cloneForClass(owner));
475       }
476     }
477   }
478 
selfFields()479   public ArrayList<FieldInfo> selfFields() {
480     if (mSelfFields == null) {
481         HashMap<String, FieldInfo> fields = new HashMap<String, FieldInfo>();
482       // our hidden parents
483       if (mRealSuperclass != null && !mRealSuperclass.checkLevel()) {
484         gatherFields(this, mRealSuperclass, fields);
485       }
486       for (ClassInfo iface : mRealInterfaces) {
487         if (!iface.checkLevel()) {
488           gatherFields(this, iface, fields);
489         }
490       }
491 
492       for (FieldInfo f : mAllSelfFields) {
493           if (!f.isHidden()) {
494               fields.put(f.name(), f);
495           }
496       }
497 
498       mSelfFields = new ArrayList<FieldInfo>(fields.values());
499       Collections.sort(mSelfFields, FieldInfo.comparator);
500     }
501     return mSelfFields;
502   }
503 
allSelfFields()504   public ArrayList<FieldInfo> allSelfFields() {
505     return mAllSelfFields;
506   }
507 
gatherMethods(ClassInfo owner, ClassInfo cl, HashMap<String, MethodInfo> methods)508   private void gatherMethods(ClassInfo owner, ClassInfo cl, HashMap<String, MethodInfo> methods) {
509     for (MethodInfo m : cl.selfMethods()) {
510       if (m.checkLevel()) {
511         methods.put(m.name() + m.signature(), m.cloneForClass(owner));
512       }
513     }
514   }
515 
selfMethods()516   public ArrayList<MethodInfo> selfMethods() {
517     if (mSelfMethods == null) {
518         HashMap<String, MethodInfo> methods = new HashMap<String, MethodInfo>();
519       // our hidden parents
520       if (mRealSuperclass != null && !mRealSuperclass.checkLevel()) {
521         gatherMethods(this, mRealSuperclass, methods);
522       }
523       for (ClassInfo iface : mRealInterfaces) {
524         if (!iface.checkLevel()) {
525           gatherMethods(this, iface, methods);
526         }
527       }
528       // mine
529       if (mAllSelfMethods != null) {
530         for (MethodInfo m : mAllSelfMethods) {
531           if (m.checkLevel()) {
532               methods.put(m.name() + m.signature(), m);
533           }
534         }
535       }
536 
537       // sort it
538       mSelfMethods = new ArrayList<MethodInfo>(methods.values());
539       Collections.sort(mSelfMethods, MethodInfo.comparator);
540     }
541     return mSelfMethods;
542   }
543 
allSelfMethods()544   public ArrayList<MethodInfo> allSelfMethods() {
545     return mAllSelfMethods;
546   }
547 
addMethod(MethodInfo method)548   public void addMethod(MethodInfo method) {
549     mApiCheckMethods.put(method.getHashableName(), method);
550 
551     mAllSelfMethods.add(method);
552     mSelfMethods = null; // flush this, hopefully it hasn't been used yet.
553   }
554 
addAnnotationElement(MethodInfo method)555   public void addAnnotationElement(MethodInfo method) {
556       mAnnotationElements.add(method);
557   }
558 
setContainingPackage(PackageInfo pkg)559   public void setContainingPackage(PackageInfo pkg) {
560     mContainingPackage = pkg;
561 
562     if (mContainingPackage != null) {
563         if (mIsEnum) {
564             mContainingPackage.addEnum(this);
565         } else if (mIsInterface) {
566             mContainingPackage.addInterface(this);
567         } else {
568             mContainingPackage.addOrdinaryClass(this);
569         }
570     }
571   }
572 
selfAttributes()573   public ArrayList<AttributeInfo> selfAttributes() {
574     if (mSelfAttributes == null) {
575       TreeMap<FieldInfo, AttributeInfo> attrs = new TreeMap<FieldInfo, AttributeInfo>();
576 
577       // the ones in the class comment won't have any methods
578       for (AttrTagInfo tag : comment().attrTags()) {
579         FieldInfo field = tag.reference();
580         if (field != null) {
581           AttributeInfo attr = attrs.get(field);
582           if (attr == null) {
583             attr = new AttributeInfo(this, field);
584             attrs.put(field, attr);
585           }
586           tag.setAttribute(attr);
587         }
588       }
589 
590       // in the methods
591       for (MethodInfo m : selfMethods()) {
592         for (AttrTagInfo tag : m.comment().attrTags()) {
593           FieldInfo field = tag.reference();
594           if (field != null) {
595             AttributeInfo attr = attrs.get(field);
596             if (attr == null) {
597               attr = new AttributeInfo(this, field);
598               attrs.put(field, attr);
599             }
600             tag.setAttribute(attr);
601             attr.methods.add(m);
602           }
603         }
604       }
605 
606       // constructors too
607       for (MethodInfo m : constructors()) {
608         for (AttrTagInfo tag : m.comment().attrTags()) {
609           FieldInfo field = tag.reference();
610           if (field != null) {
611             AttributeInfo attr = attrs.get(field);
612             if (attr == null) {
613               attr = new AttributeInfo(this, field);
614               attrs.put(field, attr);
615             }
616             tag.setAttribute(attr);
617             attr.methods.add(m);
618           }
619         }
620       }
621 
622       mSelfAttributes = new ArrayList<AttributeInfo>(attrs.values());
623       Collections.sort(mSelfAttributes, AttributeInfo.comparator);
624     }
625     return mSelfAttributes;
626   }
627 
enumConstants()628   public ArrayList<FieldInfo> enumConstants() {
629     return mEnumConstants;
630   }
631 
superclass()632   public ClassInfo superclass() {
633     if (!mSuperclassInit) {
634       if (this.checkLevel()) {
635         // rearrange our little inheritance hierarchy, because we need to hide classes that
636         // don't pass checkLevel
637         ClassInfo superclass = mRealSuperclass;
638         while (superclass != null && !superclass.checkLevel()) {
639           superclass = superclass.mRealSuperclass;
640         }
641         mSuperclass = superclass;
642       } else {
643         mSuperclass = mRealSuperclass;
644       }
645     }
646     return mSuperclass;
647   }
648 
realSuperclass()649   public ClassInfo realSuperclass() {
650     return mRealSuperclass;
651   }
652 
653   /**
654    * always the real superclass, not the collapsed one we get through superclass(), also has the
655    * type parameter info if it's generic.
656    */
superclassType()657   public TypeInfo superclassType() {
658     return mRealSuperclassType;
659   }
660 
asTypeInfo()661   public TypeInfo asTypeInfo() {
662     return mTypeInfo;
663   }
664 
interfaceTypes()665   ArrayList<TypeInfo> interfaceTypes() {
666       ArrayList<TypeInfo> types = new ArrayList<TypeInfo>();
667       for (ClassInfo iface : interfaces()) {
668           types.add(iface.asTypeInfo());
669       }
670       return types;
671   }
672 
htmlPage()673   public String htmlPage() {
674     String s = containingPackage().name();
675     s = s.replace('.', '/');
676     s += '/';
677     s += name();
678     s += ".html";
679     s = Doclava.javadocDir + s;
680     return s;
681   }
682 
683   /** Even indirectly */
isDerivedFrom(ClassInfo cl)684   public boolean isDerivedFrom(ClassInfo cl) {
685     return isDerivedFrom(cl.qualifiedName());
686   }
687 
688   /** Even indirectly */
isDerivedFrom(String qualifiedName)689   public boolean isDerivedFrom(String qualifiedName) {
690     ClassInfo dad = this.superclass();
691     if (dad != null) {
692       if (dad.mQualifiedName.equals(qualifiedName)) {
693         return true;
694       } else {
695         if (dad.isDerivedFrom(qualifiedName)) {
696           return true;
697         }
698       }
699     }
700     for (ClassInfo iface : interfaces()) {
701       if (iface.mQualifiedName.equals(qualifiedName)) {
702         return true;
703       } else {
704         if (iface.isDerivedFrom(qualifiedName)) {
705           return true;
706         }
707       }
708     }
709     return false;
710   }
711 
makeKeywordEntries(List<KeywordEntry> keywords)712   public void makeKeywordEntries(List<KeywordEntry> keywords) {
713     if (!checkLevel()) {
714       return;
715     }
716 
717     String htmlPage = htmlPage();
718     String qualifiedName = qualifiedName();
719 
720     keywords.add(new KeywordEntry(name(), htmlPage, "class in " + containingPackage().name()));
721 
722     ArrayList<FieldInfo> fields = selfFields();
723     //ArrayList<FieldInfo> enumConstants = enumConstants();
724     ArrayList<MethodInfo> ctors = constructors();
725     ArrayList<MethodInfo> methods = selfMethods();
726 
727     // enum constants
728     for (FieldInfo field : enumConstants()) {
729       if (field.checkLevel()) {
730         keywords.add(new KeywordEntry(field.name(), htmlPage + "#" + field.anchor(),
731             "enum constant in " + qualifiedName));
732       }
733     }
734 
735     // constants
736     for (FieldInfo field : fields) {
737       if (field.isConstant() && field.checkLevel()) {
738         keywords.add(new KeywordEntry(field.name(), htmlPage + "#" + field.anchor(), "constant in "
739             + qualifiedName));
740       }
741     }
742 
743     // fields
744     for (FieldInfo field : fields) {
745       if (!field.isConstant() && field.checkLevel()) {
746         keywords.add(new KeywordEntry(field.name(), htmlPage + "#" + field.anchor(), "field in "
747             + qualifiedName));
748       }
749     }
750 
751     // public constructors
752     for (MethodInfo m : ctors) {
753       if (m.isPublic() && m.checkLevel()) {
754         keywords.add(new KeywordEntry(m.prettySignature(), htmlPage + "#" + m.anchor(),
755             "constructor in " + qualifiedName));
756       }
757     }
758 
759     // protected constructors
760     if (Doclava.checkLevel(Doclava.SHOW_PROTECTED)) {
761       for (MethodInfo m : ctors) {
762         if (m.isProtected() && m.checkLevel()) {
763           keywords.add(new KeywordEntry(m.prettySignature(),
764               htmlPage + "#" + m.anchor(), "constructor in " + qualifiedName));
765         }
766       }
767     }
768 
769     // package private constructors
770     if (Doclava.checkLevel(Doclava.SHOW_PACKAGE)) {
771       for (MethodInfo m : ctors) {
772         if (m.isPackagePrivate() && m.checkLevel()) {
773           keywords.add(new KeywordEntry(m.prettySignature(),
774               htmlPage + "#" + m.anchor(), "constructor in " + qualifiedName));
775         }
776       }
777     }
778 
779     // private constructors
780     if (Doclava.checkLevel(Doclava.SHOW_PRIVATE)) {
781       for (MethodInfo m : ctors) {
782         if (m.isPrivate() && m.checkLevel()) {
783           keywords.add(new KeywordEntry(m.name() + m.prettySignature(),
784               htmlPage + "#" + m.anchor(), "constructor in " + qualifiedName));
785         }
786       }
787     }
788 
789     // public methods
790     for (MethodInfo m : methods) {
791       if (m.isPublic() && m.checkLevel()) {
792         keywords.add(new KeywordEntry(m.name() + m.prettySignature(), htmlPage + "#" + m.anchor(),
793             "method in " + qualifiedName));
794       }
795     }
796 
797     // protected methods
798     if (Doclava.checkLevel(Doclava.SHOW_PROTECTED)) {
799       for (MethodInfo m : methods) {
800         if (m.isProtected() && m.checkLevel()) {
801           keywords.add(new KeywordEntry(m.name() + m.prettySignature(),
802               htmlPage + "#" + m.anchor(), "method in " + qualifiedName));
803         }
804       }
805     }
806 
807     // package private methods
808     if (Doclava.checkLevel(Doclava.SHOW_PACKAGE)) {
809       for (MethodInfo m : methods) {
810         if (m.isPackagePrivate() && m.checkLevel()) {
811           keywords.add(new KeywordEntry(m.name() + m.prettySignature(),
812               htmlPage + "#" + m.anchor(), "method in " + qualifiedName));
813         }
814       }
815     }
816 
817     // private methods
818     if (Doclava.checkLevel(Doclava.SHOW_PRIVATE)) {
819       for (MethodInfo m : methods) {
820         if (m.isPrivate() && m.checkLevel()) {
821           keywords.add(new KeywordEntry(m.name() + m.prettySignature(),
822               htmlPage + "#" + m.anchor(), "method in " + qualifiedName));
823         }
824       }
825     }
826   }
827 
makeLink(Data data, String base)828   public void makeLink(Data data, String base) {
829     data.setValue(base + ".label", this.name());
830     if (!this.isPrimitive() && this.isIncluded() && this.checkLevel()) {
831       data.setValue(base + ".link", this.htmlPage());
832     }
833   }
834 
makeLinkListHDF(Data data, String base, ClassInfo[] classes)835   public static void makeLinkListHDF(Data data, String base, ClassInfo[] classes) {
836     final int N = classes.length;
837     for (int i = 0; i < N; i++) {
838       ClassInfo cl = classes[i];
839       if (cl.checkLevel()) {
840         cl.asTypeInfo().makeHDF(data, base + "." + i);
841       }
842     }
843   }
844 
845   /**
846    * Used in lists of this class (packages, nested classes, known subclasses)
847    */
makeShortDescrHDF(Data data, String base)848   public void makeShortDescrHDF(Data data, String base) {
849     mTypeInfo.makeHDF(data, base + ".type");
850     data.setValue(base + ".kind", this.kind());
851     TagInfo.makeHDF(data, base + ".shortDescr", this.firstSentenceTags());
852     TagInfo.makeHDF(data, base + ".deprecated", deprecatedTags());
853     data.setValue(base + ".since", getSince());
854     if (isDeprecated()) {
855       data.setValue(base + ".deprecatedsince", getDeprecatedSince());
856     }
857     setFederatedReferences(data, base);
858   }
859 
860   /**
861    * Turns into the main class page
862    */
makeHDF(Data data)863   public void makeHDF(Data data) {
864     int i, j, n;
865     String name = name();
866     String qualified = qualifiedName();
867     ArrayList<AttributeInfo> selfAttributes = selfAttributes();
868     ArrayList<MethodInfo> methods = selfMethods();
869     ArrayList<FieldInfo> fields = selfFields();
870     ArrayList<FieldInfo> enumConstants = enumConstants();
871     ArrayList<MethodInfo> ctors = constructors();
872     ArrayList<ClassInfo> inners = innerClasses();
873 
874     // class name
875     mTypeInfo.makeHDF(data, "class.type");
876     mTypeInfo.makeQualifiedHDF(data, "class.qualifiedType");
877     data.setValue("class.name", name);
878     data.setValue("class.qualified", qualified);
879     if (isProtected()) {
880       data.setValue("class.scope", "protected");
881     } else if (isPublic()) {
882       data.setValue("class.scope", "public");
883     }
884     if (isStatic()) {
885       data.setValue("class.static", "static");
886     }
887     if (isFinal()) {
888       data.setValue("class.final", "final");
889     }
890     if (isAbstract() && !isInterface()) {
891       data.setValue("class.abstract", "abstract");
892     }
893 
894     // class info
895     String kind = kind();
896     if (kind != null) {
897       data.setValue("class.kind", kind);
898     }
899     data.setValue("class.since", getSince());
900     if (isDeprecated()) {
901       data.setValue("class.deprecatedsince", getDeprecatedSince());
902     }
903     setFederatedReferences(data, "class");
904 
905     // the containing package -- note that this can be passed to type_link,
906     // but it also contains the list of all of the packages
907     containingPackage().makeClassLinkListHDF(data, "class.package");
908 
909     // inheritance hierarchy
910     Vector<ClassInfo> superClasses = new Vector<ClassInfo>();
911     superClasses.add(this);
912     ClassInfo supr = superclass();
913     while (supr != null) {
914       superClasses.add(supr);
915       supr = supr.superclass();
916     }
917     n = superClasses.size();
918     for (i = 0; i < n; i++) {
919       supr = superClasses.elementAt(n - i - 1);
920 
921       supr.asTypeInfo().makeQualifiedHDF(data, "class.inheritance." + i + ".class");
922       supr.asTypeInfo().makeHDF(data, "class.inheritance." + i + ".short_class");
923       j = 0;
924       for (TypeInfo t : supr.interfaceTypes()) {
925         t.makeHDF(data, "class.inheritance." + i + ".interfaces." + j);
926         j++;
927       }
928     }
929 
930     // class description
931     TagInfo.makeHDF(data, "class.descr", inlineTags());
932     TagInfo.makeHDF(data, "class.seeAlso", comment().seeTags());
933     TagInfo.makeHDF(data, "class.deprecated", deprecatedTags());
934 
935     // known subclasses
936     TreeMap<String, ClassInfo> direct = new TreeMap<String, ClassInfo>();
937     TreeMap<String, ClassInfo> indirect = new TreeMap<String, ClassInfo>();
938     ClassInfo[] all = Converter.rootClasses();
939     for (ClassInfo cl : all) {
940       if (cl.superclass() != null && cl.superclass().equals(this)) {
941         direct.put(cl.name(), cl);
942       } else if (cl.isDerivedFrom(this)) {
943         indirect.put(cl.name(), cl);
944       }
945     }
946     // direct
947     i = 0;
948     for (ClassInfo cl : direct.values()) {
949       if (cl.checkLevel()) {
950         cl.makeShortDescrHDF(data, "class.subclasses.direct." + i);
951       }
952       i++;
953     }
954     // indirect
955     i = 0;
956     for (ClassInfo cl : indirect.values()) {
957       if (cl.checkLevel()) {
958         cl.makeShortDescrHDF(data, "class.subclasses.indirect." + i);
959       }
960       i++;
961     }
962 
963     // hide special cases
964     if ("java.lang.Object".equals(qualified) || "java.io.Serializable".equals(qualified)) {
965       data.setValue("class.subclasses.hidden", "1");
966     } else {
967       data.setValue("class.subclasses.hidden", "0");
968     }
969 
970     // nested classes
971     i = 0;
972     for (ClassInfo inner : inners) {
973       if (inner.checkLevel()) {
974         inner.makeShortDescrHDF(data, "class.inners." + i);
975       }
976       i++;
977     }
978 
979     // enum constants
980     i = 0;
981     for (FieldInfo field : enumConstants) {
982       field.makeHDF(data, "class.enumConstants." + i);
983       i++;
984     }
985 
986     // constants
987     i = 0;
988     for (FieldInfo field : fields) {
989       if (field.isConstant()) {
990         field.makeHDF(data, "class.constants." + i);
991         i++;
992       }
993     }
994 
995     // fields
996     i = 0;
997     for (FieldInfo field : fields) {
998       if (!field.isConstant()) {
999         field.makeHDF(data, "class.fields." + i);
1000         i++;
1001       }
1002     }
1003 
1004     // public constructors
1005     i = 0;
1006     for (MethodInfo ctor : ctors) {
1007       if (ctor.isPublic()) {
1008         ctor.makeHDF(data, "class.ctors.public." + i);
1009         i++;
1010       }
1011     }
1012 
1013     // protected constructors
1014     if (Doclava.checkLevel(Doclava.SHOW_PROTECTED)) {
1015       i = 0;
1016       for (MethodInfo ctor : ctors) {
1017         if (ctor.isProtected()) {
1018           ctor.makeHDF(data, "class.ctors.protected." + i);
1019           i++;
1020         }
1021       }
1022     }
1023 
1024     // package private constructors
1025     if (Doclava.checkLevel(Doclava.SHOW_PACKAGE)) {
1026       i = 0;
1027       for (MethodInfo ctor : ctors) {
1028         if (ctor.isPackagePrivate()) {
1029           ctor.makeHDF(data, "class.ctors.package." + i);
1030           i++;
1031         }
1032       }
1033     }
1034 
1035     // private constructors
1036     if (Doclava.checkLevel(Doclava.SHOW_PRIVATE)) {
1037       i = 0;
1038       for (MethodInfo ctor : ctors) {
1039         if (ctor.isPrivate()) {
1040           ctor.makeHDF(data, "class.ctors.private." + i);
1041           i++;
1042         }
1043       }
1044     }
1045 
1046     // public methods
1047     i = 0;
1048     for (MethodInfo method : methods) {
1049       if (method.isPublic()) {
1050         method.makeHDF(data, "class.methods.public." + i);
1051         i++;
1052       }
1053     }
1054 
1055     // protected methods
1056     if (Doclava.checkLevel(Doclava.SHOW_PROTECTED)) {
1057       i = 0;
1058       for (MethodInfo method : methods) {
1059         if (method.isProtected()) {
1060           method.makeHDF(data, "class.methods.protected." + i);
1061           i++;
1062         }
1063       }
1064     }
1065 
1066     // package private methods
1067     if (Doclava.checkLevel(Doclava.SHOW_PACKAGE)) {
1068       i = 0;
1069       for (MethodInfo method : methods) {
1070         if (method.isPackagePrivate()) {
1071           method.makeHDF(data, "class.methods.package." + i);
1072           i++;
1073         }
1074       }
1075     }
1076 
1077     // private methods
1078     if (Doclava.checkLevel(Doclava.SHOW_PRIVATE)) {
1079       i = 0;
1080       for (MethodInfo method : methods) {
1081         if (method.isPrivate()) {
1082           method.makeHDF(data, "class.methods.private." + i);
1083           i++;
1084         }
1085       }
1086     }
1087 
1088     // xml attributes
1089     i = 0;
1090     for (AttributeInfo attr : selfAttributes) {
1091       if (attr.checkLevel()) {
1092         attr.makeHDF(data, "class.attrs." + i);
1093         i++;
1094       }
1095     }
1096 
1097     // inherited methods
1098     Set<ClassInfo> interfaces = new TreeSet<ClassInfo>();
1099     addInterfaces(interfaces(), interfaces);
1100     ClassInfo cl = superclass();
1101     i = 0;
1102     while (cl != null) {
1103       addInterfaces(cl.interfaces(), interfaces);
1104       makeInheritedHDF(data, i, cl);
1105       cl = cl.superclass();
1106       i++;
1107     }
1108     for (ClassInfo iface : interfaces) {
1109       makeInheritedHDF(data, i, iface);
1110       i++;
1111     }
1112   }
1113 
addInterfaces(ArrayList<ClassInfo> ifaces, Set<ClassInfo> out)1114   private static void addInterfaces(ArrayList<ClassInfo> ifaces, Set<ClassInfo> out) {
1115     for (ClassInfo cl : ifaces) {
1116       out.add(cl);
1117       addInterfaces(cl.interfaces(), out);
1118     }
1119   }
1120 
makeInheritedHDF(Data data, int index, ClassInfo cl)1121   private static void makeInheritedHDF(Data data, int index, ClassInfo cl) {
1122     int i;
1123 
1124     String base = "class.inherited." + index;
1125     data.setValue(base + ".qualified", cl.qualifiedName());
1126     if (cl.checkLevel()) {
1127       data.setValue(base + ".link", cl.htmlPage());
1128     }
1129     String kind = cl.kind();
1130     if (kind != null) {
1131       data.setValue(base + ".kind", kind);
1132     }
1133 
1134     if (cl.mIsIncluded) {
1135       data.setValue(base + ".included", "true");
1136     } else {
1137       Doclava.federationTagger.tagAll(new ClassInfo[] {cl});
1138       if (!cl.getFederatedReferences().isEmpty()) {
1139         FederatedSite site = cl.getFederatedReferences().iterator().next();
1140         data.setValue(base + ".link", site.linkFor(cl.htmlPage()));
1141         data.setValue(base + ".federated", site.name());
1142       }
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
isHidden()1179   public boolean isHidden() {
1180     int val = mHidden;
1181     if (val >= 0) {
1182       return val != 0;
1183     } else {
1184       boolean v = isHiddenImpl();
1185       mHidden = v ? 1 : 0;
1186       return v;
1187     }
1188   }
1189 
isHiddenImpl()1190   public boolean isHiddenImpl() {
1191     ClassInfo cl = this;
1192     while (cl != null) {
1193       PackageInfo pkg = cl.containingPackage();
1194       if (pkg != null && pkg.isHidden()) {
1195         return true;
1196       }
1197       if (cl.annotations() != null) {
1198         for (AnnotationInstanceInfo info : cl.annotations()) {
1199           if (Doclava.showAnnotations.contains(info.type().qualifiedName())) {
1200             return false;
1201           }
1202         }
1203       }
1204       if (cl.comment().isHidden()) {
1205         return true;
1206       }
1207       cl = cl.containingClass();
1208     }
1209     return false;
1210   }
1211 
matchMethod(ArrayList<MethodInfo> methods, String name, String[] params, String[] dimensions, boolean varargs)1212   private MethodInfo matchMethod(ArrayList<MethodInfo> methods, String name, String[] params,
1213       String[] dimensions, boolean varargs) {
1214     for (MethodInfo method : methods) {
1215       if (method.name().equals(name)) {
1216         if (params == null) {
1217           return method;
1218         } else {
1219           if (method.matchesParams(params, dimensions, varargs)) {
1220             return method;
1221           }
1222         }
1223       }
1224     }
1225     return null;
1226   }
1227 
findMethod(String name, String[] params, String[] dimensions, boolean varargs)1228   public MethodInfo findMethod(String name, String[] params, String[] dimensions, boolean varargs) {
1229     // first look on our class, and our superclasses
1230 
1231     // for methods
1232     MethodInfo rv;
1233     rv = matchMethod(methods(), name, params, dimensions, varargs);
1234 
1235     if (rv != null) {
1236       return rv;
1237     }
1238 
1239     // for constructors
1240     rv = matchMethod(constructors(), name, params, dimensions, varargs);
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, varargs);
1249     }
1250 
1251     return null;
1252   }
1253 
supportsMethod(MethodInfo method)1254   public boolean supportsMethod(MethodInfo method) {
1255     for (MethodInfo m : methods()) {
1256       if (m.getHashableName().equals(method.getHashableName())) {
1257         return true;
1258       }
1259     }
1260     return false;
1261   }
1262 
searchInnerClasses(String[] nameParts, int index)1263   private ClassInfo searchInnerClasses(String[] nameParts, int index) {
1264     String part = nameParts[index];
1265 
1266     ArrayList<ClassInfo> inners = mInnerClasses;
1267     for (ClassInfo in : inners) {
1268       String[] innerParts = in.nameParts();
1269       if (part.equals(innerParts[innerParts.length - 1])) {
1270         if (index == nameParts.length - 1) {
1271           return in;
1272         } else {
1273           return in.searchInnerClasses(nameParts, index + 1);
1274         }
1275       }
1276     }
1277     return null;
1278   }
1279 
extendedFindClass(String className)1280   public ClassInfo extendedFindClass(String className) {
1281     // ClassDoc.findClass has this bug that we're working around here:
1282     // If you have a class PackageManager with an inner class PackageInfo
1283     // and you call it with "PackageInfo" it doesn't find it.
1284     return searchInnerClasses(className.split("\\."), 0);
1285   }
1286 
findClass(String className)1287   public ClassInfo findClass(String className) {
1288     return Converter.obtainClass(mClass.findClass(className));
1289   }
1290 
findInnerClass(String className)1291   public ClassInfo findInnerClass(String className) {
1292     // ClassDoc.findClass won't find inner classes. To deal with that,
1293     // we try what they gave us first, but if that didn't work, then
1294     // we see if there are any periods in className, and start searching
1295     // from there.
1296     String[] nodes = className.split("\\.");
1297     ClassDoc cl = mClass;
1298     for (String n : nodes) {
1299       cl = cl.findClass(n);
1300       if (cl == null) {
1301         return null;
1302       }
1303     }
1304     return Converter.obtainClass(cl);
1305   }
1306 
findField(String name)1307   public FieldInfo findField(String name) {
1308     // first look on our class, and our superclasses
1309     for (FieldInfo f : fields()) {
1310       if (f.name().equals(name)) {
1311         return f;
1312       }
1313     }
1314 
1315     // then look at our enum constants (these are really fields, maybe
1316     // they should be mixed into fields(). not sure)
1317     for (FieldInfo f : enumConstants()) {
1318       if (f.name().equals(name)) {
1319         return f;
1320       }
1321     }
1322 
1323     // then recursively look at our containing class
1324     ClassInfo containing = containingClass();
1325     if (containing != null) {
1326       return containing.findField(name);
1327     }
1328 
1329     return null;
1330   }
1331 
sortByName(ClassInfo[] classes)1332   public static ClassInfo[] sortByName(ClassInfo[] classes) {
1333     int i;
1334     Sorter[] sorted = new Sorter[classes.length];
1335     for (i = 0; i < sorted.length; i++) {
1336       ClassInfo cl = classes[i];
1337       sorted[i] = new Sorter(cl.name(), cl);
1338     }
1339 
1340     Arrays.sort(sorted);
1341 
1342     ClassInfo[] rv = new ClassInfo[classes.length];
1343     for (i = 0; i < rv.length; i++) {
1344       rv[i] = (ClassInfo) sorted[i].data;
1345     }
1346 
1347     return rv;
1348   }
1349 
equals(ClassInfo that)1350   public boolean equals(ClassInfo that) {
1351     if (that != null) {
1352       return this.qualifiedName().equals(that.qualifiedName());
1353     } else {
1354       return false;
1355     }
1356   }
1357 
setNonWrittenConstructors(ArrayList<MethodInfo> nonWritten)1358   public void setNonWrittenConstructors(ArrayList<MethodInfo> nonWritten) {
1359     mNonWrittenConstructors = nonWritten;
1360   }
1361 
getNonWrittenConstructors()1362   public ArrayList<MethodInfo> getNonWrittenConstructors() {
1363     return mNonWrittenConstructors;
1364   }
1365 
kind()1366   public String kind() {
1367     if (isOrdinaryClass()) {
1368       return "class";
1369     } else if (isInterface()) {
1370       return "interface";
1371     } else if (isEnum()) {
1372       return "enum";
1373     } else if (isError()) {
1374       return "class";
1375     } else if (isException()) {
1376       return "class";
1377     } else if (isAnnotation()) {
1378       return "@interface";
1379     }
1380     return null;
1381   }
1382 
scope()1383   public String scope() {
1384     if (isPublic()) {
1385       return "public";
1386     } else if (isProtected()) {
1387       return "protected";
1388     } else if (isPackagePrivate()) {
1389       return "";
1390     } else if (isPrivate()) {
1391       return "private";
1392     } else {
1393       throw new RuntimeException("invalid scope for object " + this);
1394     }
1395   }
1396 
setHiddenMethods(ArrayList<MethodInfo> mInfo)1397   public void setHiddenMethods(ArrayList<MethodInfo> mInfo) {
1398     mHiddenMethods = mInfo;
1399   }
1400 
getHiddenMethods()1401   public ArrayList<MethodInfo> getHiddenMethods() {
1402     return mHiddenMethods;
1403   }
1404 
1405   @Override
toString()1406   public String toString() {
1407     return this.qualifiedName();
1408   }
1409 
setReasonIncluded(String reason)1410   public void setReasonIncluded(String reason) {
1411     mReasonIncluded = reason;
1412   }
1413 
getReasonIncluded()1414   public String getReasonIncluded() {
1415     return mReasonIncluded;
1416   }
1417 
1418   private ClassDoc mClass;
1419 
1420   // ctor
1421   private boolean mIsPublic;
1422   private boolean mIsProtected;
1423   private boolean mIsPackagePrivate;
1424   private boolean mIsPrivate;
1425   private boolean mIsStatic;
1426   private boolean mIsInterface;
1427   private boolean mIsAbstract;
1428   private boolean mIsOrdinaryClass;
1429   private boolean mIsException;
1430   private boolean mIsError;
1431   private boolean mIsEnum;
1432   private boolean mIsAnnotation;
1433   private boolean mIsFinal;
1434   private boolean mIsIncluded;
1435   private String mName;
1436   private String mQualifiedName;
1437   private String mQualifiedTypeName;
1438   private boolean mIsPrimitive;
1439   private TypeInfo mTypeInfo;
1440   private String[] mNameParts;
1441 
1442   // init
1443   private ArrayList<ClassInfo> mRealInterfaces = new ArrayList<ClassInfo>();
1444   private ArrayList<ClassInfo> mInterfaces;
1445   private ArrayList<TypeInfo> mRealInterfaceTypes;
1446   private ArrayList<ClassInfo> mInnerClasses;
1447   private ArrayList<MethodInfo> mAllConstructors = new ArrayList<MethodInfo>();
1448   private ArrayList<MethodInfo> mAllSelfMethods = new ArrayList<MethodInfo>();
1449   private ArrayList<MethodInfo> mAnnotationElements = new ArrayList<MethodInfo>(); // if this class is an annotation
1450   private ArrayList<FieldInfo> mAllSelfFields = new ArrayList<FieldInfo>();
1451   private ArrayList<FieldInfo> mEnumConstants = new ArrayList<FieldInfo>();
1452   private PackageInfo mContainingPackage;
1453   private ClassInfo mContainingClass;
1454   private ClassInfo mRealSuperclass;
1455   private TypeInfo mRealSuperclassType;
1456   private ClassInfo mSuperclass;
1457   private ArrayList<AnnotationInstanceInfo> mAnnotations;
1458   private boolean mSuperclassInit;
1459   private boolean mDeprecatedKnown;
1460 
1461   // lazy
1462   private ArrayList<MethodInfo> mConstructors;
1463   private ArrayList<ClassInfo> mRealInnerClasses;
1464   private ArrayList<MethodInfo> mSelfMethods;
1465   private ArrayList<FieldInfo> mSelfFields;
1466   private ArrayList<AttributeInfo> mSelfAttributes;
1467   private ArrayList<MethodInfo> mMethods;
1468   private ArrayList<FieldInfo> mFields;
1469   private ArrayList<TypeInfo> mTypeParameters;
1470   private ArrayList<MethodInfo> mHiddenMethods;
1471   private int mHidden = -1;
1472   private int mCheckLevel = -1;
1473   private String mReasonIncluded;
1474   private ArrayList<MethodInfo> mNonWrittenConstructors;
1475   private boolean mIsDeprecated;
1476 
1477   // TODO: Temporary members from apicheck migration.
1478   private HashMap<String, MethodInfo> mApiCheckConstructors = new HashMap<String, MethodInfo>();
1479   private HashMap<String, MethodInfo> mApiCheckMethods = new HashMap<String, MethodInfo>();
1480   private HashMap<String, FieldInfo> mApiCheckFields = new HashMap<String, FieldInfo>();
1481   private HashMap<String, FieldInfo> mApiCheckEnumConstants = new HashMap<String, FieldInfo>();
1482 
1483   // Resolutions
1484   private ArrayList<Resolution> mResolutions;
1485 
1486   /**
1487    * Returns true if {@code cl} implements the interface {@code iface} either by either being that
1488    * interface, implementing that interface or extending a type that implements the interface.
1489    */
implementsInterface(ClassInfo cl, String iface)1490   private boolean implementsInterface(ClassInfo cl, String iface) {
1491     if (cl.qualifiedName().equals(iface)) {
1492       return true;
1493     }
1494     for (ClassInfo clImplements : cl.interfaces()) {
1495       if (implementsInterface(clImplements, iface)) {
1496         return true;
1497       }
1498     }
1499     if (cl.mSuperclass != null && implementsInterface(cl.mSuperclass, iface)) {
1500       return true;
1501     }
1502     return false;
1503   }
1504 
addInterface(ClassInfo iface)1505   public void addInterface(ClassInfo iface) {
1506     mRealInterfaces.add(iface);
1507   }
1508 
addConstructor(MethodInfo ctor)1509   public void addConstructor(MethodInfo ctor) {
1510     mApiCheckConstructors.put(ctor.getHashableName(), ctor);
1511 
1512     mAllConstructors.add(ctor);
1513     mConstructors = null; // flush this, hopefully it hasn't been used yet.
1514   }
1515 
addField(FieldInfo field)1516   public void addField(FieldInfo field) {
1517     mApiCheckFields.put(field.name(), field);
1518 
1519     mAllSelfFields.add(field);
1520 
1521     mSelfFields = null; // flush this, hopefully it hasn't been used yet.
1522   }
1523 
addEnumConstant(FieldInfo field)1524   public void addEnumConstant(FieldInfo field) {
1525     mApiCheckEnumConstants.put(field.name(), field);
1526 
1527     mEnumConstants.add(field);
1528   }
1529 
setSuperClass(ClassInfo superclass)1530   public void setSuperClass(ClassInfo superclass) {
1531     mRealSuperclass = superclass;
1532     mSuperclass = superclass;
1533   }
1534 
allConstructorsMap()1535   public Map<String, MethodInfo> allConstructorsMap() {
1536     return mApiCheckConstructors;
1537   }
1538 
allFields()1539   public Map<String, FieldInfo> allFields() {
1540     return mApiCheckFields;
1541   }
1542 
1543   /**
1544    * Returns all methods defined directly in this class. For a list of all
1545    * methods supported by this class, see {@link #methods()}.
1546    */
allMethods()1547   public Map<String, MethodInfo> allMethods() {
1548     return mApiCheckMethods;
1549   }
1550 
1551   /**
1552    * Returns the class hierarchy for this class, starting with this class.
1553    */
hierarchy()1554   public Iterable<ClassInfo> hierarchy() {
1555     List<ClassInfo> result = new ArrayList<ClassInfo>(4);
1556     for (ClassInfo c = this; c != null; c = c.mSuperclass) {
1557       result.add(c);
1558     }
1559     return result;
1560   }
1561 
superclassName()1562   public String superclassName() {
1563     if (mSuperclass == null) {
1564       if (mQualifiedName.equals("java.lang.Object")) {
1565         return null;
1566       }
1567       throw new UnsupportedOperationException("Superclass not set for " + qualifiedName());
1568     }
1569     return mSuperclass.mQualifiedName;
1570   }
1571 
setAnnotations(ArrayList<AnnotationInstanceInfo> annotations)1572   public void setAnnotations(ArrayList<AnnotationInstanceInfo> annotations) {
1573     mAnnotations = annotations;
1574   }
1575 
isConsistent(ClassInfo cl)1576   public boolean isConsistent(ClassInfo cl) {
1577     boolean consistent = true;
1578 
1579     if (isInterface() != cl.isInterface()) {
1580       Errors.error(Errors.CHANGED_CLASS, cl.position(), "Class " + cl.qualifiedName()
1581           + " changed class/interface declaration");
1582       consistent = false;
1583     }
1584     for (ClassInfo iface : mRealInterfaces) {
1585       if (!implementsInterface(cl, iface.mQualifiedName)) {
1586         Errors.error(Errors.REMOVED_INTERFACE, cl.position(), "Class " + qualifiedName()
1587             + " no longer implements " + iface);
1588       }
1589     }
1590     for (ClassInfo iface : cl.mRealInterfaces) {
1591       if (!implementsInterface(this, iface.mQualifiedName)) {
1592         Errors.error(Errors.ADDED_INTERFACE, cl.position(), "Added interface " + iface
1593             + " to class " + qualifiedName());
1594         consistent = false;
1595       }
1596     }
1597 
1598     for (MethodInfo mInfo : mApiCheckMethods.values()) {
1599       if (cl.mApiCheckMethods.containsKey(mInfo.getHashableName())) {
1600         if (!mInfo.isConsistent(cl.mApiCheckMethods.get(mInfo.getHashableName()))) {
1601           consistent = false;
1602         }
1603       } else {
1604         /*
1605          * This class formerly provided this method directly, and now does not. Check our ancestry
1606          * to see if there's an inherited version that still fulfills the API requirement.
1607          */
1608         MethodInfo mi = ClassInfo.overriddenMethod(mInfo, cl);
1609         if (mi == null) {
1610           mi = ClassInfo.interfaceMethod(mInfo, cl);
1611         }
1612         if (mi == null) {
1613           Errors.error(Errors.REMOVED_METHOD, mInfo.position(), "Removed public method "
1614               + mInfo.qualifiedName());
1615           consistent = false;
1616         }
1617       }
1618     }
1619     for (MethodInfo mInfo : cl.mApiCheckMethods.values()) {
1620       if (!mApiCheckMethods.containsKey(mInfo.getHashableName())) {
1621         /*
1622          * Similarly to the above, do not fail if this "new" method is really an override of an
1623          * existing superclass method.
1624          */
1625         MethodInfo mi = ClassInfo.overriddenMethod(mInfo, this);
1626         if (mi == null) {
1627           Errors.error(Errors.ADDED_METHOD, mInfo.position(), "Added public method "
1628               + mInfo.qualifiedName());
1629           consistent = false;
1630         }
1631       }
1632     }
1633 
1634     for (MethodInfo mInfo : mApiCheckConstructors.values()) {
1635       if (cl.mApiCheckConstructors.containsKey(mInfo.getHashableName())) {
1636         if (!mInfo.isConsistent(cl.mApiCheckConstructors.get(mInfo.getHashableName()))) {
1637           consistent = false;
1638         }
1639       } else {
1640         Errors.error(Errors.REMOVED_METHOD, mInfo.position(), "Removed public constructor "
1641             + mInfo.prettySignature());
1642         consistent = false;
1643       }
1644     }
1645     for (MethodInfo mInfo : cl.mApiCheckConstructors.values()) {
1646       if (!mApiCheckConstructors.containsKey(mInfo.getHashableName())) {
1647         Errors.error(Errors.ADDED_METHOD, mInfo.position(), "Added public constructor "
1648             + mInfo.prettySignature());
1649         consistent = false;
1650       }
1651     }
1652 
1653     for (FieldInfo mInfo : mApiCheckFields.values()) {
1654       if (cl.mApiCheckFields.containsKey(mInfo.name())) {
1655         if (!mInfo.isConsistent(cl.mApiCheckFields.get(mInfo.name()))) {
1656           consistent = false;
1657         }
1658       } else {
1659         Errors.error(Errors.REMOVED_FIELD, mInfo.position(), "Removed field "
1660             + mInfo.qualifiedName());
1661         consistent = false;
1662       }
1663     }
1664     for (FieldInfo mInfo : cl.mApiCheckFields.values()) {
1665       if (!mApiCheckFields.containsKey(mInfo.name())) {
1666         Errors.error(Errors.ADDED_FIELD, mInfo.position(), "Added public field "
1667             + mInfo.qualifiedName());
1668         consistent = false;
1669       }
1670     }
1671 
1672     for (FieldInfo info : mApiCheckEnumConstants.values()) {
1673       if (cl.mApiCheckEnumConstants.containsKey(info.name())) {
1674         if (!info.isConsistent(cl.mApiCheckEnumConstants.get(info.name()))) {
1675           consistent = false;
1676         }
1677       } else {
1678         Errors.error(Errors.REMOVED_FIELD, info.position(), "Removed enum constant "
1679             + info.qualifiedName());
1680         consistent = false;
1681       }
1682     }
1683     for (FieldInfo info : cl.mApiCheckEnumConstants.values()) {
1684       if (!mApiCheckEnumConstants.containsKey(info.name())) {
1685         Errors.error(Errors.ADDED_FIELD, info.position(), "Added enum constant "
1686             + info.qualifiedName());
1687         consistent = false;
1688       }
1689     }
1690 
1691     if (mIsAbstract != cl.mIsAbstract) {
1692       consistent = false;
1693       Errors.error(Errors.CHANGED_ABSTRACT, cl.position(), "Class " + cl.qualifiedName()
1694           + " changed abstract qualifier");
1695     }
1696 
1697     if (mIsFinal != cl.mIsFinal) {
1698       consistent = false;
1699       Errors.error(Errors.CHANGED_FINAL, cl.position(), "Class " + cl.qualifiedName()
1700           + " changed final qualifier");
1701     }
1702 
1703     if (mIsStatic != cl.mIsStatic) {
1704       consistent = false;
1705       Errors.error(Errors.CHANGED_STATIC, cl.position(), "Class " + cl.qualifiedName()
1706           + " changed static qualifier");
1707     }
1708 
1709     if (!scope().equals(cl.scope())) {
1710       consistent = false;
1711       Errors.error(Errors.CHANGED_SCOPE, cl.position(), "Class " + cl.qualifiedName()
1712           + " scope changed from " + scope() + " to " + cl.scope());
1713     }
1714 
1715     if (!isDeprecated() == cl.isDeprecated()) {
1716       consistent = false;
1717       Errors.error(Errors.CHANGED_DEPRECATED, cl.position(), "Class " + cl.qualifiedName()
1718           + " has changed deprecation state");
1719     }
1720 
1721     if (superclassName() != null) {
1722       if (cl.superclassName() == null || !superclassName().equals(cl.superclassName())) {
1723         consistent = false;
1724         Errors.error(Errors.CHANGED_SUPERCLASS, cl.position(), "Class " + qualifiedName()
1725             + " superclass changed from " + superclassName() + " to " + cl.superclassName());
1726       }
1727     } else if (cl.superclassName() != null) {
1728       consistent = false;
1729       Errors.error(Errors.CHANGED_SUPERCLASS, cl.position(), "Class " + qualifiedName()
1730           + " superclass changed from " + "null to " + cl.superclassName());
1731     }
1732 
1733     return consistent;
1734   }
1735 
1736   // Find a superclass implementation of the given method.
overriddenMethod(MethodInfo candidate, ClassInfo newClassObj)1737   public static MethodInfo overriddenMethod(MethodInfo candidate, ClassInfo newClassObj) {
1738     if (newClassObj == null) {
1739       return null;
1740     }
1741     for (MethodInfo mi : newClassObj.mApiCheckMethods.values()) {
1742       if (mi.matches(candidate)) {
1743         // found it
1744         return mi;
1745       }
1746     }
1747 
1748     // not found here. recursively search ancestors
1749     return ClassInfo.overriddenMethod(candidate, newClassObj.mSuperclass);
1750   }
1751 
1752   // Find a superinterface declaration of the given method.
interfaceMethod(MethodInfo candidate, ClassInfo newClassObj)1753   public static MethodInfo interfaceMethod(MethodInfo candidate, ClassInfo newClassObj) {
1754     if (newClassObj == null) {
1755       return null;
1756     }
1757     for (ClassInfo interfaceInfo : newClassObj.interfaces()) {
1758       for (MethodInfo mi : interfaceInfo.mApiCheckMethods.values()) {
1759         if (mi.matches(candidate)) {
1760           return mi;
1761         }
1762       }
1763     }
1764     return ClassInfo.interfaceMethod(candidate, newClassObj.mSuperclass);
1765   }
1766 
hasConstructor(MethodInfo constructor)1767   public boolean hasConstructor(MethodInfo constructor) {
1768     String name = constructor.getHashableName();
1769     for (MethodInfo ctor : mApiCheckConstructors.values()) {
1770       if (name.equals(ctor.getHashableName())) {
1771         return true;
1772       }
1773     }
1774     return false;
1775   }
1776 
setTypeInfo(TypeInfo typeInfo)1777   public void setTypeInfo(TypeInfo typeInfo) {
1778     mTypeInfo = typeInfo;
1779   }
1780 
type()1781   public TypeInfo type() {
1782       return mTypeInfo;
1783   }
1784 
addInnerClass(ClassInfo innerClass)1785   public void addInnerClass(ClassInfo innerClass) {
1786       if (mInnerClasses == null) {
1787           mInnerClasses = new ArrayList<ClassInfo>();
1788       }
1789 
1790       mInnerClasses.add(innerClass);
1791   }
1792 
setContainingClass(ClassInfo containingClass)1793   public void setContainingClass(ClassInfo containingClass) {
1794       mContainingClass = containingClass;
1795   }
1796 
setSuperclassType(TypeInfo superclassType)1797   public void setSuperclassType(TypeInfo superclassType) {
1798       mRealSuperclassType = superclassType;
1799   }
1800 
printResolutions()1801   public void printResolutions() {
1802       if (mResolutions == null || mResolutions.isEmpty()) {
1803           return;
1804       }
1805 
1806       System.out.println("Resolutions for Class " + mName + ":");
1807 
1808       for (Resolution r : mResolutions) {
1809           System.out.println(r);
1810       }
1811   }
1812 
addResolution(Resolution resolution)1813   public void addResolution(Resolution resolution) {
1814       if (mResolutions == null) {
1815           mResolutions = new ArrayList<Resolution>();
1816       }
1817 
1818       mResolutions.add(resolution);
1819   }
1820 
resolveResolutions()1821   public boolean resolveResolutions() {
1822       ArrayList<Resolution> resolutions = mResolutions;
1823       mResolutions = new ArrayList<Resolution>();
1824 
1825       boolean allResolved = true;
1826       for (Resolution resolution : resolutions) {
1827           StringBuilder qualifiedClassName = new StringBuilder();
1828           InfoBuilder.resolveQualifiedName(resolution.getValue(), qualifiedClassName,
1829                   resolution.getInfoBuilder());
1830 
1831           // if we still couldn't resolve it, save it for the next pass
1832           if ("".equals(qualifiedClassName.toString())) {
1833               mResolutions.add(resolution);
1834               allResolved = false;
1835           } else if ("superclassQualifiedName".equals(resolution.getVariable())) {
1836               setSuperClass(InfoBuilder.Caches.obtainClass(qualifiedClassName.toString()));
1837           } else if ("interfaceQualifiedName".equals(resolution.getVariable())) {
1838               addInterface(InfoBuilder.Caches.obtainClass(qualifiedClassName.toString()));
1839           }
1840       }
1841 
1842       return allResolved;
1843   }
1844 }
1845