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