• 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.ArrayDeque;
23 import java.util.ArrayList;
24 import java.util.Arrays;
25 import java.util.Collection;
26 import java.util.Collections;
27 import java.util.Comparator;
28 import java.util.HashMap;
29 import java.util.HashSet;
30 import java.util.Iterator;
31 import java.util.LinkedHashSet;
32 import java.util.LinkedList;
33 import java.util.List;
34 import java.util.Map;
35 import java.util.Objects;
36 import java.util.Queue;
37 import java.util.Set;
38 import java.util.TreeMap;
39 import java.util.function.Predicate;
40 
41 public class ClassInfo extends DocInfo implements ContainerInfo, Comparable, Scoped, Resolvable {
42   /**
43    * Contains a ClassInfo and a TypeInfo.
44    * <p>
45    * This is used to match a ClassInfo, which doesn't keep track of its type parameters
46    * and a type which does.
47    */
48   private class ClassTypePair {
49     private final ClassInfo mClassInfo;
50     private final TypeInfo mTypeInfo;
51 
ClassTypePair(ClassInfo cl, TypeInfo t)52     public ClassTypePair(ClassInfo cl, TypeInfo t) {
53       mClassInfo = cl;
54       mTypeInfo = t;
55     }
56 
classInfo()57     public ClassInfo classInfo() {
58       return mClassInfo;
59     }
60 
typeInfo()61     public TypeInfo typeInfo() {
62       return mTypeInfo;
63     }
64 
getTypeArgumentMapping()65     public Map<String, TypeInfo> getTypeArgumentMapping() {
66       return TypeInfo.getTypeArgumentMapping(classInfo(), typeInfo());
67     }
68   }
69 
70   public static final Comparator<ClassInfo> comparator = new Comparator<ClassInfo>() {
71     public int compare(ClassInfo a, ClassInfo b) {
72       return a.name().compareTo(b.name());
73     }
74   };
75 
76   public static final Comparator<ClassInfo> qualifiedComparator = new Comparator<ClassInfo>() {
77     public int compare(ClassInfo a, ClassInfo b) {
78       return a.qualifiedName().compareTo(b.qualifiedName());
79     }
80   };
81 
82   /**
83    * Constructs a stub representation of a class.
84    */
ClassInfo(String qualifiedName)85   public ClassInfo(String qualifiedName) {
86     super("", SourcePositionInfo.UNKNOWN);
87     mQualifiedName = qualifiedName;
88     if (qualifiedName.lastIndexOf('.') != -1) {
89       mName = qualifiedName.substring(qualifiedName.lastIndexOf('.') + 1);
90     } else {
91       mName = qualifiedName;
92     }
93   }
94 
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)95   public ClassInfo(ClassDoc cl, String rawCommentText, SourcePositionInfo position,
96           boolean isPublic, boolean isProtected, boolean isPackagePrivate, boolean isPrivate,
97           boolean isStatic, boolean isInterface, boolean isAbstract, boolean isOrdinaryClass,
98           boolean isException, boolean isError, boolean isEnum, boolean isAnnotation, boolean isFinal,
99           boolean isIncluded, String name, String qualifiedName, String qualifiedTypeName,
100           boolean isPrimitive) {
101       super(rawCommentText, position);
102 
103       initialize(rawCommentText, position,
104               isPublic, isProtected, isPackagePrivate, isPrivate,
105               isStatic, isInterface, isAbstract, isOrdinaryClass,
106               isException, isError, isEnum, isAnnotation, isFinal,
107               isIncluded, qualifiedTypeName, isPrimitive, null);
108 
109       mName = name;
110       mQualifiedName = qualifiedName;
111       mNameParts = name.split("\\.");
112       mClass = cl;
113   }
114 
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)115   public void initialize(String rawCommentText, SourcePositionInfo position,
116           boolean isPublic, boolean isProtected, boolean isPackagePrivate, boolean isPrivate,
117           boolean isStatic, boolean isInterface, boolean isAbstract, boolean isOrdinaryClass,
118           boolean isException, boolean isError, boolean isEnum, boolean isAnnotation, boolean isFinal,
119           boolean isIncluded, String qualifiedTypeName, boolean isPrimitive, ArrayList<AnnotationInstanceInfo> annotations) {
120 
121     // calls
122     setPosition(position);
123     setRawCommentText(rawCommentText);
124     mIsPublic = isPublic;
125     mIsProtected = isProtected;
126     mIsPackagePrivate = isPackagePrivate;
127     mIsPrivate = isPrivate;
128     mIsStatic = isStatic;
129     mIsInterface = isInterface;
130     mIsAbstract = isAbstract;
131     mIsOrdinaryClass = isOrdinaryClass;
132     mIsException = isException;
133     mIsError = isError;
134     mIsEnum = isEnum;
135     mIsAnnotation = isAnnotation;
136     mIsFinal = isFinal;
137     mIsIncluded = isIncluded;
138     mQualifiedTypeName = qualifiedTypeName;
139     mIsPrimitive = isPrimitive;
140     mAnnotations = annotations;
141     mShowAnnotations = AnnotationInstanceInfo.getShowAnnotationsIntersection(annotations);
142     mHideAnnotations = AnnotationInstanceInfo.getHideAnnotationsIntersection(annotations);
143   }
144 
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)145   public void init(TypeInfo typeInfo, ArrayList<ClassInfo> interfaces,
146           ArrayList<TypeInfo> interfaceTypes, ArrayList<ClassInfo> innerClasses,
147           ArrayList<MethodInfo> constructors, ArrayList<MethodInfo> methods,
148           ArrayList<MethodInfo> annotationElements, ArrayList<FieldInfo> fields,
149           ArrayList<FieldInfo> enumConstants, PackageInfo containingPackage,
150           ClassInfo containingClass, ClassInfo superclass,
151       TypeInfo superclassType, ArrayList<AnnotationInstanceInfo> annotations) {
152     mTypeInfo = typeInfo;
153     mRealInterfaces = new ArrayList<ClassInfo>(interfaces);
154     mRealInterfaceTypes = interfaceTypes;
155     mInnerClasses = innerClasses;
156     // mAllConstructors will not contain *all* constructors. Only the constructors that pass
157     // checkLevel. @see {@link Converter#convertMethods(ConstructorDoc[])}
158     mAllConstructors = constructors;
159     // mAllSelfMethods will not contain *all* self methods. Only the methods that pass
160     // checkLevel. @see {@link Converter#convertMethods(MethodDoc[])}
161     mAllSelfMethods = methods;
162     mAnnotationElements = annotationElements;
163     // mAllSelfFields will not contain *all* self fields. Only the fields that pass
164     // checkLevel. @see {@link Converter#convetFields(FieldDoc[])}
165     mAllSelfFields = fields;
166     // mEnumConstants will not contain *all* enum constants. Only the enums that pass
167     // checkLevel. @see {@link Converter#convetFields(FieldDoc[])}
168     mEnumConstants = enumConstants;
169     mContainingPackage = containingPackage;
170     mContainingClass = containingClass;
171     mRealSuperclass = superclass;
172     mRealSuperclassType = superclassType;
173     mAnnotations = annotations;
174     mShowAnnotations = AnnotationInstanceInfo.getShowAnnotationsIntersection(annotations);
175     mHideAnnotations = AnnotationInstanceInfo.getHideAnnotationsIntersection(annotations);
176 
177     // after providing new methods and new superclass info,clear any cached
178     // lists of self + superclass methods, ctors, etc.
179     mSuperclassInit = false;
180     mConstructors = null;
181     mMethods = null;
182     mSelfMethods = null;
183     mFields = null;
184     mSelfFields = null;
185     mSelfAttributes = null;
186     mDeprecatedKnown = false;
187     mSuperclassesWithTypes = null;
188     mInterfacesWithTypes = null;
189     mAllInterfacesWithTypes = null;
190 
191     Collections.sort(mEnumConstants, FieldInfo.comparator);
192     Collections.sort(mInnerClasses, ClassInfo.comparator);
193   }
194 
init2()195   public void init2() {
196     // calling this here forces the AttrTagInfo objects to be linked to the AttribtueInfo
197     // objects
198     selfAttributes();
199   }
200 
init3(ArrayList<TypeInfo> types, ArrayList<ClassInfo> realInnerClasses)201   public void init3(ArrayList<TypeInfo> types, ArrayList<ClassInfo> realInnerClasses) {
202     mTypeParameters = types;
203     mRealInnerClasses = realInnerClasses;
204   }
205 
206   public class ClassMemberInfo extends MemberInfo {
ClassMemberInfo()207     public ClassMemberInfo() {
208       super(ClassInfo.this.getRawCommentText(), ClassInfo.this.name(), ClassInfo.this.name(),
209           ClassInfo.this, ClassInfo.this, ClassInfo.this.isPublic(), ClassInfo.this.isProtected(),
210           ClassInfo.this.isPackagePrivate(), ClassInfo.this.isPrivate(), ClassInfo.this.isFinal(),
211           ClassInfo.this.isStatic(), false, ClassInfo.this.kind(), ClassInfo.this.position(),
212           ClassInfo.this.annotations());
213     }
214 
215     @Override
isExecutable()216     public boolean isExecutable() {
217       return false;
218     }
219   }
220 
221   /**
222    * Return representation of this class as {@link MemberInfo}. This normally
223    * doesn't make any sense, but it's useful for {@link Predicate} testing.
224    */
asMemberInfo()225   public MemberInfo asMemberInfo() {
226     return new ClassMemberInfo();
227   }
228 
getRealInnerClasses()229   public ArrayList<ClassInfo> getRealInnerClasses() {
230     return mRealInnerClasses;
231   }
232 
getTypeParameters()233   public ArrayList<TypeInfo> getTypeParameters() {
234     return mTypeParameters;
235   }
236 
237   /**
238    * @return true if this class needs to be shown in api txt, based on the
239    * hidden/removed status of the class and the show level setting in doclava.
240    */
checkLevel()241   public boolean checkLevel() {
242     if (mCheckLevel == null) {
243       mCheckLevel = Doclava.checkLevel(mIsPublic, mIsProtected, mIsPackagePrivate, mIsPrivate,
244           isHiddenOrRemoved());
245     }
246 
247     return mCheckLevel;
248   }
249 
compareTo(Object that)250   public int compareTo(Object that) {
251     if (that instanceof ClassInfo) {
252       return mQualifiedName.compareTo(((ClassInfo) that).mQualifiedName);
253     } else {
254       return this.hashCode() - that.hashCode();
255     }
256   }
257 
258   @Override
parent()259   public ContainerInfo parent() {
260     return this;
261   }
262 
isPublic()263   public boolean isPublic() {
264     return mIsPublic;
265   }
266 
isProtected()267   public boolean isProtected() {
268     return mIsProtected;
269   }
270 
isPackagePrivate()271   public boolean isPackagePrivate() {
272     return mIsPackagePrivate;
273   }
274 
isPrivate()275   public boolean isPrivate() {
276     return mIsPrivate;
277   }
278 
isStatic()279   public boolean isStatic() {
280     return mIsStatic;
281   }
282 
isInterface()283   public boolean isInterface() {
284     return mIsInterface;
285   }
286 
isAbstract()287   public boolean isAbstract() {
288     return mIsAbstract;
289   }
290 
containingPackage()291   public PackageInfo containingPackage() {
292     return mContainingPackage;
293   }
294 
containingClass()295   public ClassInfo containingClass() {
296     return mContainingClass;
297   }
298 
isOrdinaryClass()299   public boolean isOrdinaryClass() {
300     return mIsOrdinaryClass;
301   }
302 
isException()303   public boolean isException() {
304     return mIsException;
305   }
306 
isError()307   public boolean isError() {
308     return mIsError;
309   }
310 
isEnum()311   public boolean isEnum() {
312     return mIsEnum;
313   }
314 
isAnnotation()315   public boolean isAnnotation() {
316     return mIsAnnotation;
317   }
318 
isFinal()319   public boolean isFinal() {
320     return mIsFinal;
321   }
322 
isEffectivelyFinal()323   public boolean isEffectivelyFinal() {
324     return mIsFinal || mApiCheckConstructors.isEmpty();
325   }
326 
isIncluded()327   public boolean isIncluded() {
328     return mIsIncluded;
329   }
330 
typeVariables()331   public HashSet<String> typeVariables() {
332     HashSet<String> result = TypeInfo.typeVariables(mTypeInfo.typeArguments());
333     ClassInfo cl = containingClass();
334     while (cl != null) {
335       ArrayList<TypeInfo> types = cl.asTypeInfo().typeArguments();
336       if (types != null) {
337         TypeInfo.typeVariables(types, result);
338       }
339       cl = cl.containingClass();
340     }
341     return result;
342   }
343 
getTypeParameter(String qualifiedTypeName)344   public TypeInfo getTypeParameter(String qualifiedTypeName) {
345       List<TypeInfo> parameters = mTypeInfo.typeArguments();
346       if (parameters == null) {
347           return null;
348       }
349       for (TypeInfo parameter : parameters) {
350           if (parameter.qualifiedTypeName().equals(qualifiedTypeName)) {
351               return parameter;
352           }
353       }
354       return null;
355   }
356 
357   /**
358    * List of only direct interface's classes, without worrying about type param mapping.
359    * This can't be lazy loaded, because its overloads depend on changing type parameters
360    * passed in from the callers.
361    */
justMyInterfacesWithTypes()362   private List<ClassTypePair> justMyInterfacesWithTypes() {
363     return justMyInterfacesWithTypes(Collections.<String, TypeInfo>emptyMap());
364   }
365 
366   /**
367    * List of only direct interface's classes and their parameterized types.
368    * This can't be lazy loaded, because of the passed in typeArgumentsMap.
369    */
justMyInterfacesWithTypes(Map<String, TypeInfo> typeArgumentsMap)370   private List<ClassTypePair> justMyInterfacesWithTypes(Map<String, TypeInfo> typeArgumentsMap) {
371     if (mRealInterfaces == null || mRealInterfaceTypes == null) {
372       return Collections.<ClassTypePair>emptyList();
373     }
374 
375     List<ClassTypePair> list = new ArrayList<ClassTypePair>();
376     for (int i = 0; i < mRealInterfaces.size(); i++) {
377       ClassInfo iface = mRealInterfaces.get(i);
378       TypeInfo type = mRealInterfaceTypes.get(i);
379       if (iface != null && type != null) {
380         type = type.getTypeWithArguments(typeArgumentsMap);
381         if (iface.checkLevel()) {
382           list.add(new ClassTypePair(iface, type));
383         } else {
384           // add the interface's interfaces
385           Map<String, TypeInfo> map = TypeInfo.getTypeArgumentMapping(iface.asTypeInfo(), type);
386           list.addAll(iface.justMyInterfacesWithTypes(map));
387         }
388       }
389     }
390     return list;
391   }
392 
393   /**
394    * List of only direct interface's classes, and any hidden superclass's direct interfaces
395    * between this class and the first visible superclass and those interface class's parameterized types.
396    */
interfacesWithTypes()397   private ArrayList<ClassTypePair> interfacesWithTypes() {
398     if (mInterfacesWithTypes == null) {
399       mInterfacesWithTypes = new ArrayList<ClassTypePair>();
400 
401       Iterator<ClassTypePair> itr = superClassesWithTypes().iterator();
402       // skip the first one, which is this class
403       itr.next();
404       while (itr.hasNext()) {
405         ClassTypePair ctp = itr.next();
406         if (ctp.classInfo().checkLevel()) {
407           break;
408         } else {
409           // fill mInterfacesWithTypes from the hidden superclass
410           mInterfacesWithTypes.addAll(
411               ctp.classInfo().justMyInterfacesWithTypes(ctp.getTypeArgumentMapping()));
412         }
413       }
414       mInterfacesWithTypes.addAll(
415           justMyInterfacesWithTypes());
416     }
417     return mInterfacesWithTypes;
418   }
419 
420   /**
421    * List of all interface's classes reachable in this class's inheritance hierarchy
422    * and those interface class's parameterized types.
423    */
allInterfacesWithTypes()424   private ArrayList<ClassTypePair> allInterfacesWithTypes() {
425     if (mAllInterfacesWithTypes == null) {
426         mAllInterfacesWithTypes = new ArrayList<ClassTypePair>();
427         Queue<ClassTypePair> toParse = new ArrayDeque<ClassTypePair>();
428         Set<String> visited = new HashSet<String>();
429 
430         Iterator<ClassTypePair> itr = superClassesWithTypes().iterator();
431         // skip the first one, which is this class
432         itr.next();
433         while (itr.hasNext()) {
434           ClassTypePair ctp = itr.next();
435           toParse.addAll(
436               ctp.classInfo().justMyInterfacesWithTypes(ctp.getTypeArgumentMapping()));
437         }
438         toParse.addAll(justMyInterfacesWithTypes());
439         while (!toParse.isEmpty()) {
440           ClassTypePair ctp = toParse.remove();
441           if (!visited.contains(ctp.typeInfo().fullName())) {
442             mAllInterfacesWithTypes.add(ctp);
443             visited.add(ctp.typeInfo().fullName());
444             toParse.addAll(ctp.classInfo().justMyInterfacesWithTypes(ctp.getTypeArgumentMapping()));
445           }
446         }
447     }
448     return mAllInterfacesWithTypes;
449   }
450 
451   /**
452    * A list of ClassTypePairs that contain all superclasses
453    * and their corresponding types. The types will have type parameters
454    * cascaded upwards so they match, if any classes along the way set them.
455    * The list includes the current class, and is an ascending order up the
456    * heirarchy tree.
457    * */
superClassesWithTypes()458   private ArrayList<ClassTypePair> superClassesWithTypes() {
459     if (mSuperclassesWithTypes == null) {
460       mSuperclassesWithTypes = new ArrayList<ClassTypePair>();
461 
462       ClassTypePair lastCtp = new ClassTypePair(this, this.asTypeInfo());
463       mSuperclassesWithTypes.add(lastCtp);
464 
465       Map<String, TypeInfo> typeArgumentsMap;
466       ClassInfo superclass = mRealSuperclass;
467       TypeInfo supertype = mRealSuperclassType;
468       TypeInfo nextType;
469       while (superclass != null && supertype != null) {
470         typeArgumentsMap = lastCtp.getTypeArgumentMapping();
471         lastCtp = new ClassTypePair(superclass, supertype.getTypeWithArguments(typeArgumentsMap));
472         mSuperclassesWithTypes.add(lastCtp);
473 
474         supertype = superclass.mRealSuperclassType;
475         superclass = superclass.mRealSuperclass;
476       }
477     }
478     return mSuperclassesWithTypes;
479   }
480 
gatherHiddenInterfaces(ClassInfo cl, HashSet<ClassInfo> interfaces)481   private static void gatherHiddenInterfaces(ClassInfo cl, HashSet<ClassInfo> interfaces) {
482     for (ClassInfo iface : cl.mRealInterfaces) {
483       if (iface.checkLevel()) {
484         interfaces.add(iface);
485       } else {
486         gatherHiddenInterfaces(iface, interfaces);
487       }
488     }
489   }
490 
interfaces()491   public ArrayList<ClassInfo> interfaces() {
492     if (mInterfaces == null) {
493       if (checkLevel()) {
494         HashSet<ClassInfo> interfaces = new HashSet<ClassInfo>();
495         ClassInfo superclass = mRealSuperclass;
496         while (superclass != null && !superclass.checkLevel()) {
497           gatherHiddenInterfaces(superclass, interfaces);
498           superclass = superclass.mRealSuperclass;
499         }
500         gatherHiddenInterfaces(this, interfaces);
501         mInterfaces = new ArrayList<ClassInfo>(interfaces);
502       } else {
503         // put something here in case someone uses it
504         mInterfaces = new ArrayList<ClassInfo>(mRealInterfaces);
505       }
506       Collections.sort(mInterfaces, ClassInfo.qualifiedComparator);
507     }
508     return mInterfaces;
509   }
510 
realInterfaces()511   public ArrayList<ClassInfo> realInterfaces() {
512     return mRealInterfaces;
513   }
514 
realInterfaceTypes()515   ArrayList<TypeInfo> realInterfaceTypes() {
516     return mRealInterfaceTypes;
517   }
518 
addInterfaceType(TypeInfo type)519   public void addInterfaceType(TypeInfo type) {
520       if (mRealInterfaceTypes == null) {
521           mRealInterfaceTypes = new ArrayList<TypeInfo>();
522       }
523 
524       mRealInterfaceTypes.add(type);
525   }
526 
name()527   public String name() {
528     return mName;
529   }
530 
nameParts()531   public String[] nameParts() {
532     return mNameParts;
533   }
534 
leafName()535   public String leafName() {
536     return mNameParts[mNameParts.length - 1];
537   }
538 
qualifiedName()539   public String qualifiedName() {
540     return mQualifiedName;
541   }
542 
qualifiedTypeName()543   public String qualifiedTypeName() {
544     return mQualifiedTypeName;
545   }
546 
isPrimitive()547   public boolean isPrimitive() {
548     return mIsPrimitive;
549   }
550 
allConstructors()551   public ArrayList<MethodInfo> allConstructors() {
552     return mAllConstructors;
553   }
554 
constructors()555   public ArrayList<MethodInfo> constructors() {
556     if (mConstructors == null) {
557       if (mAllConstructors == null) {
558         return new ArrayList<MethodInfo>();
559       }
560 
561       mConstructors = new ArrayList<MethodInfo>();
562       for (MethodInfo m : mAllConstructors) {
563         if (!m.isHiddenOrRemoved()) {
564             mConstructors.add(m);
565         }
566       }
567 
568       Collections.sort(mConstructors, MethodInfo.comparator);
569     }
570     return mConstructors;
571   }
572 
innerClasses()573   public ArrayList<ClassInfo> innerClasses() {
574     return mInnerClasses;
575   }
576 
inlineTags()577   public TagInfo[] inlineTags() {
578     return comment().tags();
579   }
580 
firstSentenceTags()581   public TagInfo[] firstSentenceTags() {
582     return comment().briefTags();
583   }
584 
setDeprecated(boolean deprecated)585   public void setDeprecated(boolean deprecated) {
586     mDeprecatedKnown = true;
587     mIsDeprecated = deprecated;
588   }
589 
isDeprecated()590   public boolean isDeprecated() {
591     if (!mDeprecatedKnown) {
592       boolean commentDeprecated = comment().isDeprecated();
593       boolean annotationDeprecated = false;
594       for (AnnotationInstanceInfo annotation : annotations()) {
595         if (annotation.type().qualifiedName().equals("java.lang.Deprecated")) {
596           annotationDeprecated = true;
597           break;
598         }
599       }
600 
601       // Check to see that the JavaDoc contains @deprecated AND the method is marked as @Deprecated.
602       // Otherwise, warn.
603       // Note: We only do this for "included" classes (i.e. those we have source code for); we do
604       // not have comments for classes from .class files but we do know whether a class is marked
605       // as @Deprecated.
606       if (isIncluded() && !isHiddenOrRemoved() && commentDeprecated != annotationDeprecated) {
607         Errors.error(Errors.DEPRECATION_MISMATCH, position(), "Class " + qualifiedName()
608             + ": @Deprecated annotation (" + (annotationDeprecated ? "" : "not ")
609             + "present) and @deprecated doc tag (" + (commentDeprecated ? "" : "not ")
610             + "present) do not match");
611       }
612 
613       mIsDeprecated = commentDeprecated | annotationDeprecated;
614       mDeprecatedKnown = true;
615     }
616     return mIsDeprecated;
617   }
618 
deprecatedTags()619   public TagInfo[] deprecatedTags() {
620     // Should we also do the interfaces?
621     return comment().deprecatedTags();
622   }
623 
methods()624   public ArrayList<MethodInfo> methods() {
625       if (mMethods == null) {
626           TreeMap<String, MethodInfo> all = new TreeMap<String, MethodInfo>();
627 
628           ArrayList<ClassInfo> interfaces = interfaces();
629           for (ClassInfo iface : interfaces) {
630             if (iface != null) {
631               for (MethodInfo method : iface.methods()) {
632                 all.put(method.getHashableName(), method);
633               }
634             }
635           }
636 
637           ClassInfo superclass = superclass();
638           if (superclass != null) {
639             for (MethodInfo method : superclass.methods()) {
640                 all.put(method.getHashableName(), method);
641             }
642           }
643 
644           for (MethodInfo method : selfMethods()) {
645               all.put(method.getHashableName(), method);
646           }
647 
648           mMethods = new ArrayList<MethodInfo>(all.values());
649           Collections.sort(mMethods, MethodInfo.comparator);
650       }
651     return mMethods;
652   }
653 
annotationElements()654   public ArrayList<MethodInfo> annotationElements() {
655     return mAnnotationElements;
656   }
657 
annotations()658   public ArrayList<AnnotationInstanceInfo> annotations() {
659     return mAnnotations;
660   }
661 
addFields(ClassInfo cl, TreeMap<String, FieldInfo> all)662   private static void addFields(ClassInfo cl, TreeMap<String, FieldInfo> all) {
663     for (FieldInfo field : cl.fields()) {
664         all.put(field.name(), field);
665     }
666   }
667 
fields()668   public ArrayList<FieldInfo> fields() {
669     if (mFields == null) {
670       TreeMap<String, FieldInfo> all = new TreeMap<String, FieldInfo>();
671 
672       for (ClassInfo iface : interfaces()) {
673         addFields(iface, all);
674       }
675 
676       ClassInfo superclass = superclass();
677       if (superclass != null) {
678         addFields(superclass, all);
679       }
680 
681       for (FieldInfo field : selfFields()) {
682         if (!field.isHiddenOrRemoved()) {
683             all.put(field.name(), field);
684         }
685       }
686 
687       for (FieldInfo enumConst : mEnumConstants) {
688         if (!enumConst.isHiddenOrRemoved()) {
689             all.put(enumConst.name(), enumConst);
690         }
691       }
692 
693       mFields = new ArrayList<FieldInfo>(all.values());
694     }
695     return mFields;
696   }
697 
gatherFields(ClassInfo owner, ClassInfo cl, HashMap<String, FieldInfo> fields)698   public void gatherFields(ClassInfo owner, ClassInfo cl, HashMap<String, FieldInfo> fields) {
699     for (FieldInfo f : cl.selfFields()) {
700       if (f.checkLevel()) {
701         fields.put(f.name(), f.cloneForClass(owner));
702       }
703     }
704   }
705 
selfFields()706   public ArrayList<FieldInfo> selfFields() {
707     if (mSelfFields == null) {
708         HashMap<String, FieldInfo> fields = new HashMap<String, FieldInfo>();
709       // our hidden parents
710       if (mRealSuperclass != null && !mRealSuperclass.checkLevel()) {
711         gatherFields(this, mRealSuperclass, fields);
712       }
713       for (ClassInfo iface : mRealInterfaces) {
714         if (!iface.checkLevel()) {
715           gatherFields(this, iface, fields);
716         }
717       }
718 
719       for (FieldInfo f : mAllSelfFields) {
720           if (!f.isHiddenOrRemoved()) {
721               fields.put(f.name(), f);
722           }
723       }
724 
725       mSelfFields = new ArrayList<FieldInfo>(fields.values());
726       Collections.sort(mSelfFields, FieldInfo.comparator);
727     }
728     return mSelfFields;
729   }
730 
allSelfFields()731   public ArrayList<FieldInfo> allSelfFields() {
732     return mAllSelfFields;
733   }
734 
gatherMethods(ClassInfo owner, ClassTypePair ctp, HashMap<String, MethodInfo> methods)735   private void gatherMethods(ClassInfo owner, ClassTypePair ctp, HashMap<String, MethodInfo> methods) {
736     for (MethodInfo m : ctp.classInfo().selfMethods()) {
737       if (m.checkLevel()) {
738         methods.put(m.name() + m.signature(), m.cloneForClass(owner, ctp.getTypeArgumentMapping()));
739       }
740     }
741   }
742 
selfMethods()743   public ArrayList<MethodInfo> selfMethods() {
744     if (mSelfMethods == null) {
745         HashMap<String, MethodInfo> methods = new HashMap<String, MethodInfo>();
746       // our hidden parents
747       for (ClassTypePair ctp : superClassesWithTypes()) {
748         // this class is included in this list, so skip it!
749         if (ctp.classInfo() != this) {
750           if (ctp.classInfo().checkLevel()) {
751             break;
752           }
753           gatherMethods(this, ctp, methods);
754         }
755       }
756       for (ClassTypePair ctp : justMyInterfacesWithTypes(Collections.<String, TypeInfo>emptyMap())) {
757         if (!ctp.classInfo().checkLevel()) {
758           gatherMethods(this, ctp, methods);
759         }
760       }
761       // mine
762       if (mAllSelfMethods != null) {
763         for (MethodInfo m : mAllSelfMethods) {
764           if (m.checkLevel()) {
765             methods.put(m.name() + m.signature(), m);
766           }
767         }
768       }
769 
770       for (MethodInfo mi : annotationElements()) {
771         if (!mi.isHiddenOrRemoved()) {
772           // add annotation element as a field
773           methods.put(mi.name() + mi.signature(), mi);
774         }
775       }
776 
777       // sort it
778       mSelfMethods = new ArrayList<MethodInfo>(methods.values());
779       Collections.sort(mSelfMethods, MethodInfo.comparator);
780     }
781     return mSelfMethods;
782   }
783 
allSelfMethods()784   public ArrayList<MethodInfo> allSelfMethods() {
785     return mAllSelfMethods;
786   }
787 
788   /**
789    * @param removedMethods the removed methods regardless of access levels.
790    */
setRemovedMethods(List<MethodInfo> removedMethods)791   public void setRemovedMethods(List<MethodInfo> removedMethods) {
792     Collections.sort(removedMethods, MethodInfo.comparator);
793     mRemovedMethods = Collections.unmodifiableList(removedMethods);
794   }
795 
setExhaustiveConstructors(List<MethodInfo> constructors)796   public void setExhaustiveConstructors(List<MethodInfo> constructors) {
797     mExhaustiveConstructors = constructors;
798   }
799 
setExhaustiveMethods(List<MethodInfo> methods)800   public void setExhaustiveMethods(List<MethodInfo> methods) {
801     mExhaustiveMethods = methods;
802   }
803 
setExhaustiveEnumConstants(List<FieldInfo> enumConstants)804   public void setExhaustiveEnumConstants(List<FieldInfo> enumConstants) {
805     mExhaustiveEnumConstants = enumConstants;
806   }
807 
setExhaustiveFields(List<FieldInfo> fields)808   public void setExhaustiveFields(List<FieldInfo> fields) {
809     mExhaustiveFields = fields;
810   }
811 
812   /**
813    * @return all methods that are marked as removed, regardless of access levels.
814    * The returned list is sorted and unmodifiable.
815    */
getRemovedMethods()816   public List<MethodInfo> getRemovedMethods() {
817     return mRemovedMethods;
818   }
819 
getExhaustiveConstructors()820   public List<MethodInfo> getExhaustiveConstructors() {
821     return mExhaustiveConstructors;
822   }
823 
getExhaustiveMethods()824   public List<MethodInfo> getExhaustiveMethods() {
825     return mExhaustiveMethods;
826   }
827 
getExhaustiveEnumConstants()828   public List<FieldInfo> getExhaustiveEnumConstants() {
829     return mExhaustiveEnumConstants;
830   }
831 
getExhaustiveFields()832   public List<FieldInfo> getExhaustiveFields() {
833     return mExhaustiveFields;
834   }
835 
836   /**
837    * Return list of ancestor classes that contribute to this class through
838    * inheritance. Ordered from most general to most specific with all interfaces
839    * listed before concrete classes.
840    */
gatherAncestorClasses()841   public List<ClassInfo> gatherAncestorClasses() {
842     LinkedList<ClassInfo> classes = gatherAncestorClasses(new LinkedList<>());
843     classes.removeLast();
844     return classes;
845   }
846 
gatherAncestorClasses(LinkedList<ClassInfo> classes)847   private LinkedList<ClassInfo> gatherAncestorClasses(LinkedList<ClassInfo> classes) {
848     classes.add(0, this);
849     if (mRealSuperclass != null) {
850       mRealSuperclass.gatherAncestorClasses(classes);
851     }
852     if (mRealInterfaces != null) {
853       for (ClassInfo clazz : mRealInterfaces) {
854         clazz.gatherAncestorClasses(classes);
855       }
856     }
857     return classes;
858   }
859 
860   /**
861    * Return superclass matching the given predicate. When a superclass doesn't
862    * match, we'll keep crawling up the tree until we find someone who matches.
863    */
filteredSuperclass(Predicate<MemberInfo> predicate)864   public ClassInfo filteredSuperclass(Predicate<MemberInfo> predicate) {
865     if (mRealSuperclass == null) {
866       return null;
867     } else if (predicate.test(mRealSuperclass.asMemberInfo())) {
868       return mRealSuperclass;
869     } else {
870       return mRealSuperclass.filteredSuperclass(predicate);
871     }
872   }
873 
874   /**
875    * Return interfaces matching the given predicate. When a superclass or
876    * interface doesn't match, we'll keep crawling up the tree until we find
877    * someone who matches.
878    */
filteredInterfaces(Predicate<MemberInfo> predicate)879   public Collection<ClassInfo> filteredInterfaces(Predicate<MemberInfo> predicate) {
880     return filteredInterfaces(predicate, new LinkedHashSet<>());
881   }
882 
filteredInterfaces(Predicate<MemberInfo> predicate, LinkedHashSet<ClassInfo> classes)883   private LinkedHashSet<ClassInfo> filteredInterfaces(Predicate<MemberInfo> predicate,
884       LinkedHashSet<ClassInfo> classes) {
885     if (mRealSuperclass != null && !predicate.test(mRealSuperclass.asMemberInfo())) {
886       mRealSuperclass.filteredInterfaces(predicate, classes);
887     }
888     if (mRealInterfaces != null) {
889       for (ClassInfo clazz : mRealInterfaces) {
890         if (predicate.test(clazz.asMemberInfo())) {
891           classes.add(clazz);
892         } else {
893           clazz.filteredInterfaces(predicate, classes);
894         }
895       }
896     }
897     return classes;
898   }
899 
900   /**
901    * Return methods matching the given predicate. Forcibly includes local
902    * methods that override a matching method in an ancestor class.
903    */
filteredMethods(Predicate<MemberInfo> predicate)904   public Collection<MethodInfo> filteredMethods(Predicate<MemberInfo> predicate) {
905     Set<MethodInfo> methods = new LinkedHashSet<>();
906     for (MethodInfo method : getExhaustiveMethods()) {
907       if (predicate.test(method) || (method.findPredicateOverriddenMethod(predicate) != null)) {
908         methods.remove(method);
909         methods.add(method);
910       }
911     }
912     return methods;
913   }
914 
915   /**
916    * Return fields matching the given predicate. Also clones fields from
917    * ancestors that would match had they been defined in this class.
918    */
filteredFields(Predicate<MemberInfo> predicate)919   public Collection<FieldInfo> filteredFields(Predicate<MemberInfo> predicate) {
920     Set<FieldInfo> fields = new LinkedHashSet<>();
921     if (Doclava.showUnannotated) {
922       for (ClassInfo clazz : gatherAncestorClasses()) {
923         if (!clazz.isInterface()) continue;
924         for (FieldInfo field : clazz.getExhaustiveFields()) {
925           if (!predicate.test(field)) {
926             field = field.cloneForClass(this);
927             if (predicate.test(field)) {
928               fields.remove(field);
929               fields.add(field);
930             }
931           }
932         }
933       }
934     }
935     for (FieldInfo field : getExhaustiveFields()) {
936       if (predicate.test(field)) {
937         fields.remove(field);
938         fields.add(field);
939       }
940     }
941     return fields;
942   }
943 
addMethod(MethodInfo method)944   public void addMethod(MethodInfo method) {
945     mApiCheckMethods.put(method.getHashableName(), method);
946 
947     mAllSelfMethods.add(method);
948     mSelfMethods = null; // flush this, hopefully it hasn't been used yet.
949   }
950 
addAnnotationElement(MethodInfo method)951   public void addAnnotationElement(MethodInfo method) {
952     mAnnotationElements.add(method);
953   }
954 
955   // Called by PackageInfo when a ClassInfo is added to a package.
956   // This is needed because ApiCheck uses PackageInfo.addClass
957   // rather than using setContainingPackage to dispatch to the
958   // appropriate method. TODO: move ApiCheck away from addClass.
setPackage(PackageInfo pkg)959   void setPackage(PackageInfo pkg) {
960     mContainingPackage = pkg;
961   }
962 
setContainingPackage(PackageInfo pkg)963   public void setContainingPackage(PackageInfo pkg) {
964     mContainingPackage = pkg;
965 
966     if (mContainingPackage != null) {
967         if (mIsEnum) {
968             mContainingPackage.addEnum(this);
969         } else if (mIsInterface) {
970             mContainingPackage.addInterface(this);
971         } else {
972             mContainingPackage.addOrdinaryClass(this);
973         }
974     }
975   }
976 
selfAttributes()977   public ArrayList<AttributeInfo> selfAttributes() {
978     if (mSelfAttributes == null) {
979       TreeMap<FieldInfo, AttributeInfo> attrs = new TreeMap<FieldInfo, AttributeInfo>();
980 
981       // the ones in the class comment won't have any methods
982       for (AttrTagInfo tag : comment().attrTags()) {
983         FieldInfo field = tag.reference();
984         if (field != null) {
985           AttributeInfo attr = attrs.get(field);
986           if (attr == null) {
987             attr = new AttributeInfo(this, field);
988             attrs.put(field, attr);
989           }
990           tag.setAttribute(attr);
991         }
992       }
993 
994       // in the methods
995       for (MethodInfo m : selfMethods()) {
996         for (AttrTagInfo tag : m.comment().attrTags()) {
997           FieldInfo field = tag.reference();
998           if (field != null) {
999             AttributeInfo attr = attrs.get(field);
1000             if (attr == null) {
1001               attr = new AttributeInfo(this, field);
1002               attrs.put(field, attr);
1003             }
1004             tag.setAttribute(attr);
1005             attr.methods.add(m);
1006           }
1007         }
1008       }
1009 
1010       // constructors too
1011       for (MethodInfo m : constructors()) {
1012         for (AttrTagInfo tag : m.comment().attrTags()) {
1013           FieldInfo field = tag.reference();
1014           if (field != null) {
1015             AttributeInfo attr = attrs.get(field);
1016             if (attr == null) {
1017               attr = new AttributeInfo(this, field);
1018               attrs.put(field, attr);
1019             }
1020             tag.setAttribute(attr);
1021             attr.methods.add(m);
1022           }
1023         }
1024       }
1025 
1026       mSelfAttributes = new ArrayList<AttributeInfo>(attrs.values());
1027       Collections.sort(mSelfAttributes, AttributeInfo.comparator);
1028     }
1029     return mSelfAttributes;
1030   }
1031 
enumConstants()1032   public ArrayList<FieldInfo> enumConstants() {
1033     return mEnumConstants;
1034   }
1035 
superclass()1036   public ClassInfo superclass() {
1037     if (!mSuperclassInit) {
1038       if (this.checkLevel()) {
1039         // rearrange our little inheritance hierarchy, because we need to hide classes that
1040         // don't pass checkLevel
1041         ClassInfo superclass = mRealSuperclass;
1042         while (superclass != null && !superclass.checkLevel()) {
1043           superclass = superclass.mRealSuperclass;
1044         }
1045         mSuperclass = superclass;
1046       } else {
1047         mSuperclass = mRealSuperclass;
1048       }
1049     }
1050     return mSuperclass;
1051   }
1052 
realSuperclass()1053   public ClassInfo realSuperclass() {
1054     return mRealSuperclass;
1055   }
1056 
1057   /**
1058    * always the real superclass, not the collapsed one we get through superclass(), also has the
1059    * type parameter info if it's generic.
1060    */
superclassType()1061   public TypeInfo superclassType() {
1062     return mRealSuperclassType;
1063   }
1064 
asTypeInfo()1065   public TypeInfo asTypeInfo() {
1066     return mTypeInfo;
1067   }
1068 
interfaceTypes()1069   ArrayList<TypeInfo> interfaceTypes() {
1070       ArrayList<TypeInfo> types = new ArrayList<TypeInfo>();
1071       for (ClassInfo iface : interfaces()) {
1072           types.add(iface.asTypeInfo());
1073       }
1074       return types;
1075   }
1076 
htmlPage()1077   public String htmlPage() {
1078     String s = containingPackage().name();
1079     s = s.replace('.', '/');
1080     s += '/';
1081     s += name();
1082     s += ".html";
1083     s = Doclava.javadocDir + s;
1084     return s;
1085   }
1086 
1087   /** Even indirectly */
isDerivedFrom(ClassInfo cl)1088   public boolean isDerivedFrom(ClassInfo cl) {
1089     return isDerivedFrom(cl.qualifiedName());
1090   }
1091 
1092   /** Even indirectly */
isDerivedFrom(String qualifiedName)1093   public boolean isDerivedFrom(String qualifiedName) {
1094     ClassInfo dad = this.superclass();
1095     if (dad != null) {
1096       if (dad.mQualifiedName.equals(qualifiedName)) {
1097         return true;
1098       } else {
1099         if (dad.isDerivedFrom(qualifiedName)) {
1100           return true;
1101         }
1102       }
1103     }
1104     for (ClassInfo iface : interfaces()) {
1105       if (iface.mQualifiedName.equals(qualifiedName)) {
1106         return true;
1107       } else {
1108         if (iface.isDerivedFrom(qualifiedName)) {
1109           return true;
1110         }
1111       }
1112     }
1113     return false;
1114   }
1115 
makeKeywordEntries(List<KeywordEntry> keywords)1116   public void makeKeywordEntries(List<KeywordEntry> keywords) {
1117     if (!checkLevel()) {
1118       return;
1119     }
1120 
1121     String htmlPage = htmlPage();
1122     String qualifiedName = qualifiedName();
1123 
1124     keywords.add(new KeywordEntry(name(), htmlPage, "class in " + containingPackage().name()));
1125 
1126     ArrayList<FieldInfo> fields = selfFields();
1127     //ArrayList<FieldInfo> enumConstants = enumConstants();
1128     ArrayList<MethodInfo> ctors = constructors();
1129     ArrayList<MethodInfo> methods = selfMethods();
1130 
1131     // enum constants
1132     for (FieldInfo field : enumConstants()) {
1133       if (field.checkLevel()) {
1134         keywords.add(new KeywordEntry(field.name(), htmlPage + "#" + field.anchor(),
1135             "enum constant in " + qualifiedName));
1136       }
1137     }
1138 
1139     // constants
1140     for (FieldInfo field : fields) {
1141       if (field.isConstant() && field.checkLevel()) {
1142         keywords.add(new KeywordEntry(field.name(), htmlPage + "#" + field.anchor(), "constant in "
1143             + qualifiedName));
1144       }
1145     }
1146 
1147     // fields
1148     for (FieldInfo field : fields) {
1149       if (!field.isConstant() && field.checkLevel()) {
1150         keywords.add(new KeywordEntry(field.name(), htmlPage + "#" + field.anchor(), "field in "
1151             + qualifiedName));
1152       }
1153     }
1154 
1155     // public constructors
1156     for (MethodInfo m : ctors) {
1157       if (m.isPublic() && m.checkLevel()) {
1158         keywords.add(new KeywordEntry(m.prettySignature(), htmlPage + "#" + m.anchor(),
1159             "constructor in " + qualifiedName));
1160       }
1161     }
1162 
1163     // protected constructors
1164     if (Doclava.checkLevel(Doclava.SHOW_PROTECTED)) {
1165       for (MethodInfo m : ctors) {
1166         if (m.isProtected() && m.checkLevel()) {
1167           keywords.add(new KeywordEntry(m.prettySignature(),
1168               htmlPage + "#" + m.anchor(), "constructor in " + qualifiedName));
1169         }
1170       }
1171     }
1172 
1173     // package private constructors
1174     if (Doclava.checkLevel(Doclava.SHOW_PACKAGE)) {
1175       for (MethodInfo m : ctors) {
1176         if (m.isPackagePrivate() && m.checkLevel()) {
1177           keywords.add(new KeywordEntry(m.prettySignature(),
1178               htmlPage + "#" + m.anchor(), "constructor in " + qualifiedName));
1179         }
1180       }
1181     }
1182 
1183     // private constructors
1184     if (Doclava.checkLevel(Doclava.SHOW_PRIVATE)) {
1185       for (MethodInfo m : ctors) {
1186         if (m.isPrivate() && m.checkLevel()) {
1187           keywords.add(new KeywordEntry(m.name() + m.prettySignature(),
1188               htmlPage + "#" + m.anchor(), "constructor in " + qualifiedName));
1189         }
1190       }
1191     }
1192 
1193     // public methods
1194     for (MethodInfo m : methods) {
1195       if (m.isPublic() && m.checkLevel()) {
1196         keywords.add(new KeywordEntry(m.name() + m.prettySignature(), htmlPage + "#" + m.anchor(),
1197             "method in " + qualifiedName));
1198       }
1199     }
1200 
1201     // protected methods
1202     if (Doclava.checkLevel(Doclava.SHOW_PROTECTED)) {
1203       for (MethodInfo m : methods) {
1204         if (m.isProtected() && m.checkLevel()) {
1205           keywords.add(new KeywordEntry(m.name() + m.prettySignature(),
1206               htmlPage + "#" + m.anchor(), "method in " + qualifiedName));
1207         }
1208       }
1209     }
1210 
1211     // package private methods
1212     if (Doclava.checkLevel(Doclava.SHOW_PACKAGE)) {
1213       for (MethodInfo m : methods) {
1214         if (m.isPackagePrivate() && m.checkLevel()) {
1215           keywords.add(new KeywordEntry(m.name() + m.prettySignature(),
1216               htmlPage + "#" + m.anchor(), "method in " + qualifiedName));
1217         }
1218       }
1219     }
1220 
1221     // private methods
1222     if (Doclava.checkLevel(Doclava.SHOW_PRIVATE)) {
1223       for (MethodInfo m : methods) {
1224         if (m.isPrivate() && m.checkLevel()) {
1225           keywords.add(new KeywordEntry(m.name() + m.prettySignature(),
1226               htmlPage + "#" + m.anchor(), "method in " + qualifiedName));
1227         }
1228       }
1229     }
1230   }
1231 
makeLink(Data data, String base)1232   public void makeLink(Data data, String base) {
1233     data.setValue(base + ".label", this.name());
1234     if (!this.isPrimitive() && this.isIncluded() && this.checkLevel()) {
1235       data.setValue(base + ".link", this.htmlPage());
1236     }
1237   }
1238 
makeLinkListHDF(Data data, String base, ClassInfo[] classes)1239   public static void makeLinkListHDF(Data data, String base, ClassInfo[] classes) {
1240     final int N = classes.length;
1241     for (int i = 0; i < N; i++) {
1242       ClassInfo cl = classes[i];
1243       if (cl.checkLevel()) {
1244         cl.asTypeInfo().makeHDF(data, base + "." + i);
1245       }
1246     }
1247   }
1248 
1249   /**
1250    * Used in lists of this class (packages, nested classes, known subclasses)
1251    */
makeShortDescrHDF(Data data, String base)1252   public void makeShortDescrHDF(Data data, String base) {
1253     mTypeInfo.makeHDF(data, base + ".type");
1254     data.setValue(base + ".kind", this.kind());
1255     TagInfo.makeHDF(data, base + ".shortDescr", this.firstSentenceTags());
1256     TagInfo.makeHDF(data, base + ".deprecated", deprecatedTags());
1257     data.setValue(base + ".since", getSince());
1258     data.setValue(base + ".sdkextsince", getSdkExtSince());
1259     if (isDeprecated()) {
1260       data.setValue(base + ".deprecatedsince", getDeprecatedSince());
1261     }
1262     data.setValue(base + ".artifact", getArtifact());
1263 
1264     ArrayList<AnnotationInstanceInfo> showAnnos = getShowAnnotationsIncludeOuters();
1265     AnnotationInstanceInfo.makeLinkListHDF(
1266       data,
1267       base + ".showAnnotations",
1268       showAnnos.toArray(new AnnotationInstanceInfo[showAnnos.size()]));
1269 
1270     setFederatedReferences(data, base);
1271   }
1272 
1273   /**
1274    * Turns into the main class page
1275    */
makeHDF(Data data)1276   public void makeHDF(Data data) {
1277     int i, j, n;
1278     String name = name();
1279     String qualified = qualifiedName();
1280     ArrayList<AttributeInfo> selfAttributes = selfAttributes();
1281     ArrayList<MethodInfo> methods = selfMethods();
1282     ArrayList<FieldInfo> fields = selfFields();
1283     ArrayList<FieldInfo> enumConstants = enumConstants();
1284     ArrayList<MethodInfo> ctors = constructors();
1285     ArrayList<ClassInfo> inners = innerClasses();
1286 
1287     // class name
1288     mTypeInfo.makeHDF(data, "class.type");
1289     mTypeInfo.makeQualifiedHDF(data, "class.qualifiedType");
1290     data.setValue("class.name", name);
1291     data.setValue("class.qualified", qualified);
1292     if (isProtected()) {
1293       data.setValue("class.scope", "protected");
1294     } else if (isPublic()) {
1295       data.setValue("class.scope", "public");
1296     }
1297     if (isStatic()) {
1298       data.setValue("class.static", "static");
1299     }
1300     if (isFinal()) {
1301       data.setValue("class.final", "final");
1302     }
1303     if (isAbstract() && !isInterface()) {
1304       data.setValue("class.abstract", "abstract");
1305     }
1306 
1307     int numAnnotationDocumentation = 0;
1308     for (AnnotationInstanceInfo aii : annotations()) {
1309       String annotationDocumentation = Doclava.getDocumentationStringForAnnotation(
1310           aii.type().qualifiedName());
1311       if (annotationDocumentation != null) {
1312         data.setValue("class.annotationdocumentation." + numAnnotationDocumentation + ".text",
1313             annotationDocumentation);
1314         numAnnotationDocumentation++;
1315       }
1316     }
1317 
1318     ArrayList<AnnotationInstanceInfo> showAnnos = getShowAnnotationsIncludeOuters();
1319     AnnotationInstanceInfo.makeLinkListHDF(
1320       data,
1321       "class.showAnnotations",
1322       showAnnos.toArray(new AnnotationInstanceInfo[showAnnos.size()]));
1323 
1324     // class info
1325     String kind = kind();
1326     if (kind != null) {
1327       data.setValue("class.kind", kind);
1328     }
1329     data.setValue("class.since", getSince());
1330     data.setValue("class.sdkextsince", getSdkExtSince());
1331     if (isDeprecated()) {
1332       data.setValue("class.deprecatedsince", getDeprecatedSince());
1333     }
1334     data.setValue("class.artifact", getArtifact());
1335     setFederatedReferences(data, "class");
1336 
1337     // the containing package -- note that this can be passed to type_link,
1338     // but it also contains the list of all of the packages
1339     containingPackage().makeClassLinkListHDF(data, "class.package");
1340 
1341     // inheritance hierarchy
1342     List<ClassTypePair> ctplist = superClassesWithTypes();
1343     n = ctplist.size();
1344     for (i = 0; i < ctplist.size(); i++) {
1345       // go in reverse order
1346       ClassTypePair ctp = ctplist.get(n - i - 1);
1347       if (ctp.classInfo().checkLevel()) {
1348         ctp.typeInfo().makeQualifiedHDF(data, "class.inheritance." + i + ".class");
1349         ctp.typeInfo().makeHDF(data, "class.inheritance." + i + ".short_class");
1350         j = 0;
1351         for (ClassTypePair t : ctp.classInfo().interfacesWithTypes()) {
1352           t.typeInfo().makeHDF(data, "class.inheritance." + i + ".interfaces." + j);
1353           j++;
1354         }
1355       }
1356     }
1357 
1358     // class description
1359     TagInfo.makeHDF(data, "class.descr", inlineTags());
1360     TagInfo.makeHDF(data, "class.descrAux", Doclava.auxSource.classAuxTags(this));
1361     TagInfo.makeHDF(data, "class.seeAlso", comment().seeTags());
1362     TagInfo.makeHDF(data, "class.deprecated", deprecatedTags());
1363 
1364     // known subclasses
1365     TreeMap<String, ClassInfo> direct = new TreeMap<String, ClassInfo>();
1366     TreeMap<String, ClassInfo> indirect = new TreeMap<String, ClassInfo>();
1367     Collection<ClassInfo> all = Converter.rootClasses();
1368     for (ClassInfo cl : all) {
1369       if (cl.superclass() != null && cl.superclass().equals(this)) {
1370         direct.put(cl.name(), cl);
1371       } else if (cl.isDerivedFrom(this)) {
1372         indirect.put(cl.name(), cl);
1373       }
1374     }
1375     // direct
1376     i = 0;
1377     for (ClassInfo cl : direct.values()) {
1378       if (cl.checkLevel()) {
1379         cl.makeShortDescrHDF(data, "class.subclasses.direct." + i);
1380       }
1381       i++;
1382     }
1383     // indirect
1384     i = 0;
1385     for (ClassInfo cl : indirect.values()) {
1386       if (cl.checkLevel()) {
1387         cl.makeShortDescrHDF(data, "class.subclasses.indirect." + i);
1388       }
1389       i++;
1390     }
1391 
1392     // hide special cases
1393     if ("java.lang.Object".equals(qualified) || "java.io.Serializable".equals(qualified)) {
1394       data.setValue("class.subclasses.hidden", "1");
1395     } else {
1396       data.setValue("class.subclasses.hidden", "0");
1397     }
1398 
1399     // nested classes
1400     i = 0;
1401     for (ClassInfo inner : inners) {
1402       if (inner.checkLevel()) {
1403         inner.makeShortDescrHDF(data, "class.inners." + i);
1404       }
1405       i++;
1406     }
1407 
1408     // enum constants
1409     i = 0;
1410     for (FieldInfo field : enumConstants) {
1411       field.makeHDF(data, "class.enumConstants." + i);
1412       i++;
1413     }
1414 
1415     // constants
1416     i = 0;
1417     for (FieldInfo field : fields) {
1418       if (field.isConstant()) {
1419         field.makeHDF(data, "class.constants." + i);
1420         i++;
1421       }
1422     }
1423 
1424     // fields
1425     i = 0;
1426     for (FieldInfo field : fields) {
1427       if (!field.isConstant()) {
1428         field.makeHDF(data, "class.fields." + i);
1429         i++;
1430       }
1431     }
1432 
1433     // public constructors
1434     i = 0;
1435     for (MethodInfo ctor : ctors) {
1436       if (ctor.isPublic()) {
1437         ctor.makeHDF(data, "class.ctors.public." + i);
1438         i++;
1439       }
1440     }
1441 
1442     // protected constructors
1443     if (Doclava.checkLevel(Doclava.SHOW_PROTECTED)) {
1444       i = 0;
1445       for (MethodInfo ctor : ctors) {
1446         if (ctor.isProtected()) {
1447           ctor.makeHDF(data, "class.ctors.protected." + i);
1448           i++;
1449         }
1450       }
1451     }
1452 
1453     // package private constructors
1454     if (Doclava.checkLevel(Doclava.SHOW_PACKAGE)) {
1455       i = 0;
1456       for (MethodInfo ctor : ctors) {
1457         if (ctor.isPackagePrivate()) {
1458           ctor.makeHDF(data, "class.ctors.package." + i);
1459           i++;
1460         }
1461       }
1462     }
1463 
1464     // private constructors
1465     if (Doclava.checkLevel(Doclava.SHOW_PRIVATE)) {
1466       i = 0;
1467       for (MethodInfo ctor : ctors) {
1468         if (ctor.isPrivate()) {
1469           ctor.makeHDF(data, "class.ctors.private." + i);
1470           i++;
1471         }
1472       }
1473     }
1474 
1475     // public methods
1476     i = 0;
1477     for (MethodInfo method : methods) {
1478       if (method.isPublic()) {
1479         method.makeHDF(data, "class.methods.public." + i);
1480         i++;
1481       }
1482     }
1483 
1484     // protected methods
1485     if (Doclava.checkLevel(Doclava.SHOW_PROTECTED)) {
1486       i = 0;
1487       for (MethodInfo method : methods) {
1488         if (method.isProtected()) {
1489           method.makeHDF(data, "class.methods.protected." + i);
1490           i++;
1491         }
1492       }
1493     }
1494 
1495     // package private methods
1496     if (Doclava.checkLevel(Doclava.SHOW_PACKAGE)) {
1497       i = 0;
1498       for (MethodInfo method : methods) {
1499         if (method.isPackagePrivate()) {
1500           method.makeHDF(data, "class.methods.package." + i);
1501           i++;
1502         }
1503       }
1504     }
1505 
1506     // private methods
1507     if (Doclava.checkLevel(Doclava.SHOW_PRIVATE)) {
1508       i = 0;
1509       for (MethodInfo method : methods) {
1510         if (method.isPrivate()) {
1511           method.makeHDF(data, "class.methods.private." + i);
1512           i++;
1513         }
1514       }
1515     }
1516 
1517     // xml attributes
1518     i = 0;
1519     for (AttributeInfo attr : selfAttributes) {
1520       if (attr.checkLevel()) {
1521         attr.makeHDF(data, "class.attrs." + i);
1522         i++;
1523       }
1524     }
1525 
1526     // inherited methods
1527     Iterator<ClassTypePair> superclassesItr = superClassesWithTypes().iterator();
1528     superclassesItr.next(); // skip the first one, which is the current class
1529     ClassTypePair superCtp;
1530     i = 0;
1531     while (superclassesItr.hasNext()) {
1532       superCtp = superclassesItr.next();
1533       if (superCtp.classInfo().checkLevel()) {
1534         makeInheritedHDF(data, i, superCtp);
1535         i++;
1536       }
1537     }
1538     Iterator<ClassTypePair> interfacesItr = allInterfacesWithTypes().iterator();
1539     while (interfacesItr.hasNext()) {
1540       superCtp = interfacesItr.next();
1541       if (superCtp.classInfo().checkLevel()) {
1542         makeInheritedHDF(data, i, superCtp);
1543         i++;
1544       }
1545     }
1546   }
1547 
makeInheritedHDF(Data data, int index, ClassTypePair ctp)1548   private static void makeInheritedHDF(Data data, int index, ClassTypePair ctp) {
1549     int i;
1550 
1551     String base = "class.inherited." + index;
1552     data.setValue(base + ".qualified", ctp.classInfo().qualifiedName());
1553     if (ctp.classInfo().checkLevel()) {
1554       data.setValue(base + ".link", ctp.classInfo().htmlPage());
1555     }
1556     String kind = ctp.classInfo().kind();
1557     if (kind != null) {
1558       data.setValue(base + ".kind", kind);
1559     }
1560 
1561     if (ctp.classInfo().mIsIncluded) {
1562       data.setValue(base + ".included", "true");
1563     } else {
1564       Doclava.federationTagger.tagAll(Arrays.asList(ctp.classInfo()));
1565       if (!ctp.classInfo().getFederatedReferences().isEmpty()) {
1566         FederatedSite site = ctp.classInfo().getFederatedReferences().iterator().next();
1567         data.setValue(base + ".link", site.linkFor(ctp.classInfo().htmlPage()));
1568         data.setValue(base + ".federated", site.name());
1569       }
1570     }
1571 
1572     // xml attributes
1573     i = 0;
1574     for (AttributeInfo attr : ctp.classInfo().selfAttributes()) {
1575       attr.makeHDF(data, base + ".attrs." + i);
1576       i++;
1577     }
1578 
1579     // methods
1580     i = 0;
1581     for (MethodInfo method : ctp.classInfo().selfMethods()) {
1582       method.makeHDF(data, base + ".methods." + i, ctp.getTypeArgumentMapping());
1583       i++;
1584     }
1585 
1586     // fields
1587     i = 0;
1588     for (FieldInfo field : ctp.classInfo().selfFields()) {
1589       if (!field.isConstant()) {
1590         field.makeHDF(data, base + ".fields." + i);
1591         i++;
1592       }
1593     }
1594 
1595     // constants
1596     i = 0;
1597     for (FieldInfo field : ctp.classInfo().selfFields()) {
1598       if (field.isConstant()) {
1599         field.makeHDF(data, base + ".constants." + i);
1600         i++;
1601       }
1602     }
1603   }
1604 
1605   @Override
isHidden()1606   public boolean isHidden() {
1607     if (mHidden == null) {
1608       mHidden = isHiddenImpl();
1609     }
1610 
1611     return mHidden;
1612   }
1613 
1614   /**
1615    * @return true if the containing package has @hide comment, a hide annotaion,
1616    * or a containing class of this class is hidden.
1617    */
isHiddenImpl()1618   public boolean isHiddenImpl() {
1619     ClassInfo cl = this;
1620     while (cl != null) {
1621       if (cl.hasShowAnnotation()) {
1622         return false;
1623       }
1624       PackageInfo pkg = cl.containingPackage();
1625       if (pkg != null && pkg.hasHideComment()) {
1626         return true;
1627       }
1628       if (cl.comment().isHidden() || cl.hasHideAnnotation()) {
1629         return true;
1630       }
1631       cl = cl.containingClass();
1632     }
1633     return false;
1634   }
1635 
1636   @Override
isRemoved()1637   public boolean isRemoved() {
1638     if (mRemoved == null) {
1639       mRemoved = isRemovedImpl();
1640     }
1641 
1642     return mRemoved;
1643   }
1644 
1645   /**
1646    * @return true if the containing package has @removed comment, or an ancestor
1647    * class of this class is removed, or this class has @removed comment.
1648    */
isRemovedImpl()1649   public boolean isRemovedImpl() {
1650     ClassInfo cl = this;
1651     while (cl != null) {
1652       PackageInfo pkg = cl.containingPackage();
1653       if (pkg != null && pkg.hasRemovedComment()) {
1654         return true;
1655       }
1656       if (cl.comment().isRemoved()) {
1657         return true;
1658       }
1659       cl = cl.containingClass();
1660     }
1661     return false;
1662   }
1663 
1664   @Override
isHiddenOrRemoved()1665   public boolean isHiddenOrRemoved() {
1666     return isHidden() || isRemoved();
1667   }
1668 
hasShowAnnotation()1669   public boolean hasShowAnnotation() {
1670     return mShowAnnotations != null && mShowAnnotations.size() > 0;
1671   }
1672 
showAnnotations()1673   public ArrayList<AnnotationInstanceInfo> showAnnotations() {
1674     return mShowAnnotations;
1675   }
1676 
hasHideAnnotation()1677   public boolean hasHideAnnotation() {
1678     return mHideAnnotations != null && mHideAnnotations.size() > 0;
1679   }
1680 
hideAnnotations()1681   public ArrayList<AnnotationInstanceInfo> hideAnnotations() {
1682     return mHideAnnotations;
1683   }
1684 
getShowAnnotationsIncludeOuters()1685   public ArrayList<AnnotationInstanceInfo> getShowAnnotationsIncludeOuters() {
1686     ArrayList<AnnotationInstanceInfo> allAnnotations = new ArrayList<AnnotationInstanceInfo>();
1687     ClassInfo cl = this;
1688     while (cl != null) {
1689       if (cl.showAnnotations() != null) {
1690         // Don't allow duplicates into the merged list
1691         for (AnnotationInstanceInfo newAii : cl.showAnnotations()) {
1692           boolean addIt = true;
1693           for (AnnotationInstanceInfo existingAii : allAnnotations) {
1694             if (existingAii.type().name() == newAii.type().name()) {
1695               addIt = false;
1696               break;
1697             }
1698           }
1699           if (addIt) {
1700             allAnnotations.add(newAii);
1701           }
1702         }
1703       }
1704       cl = cl.containingClass();
1705     }
1706     return allAnnotations;
1707   }
1708 
matchMethod(ArrayList<MethodInfo> methods, String name, String[] params, String[] dimensions, boolean varargs)1709   private MethodInfo matchMethod(ArrayList<MethodInfo> methods, String name, String[] params,
1710       String[] dimensions, boolean varargs) {
1711     for (MethodInfo method : methods) {
1712       if (method.name().equals(name)) {
1713         if (params == null) {
1714           return method;
1715         } else {
1716           if (method.matchesParams(params, dimensions, varargs)) {
1717             return method;
1718           }
1719         }
1720       }
1721     }
1722     return null;
1723   }
1724 
findMethod(String name, String[] params, String[] dimensions, boolean varargs)1725   public MethodInfo findMethod(String name, String[] params, String[] dimensions, boolean varargs) {
1726     // first look on our class, and our superclasses
1727 
1728     // for methods
1729     MethodInfo rv;
1730     rv = matchMethod(methods(), name, params, dimensions, varargs);
1731 
1732     if (rv != null) {
1733       return rv;
1734     }
1735 
1736     // for constructors
1737     rv = matchMethod(constructors(), name, params, dimensions, varargs);
1738     if (rv != null) {
1739       return rv;
1740     }
1741 
1742     // then recursively look at our containing class
1743     ClassInfo containing = containingClass();
1744     if (containing != null) {
1745       return containing.findMethod(name, params, dimensions, varargs);
1746     }
1747 
1748     return null;
1749   }
1750 
supportsMethod(MethodInfo method)1751   public boolean supportsMethod(MethodInfo method) {
1752     for (MethodInfo m : methods()) {
1753       if (m.getHashableName().equals(method.getHashableName())) {
1754         return true;
1755       }
1756     }
1757     return false;
1758   }
1759 
searchInnerClasses(String[] nameParts, int index)1760   private ClassInfo searchInnerClasses(String[] nameParts, int index) {
1761     String part = nameParts[index];
1762 
1763     ArrayList<ClassInfo> inners = mInnerClasses;
1764     for (ClassInfo in : inners) {
1765       String[] innerParts = in.nameParts();
1766       if (part.equals(innerParts[innerParts.length - 1])) {
1767         if (index == nameParts.length - 1) {
1768           return in;
1769         } else {
1770           return in.searchInnerClasses(nameParts, index + 1);
1771         }
1772       }
1773     }
1774     return null;
1775   }
1776 
extendedFindClass(String className)1777   public ClassInfo extendedFindClass(String className) {
1778     // ClassDoc.findClass has this bug that we're working around here:
1779     // If you have a class PackageManager with an inner class PackageInfo
1780     // and you call it with "PackageInfo" it doesn't find it.
1781     return searchInnerClasses(className.split("\\."), 0);
1782   }
1783 
findClass(String className)1784   public ClassInfo findClass(String className) {
1785     return Converter.obtainClass(mClass.findClass(className));
1786   }
1787 
findInnerClass(String className)1788   public ClassInfo findInnerClass(String className) {
1789     // ClassDoc.findClass won't find inner classes. To deal with that,
1790     // we try what they gave us first, but if that didn't work, then
1791     // we see if there are any periods in className, and start searching
1792     // from there.
1793     String[] nodes = className.split("\\.");
1794     ClassDoc cl = mClass;
1795 
1796     int N = nodes.length;
1797     for (int i = 0; i < N; ++i) {
1798       final String n = nodes[i];
1799       if (n.isEmpty() && i == 0) {
1800         // We skip over an empty classname component if it's at location 0. This is
1801         // to deal with names like ".Inner". java7 will return a bogus ClassInfo when
1802         // we call "findClass("") and the next iteration of the loop will throw a
1803         // runtime exception.
1804         continue;
1805       }
1806 
1807       cl = cl.findClass(n);
1808       if (cl == null) {
1809         return null;
1810       }
1811     }
1812 
1813     return Converter.obtainClass(cl);
1814   }
1815 
findField(String name)1816   public FieldInfo findField(String name) {
1817     // first look on our class, and our superclasses
1818     for (FieldInfo f : fields()) {
1819       if (f.name().equals(name)) {
1820         return f;
1821       }
1822     }
1823 
1824     // then look at our enum constants (these are really fields, maybe
1825     // they should be mixed into fields(). not sure)
1826     for (FieldInfo f : enumConstants()) {
1827       if (f.name().equals(name)) {
1828         return f;
1829       }
1830     }
1831 
1832     // then recursively look at our containing class
1833     ClassInfo containing = containingClass();
1834     if (containing != null) {
1835       return containing.findField(name);
1836     }
1837 
1838     return null;
1839   }
1840 
sortByName(ClassInfo[] classes)1841   public static ClassInfo[] sortByName(ClassInfo[] classes) {
1842     int i;
1843     Sorter[] sorted = new Sorter[classes.length];
1844     for (i = 0; i < sorted.length; i++) {
1845       ClassInfo cl = classes[i];
1846       sorted[i] = new Sorter(cl.name(), cl);
1847     }
1848 
1849     Arrays.sort(sorted);
1850 
1851     ClassInfo[] rv = new ClassInfo[classes.length];
1852     for (i = 0; i < rv.length; i++) {
1853       rv[i] = (ClassInfo) sorted[i].data;
1854     }
1855 
1856     return rv;
1857   }
1858 
setNonWrittenConstructors(ArrayList<MethodInfo> nonWritten)1859   public void setNonWrittenConstructors(ArrayList<MethodInfo> nonWritten) {
1860     mNonWrittenConstructors = nonWritten;
1861   }
1862 
getNonWrittenConstructors()1863   public ArrayList<MethodInfo> getNonWrittenConstructors() {
1864     return mNonWrittenConstructors;
1865   }
1866 
kind()1867   public String kind() {
1868     if (isOrdinaryClass()) {
1869       return "class";
1870     } else if (isInterface()) {
1871       return "interface";
1872     } else if (isEnum()) {
1873       return "enum";
1874     } else if (isError()) {
1875       return "class";
1876     } else if (isException()) {
1877       return "class";
1878     } else if (isAnnotation()) {
1879       return "@interface";
1880     }
1881     return null;
1882   }
1883 
scope()1884   public String scope() {
1885     if (isPublic()) {
1886       return "public";
1887     } else if (isProtected()) {
1888       return "protected";
1889     } else if (isPackagePrivate()) {
1890       return "";
1891     } else if (isPrivate()) {
1892       return "private";
1893     } else {
1894       throw new RuntimeException("invalid scope for object " + this);
1895     }
1896   }
1897 
setHiddenMethods(ArrayList<MethodInfo> mInfo)1898   public void setHiddenMethods(ArrayList<MethodInfo> mInfo) {
1899     mHiddenMethods = mInfo;
1900   }
1901 
getHiddenMethods()1902   public ArrayList<MethodInfo> getHiddenMethods() {
1903     return mHiddenMethods;
1904   }
1905 
1906   @Override
toString()1907   public String toString() {
1908     return this.qualifiedName();
1909   }
1910 
1911   @Override
equals(Object o)1912   public boolean equals(Object o) {
1913     if (this == o) {
1914       return true;
1915     } else if (o instanceof ClassInfo) {
1916       final ClassInfo c = (ClassInfo) o;
1917       return mQualifiedName.equals(c.mQualifiedName);
1918     } else {
1919       return false;
1920     }
1921   }
1922 
1923   @Override
hashCode()1924   public int hashCode() {
1925     return mQualifiedName.hashCode();
1926   }
1927 
setReasonIncluded(String reason)1928   public void setReasonIncluded(String reason) {
1929     mReasonIncluded = reason;
1930   }
1931 
getReasonIncluded()1932   public String getReasonIncluded() {
1933     return mReasonIncluded;
1934   }
1935 
1936   private ClassDoc mClass;
1937 
1938   // ctor
1939   private boolean mIsPublic;
1940   private boolean mIsProtected;
1941   private boolean mIsPackagePrivate;
1942   private boolean mIsPrivate;
1943   private boolean mIsStatic;
1944   private boolean mIsInterface;
1945   private boolean mIsAbstract;
1946   private boolean mIsOrdinaryClass;
1947   private boolean mIsException;
1948   private boolean mIsError;
1949   private boolean mIsEnum;
1950   private boolean mIsAnnotation;
1951   private boolean mIsFinal;
1952   private boolean mIsIncluded;
1953   private String mName;
1954   private String mQualifiedName;
1955   private String mQualifiedTypeName;
1956   private boolean mIsPrimitive;
1957   private TypeInfo mTypeInfo;
1958   private String[] mNameParts;
1959 
1960   // init
1961   private ArrayList<ClassInfo> mRealInterfaces = new ArrayList<ClassInfo>();
1962   private ArrayList<ClassInfo> mInterfaces;
1963   private ArrayList<TypeInfo> mRealInterfaceTypes;
1964   private ArrayList<ClassInfo> mInnerClasses;
1965   // mAllConstructors will not contain *all* constructors. Only the constructors that pass
1966   // checkLevel. @see {@link Converter#convertMethods(ConstructorDoc[])}
1967   private ArrayList<MethodInfo> mAllConstructors = new ArrayList<MethodInfo>();
1968   // mAllSelfMethods will not contain *all* self methods. Only the methods that pass
1969   // checkLevel. @see {@link Converter#convertMethods(MethodDoc[])}
1970   private ArrayList<MethodInfo> mAllSelfMethods = new ArrayList<MethodInfo>();
1971   private ArrayList<MethodInfo> mAnnotationElements = new ArrayList<MethodInfo>(); // if this class is an annotation
1972   private ArrayList<FieldInfo> mAllSelfFields = new ArrayList<FieldInfo>();
1973   private ArrayList<FieldInfo> mEnumConstants = new ArrayList<FieldInfo>();
1974   private PackageInfo mContainingPackage;
1975   private ClassInfo mContainingClass;
1976   private ClassInfo mRealSuperclass;
1977   private TypeInfo mRealSuperclassType;
1978   private ClassInfo mSuperclass;
1979   private ArrayList<AnnotationInstanceInfo> mAnnotations;
1980   private ArrayList<AnnotationInstanceInfo> mShowAnnotations;
1981   private ArrayList<AnnotationInstanceInfo> mHideAnnotations;
1982   private boolean mSuperclassInit;
1983   private boolean mDeprecatedKnown;
1984 
1985   // lazy
1986   private ArrayList<ClassTypePair> mSuperclassesWithTypes;
1987   private ArrayList<ClassTypePair> mInterfacesWithTypes;
1988   private ArrayList<ClassTypePair> mAllInterfacesWithTypes;
1989   private ArrayList<MethodInfo> mConstructors;
1990   private ArrayList<ClassInfo> mRealInnerClasses;
1991   private ArrayList<MethodInfo> mSelfMethods;
1992   private ArrayList<FieldInfo> mSelfFields;
1993   private ArrayList<AttributeInfo> mSelfAttributes;
1994   private ArrayList<MethodInfo> mMethods;
1995   private ArrayList<FieldInfo> mFields;
1996   private ArrayList<TypeInfo> mTypeParameters;
1997   private ArrayList<MethodInfo> mHiddenMethods;
1998   private Boolean mHidden = null;
1999   private Boolean mRemoved = null;
2000   private Boolean mCheckLevel = null;
2001   private String mReasonIncluded;
2002   private ArrayList<MethodInfo> mNonWrittenConstructors;
2003   private boolean mIsDeprecated;
2004 
2005   // TODO: Temporary members from apicheck migration.
2006   private HashMap<String, MethodInfo> mApiCheckConstructors = new HashMap<String, MethodInfo>();
2007   private HashMap<String, MethodInfo> mApiCheckMethods = new HashMap<String, MethodInfo>();
2008   private HashMap<String, FieldInfo> mApiCheckFields = new HashMap<String, FieldInfo>();
2009   private HashMap<String, FieldInfo> mApiCheckEnumConstants = new HashMap<String, FieldInfo>();
2010 
2011   // Resolutions
2012   private ArrayList<Resolution> mResolutions;
2013 
2014   private List<MethodInfo> mRemovedMethods; // immutable after you set its value.
2015 
2016   private List<MethodInfo> mExhaustiveConstructors; // immutable after you set its value.
2017   private List<MethodInfo> mExhaustiveMethods; // immutable after you set its value.
2018   private List<FieldInfo> mExhaustiveEnumConstants; // immutable after you set its value.
2019   private List<FieldInfo> mExhaustiveFields; // immutable after you set its value.
2020 
2021   /**
2022    * Returns true if {@code cl} implements the interface {@code iface} either by either being that
2023    * interface, implementing that interface or extending a type that implements the interface.
2024    */
implementsInterface(String iface)2025   public boolean implementsInterface(String iface) {
2026     if (qualifiedName().equals(iface)) {
2027       return true;
2028     }
2029     for (ClassInfo clImplements : realInterfaces()) {
2030       if (clImplements.implementsInterface(iface)) {
2031         return true;
2032       }
2033     }
2034     if (mSuperclass != null && mSuperclass.implementsInterface(iface)) {
2035       return true;
2036     }
2037     return false;
2038   }
2039 
2040   /**
2041    * Returns true if {@code this} extends the class {@code ext}.
2042    */
extendsClass(String cl)2043   public boolean extendsClass(String cl) {
2044     if (qualifiedName().equals(cl)) {
2045       return true;
2046     }
2047     if (mSuperclass != null && mSuperclass.extendsClass(cl)) {
2048       return true;
2049     }
2050     return false;
2051   }
2052 
2053   /**
2054    * Returns true if {@code this} is assignable to cl
2055    */
isAssignableTo(String cl)2056   public boolean isAssignableTo(String cl) {
2057     return implementsInterface(cl) || extendsClass(cl);
2058   }
2059 
addInterface(ClassInfo iface)2060   public void addInterface(ClassInfo iface) {
2061     mRealInterfaces.add(iface);
2062   }
2063 
addConstructor(MethodInfo ctor)2064   public void addConstructor(MethodInfo ctor) {
2065     mApiCheckConstructors.put(ctor.getHashableName(), ctor);
2066 
2067     mAllConstructors.add(ctor);
2068     mConstructors = null; // flush this, hopefully it hasn't been used yet.
2069   }
2070 
addField(FieldInfo field)2071   public void addField(FieldInfo field) {
2072     mApiCheckFields.put(field.name(), field);
2073 
2074     mAllSelfFields.add(field);
2075 
2076     mSelfFields = null; // flush this, hopefully it hasn't been used yet.
2077   }
2078 
addEnumConstant(FieldInfo field)2079   public void addEnumConstant(FieldInfo field) {
2080     mApiCheckEnumConstants.put(field.name(), field);
2081 
2082     mEnumConstants.add(field);
2083   }
2084 
setSuperClass(ClassInfo superclass)2085   public void setSuperClass(ClassInfo superclass) {
2086     mRealSuperclass = superclass;
2087     mSuperclass = superclass;
2088   }
2089 
allConstructorsMap()2090   public Map<String, MethodInfo> allConstructorsMap() {
2091     return mApiCheckConstructors;
2092   }
2093 
allFields()2094   public Map<String, FieldInfo> allFields() {
2095     return mApiCheckFields;
2096   }
2097 
allEnums()2098   public Map<String, FieldInfo> allEnums() {
2099     return mApiCheckEnumConstants;
2100   }
2101 
2102   /**
2103    * Returns all methods defined directly in this class. For a list of all
2104    * methods supported by this class, see {@link #methods()}.
2105    */
allMethods()2106   public Map<String, MethodInfo> allMethods() {
2107     return mApiCheckMethods;
2108   }
2109 
2110   /**
2111    * Returns the class hierarchy for this class, starting with this class.
2112    */
hierarchy()2113   public Iterable<ClassInfo> hierarchy() {
2114     List<ClassInfo> result = new ArrayList<ClassInfo>(4);
2115     for (ClassInfo c = this; c != null; c = c.mSuperclass) {
2116       result.add(c);
2117     }
2118     return result;
2119   }
2120 
superclassName()2121   public String superclassName() {
2122     if (mSuperclass == null) {
2123       if (mQualifiedName.equals("java.lang.Object")) {
2124         return null;
2125       }
2126       throw new UnsupportedOperationException("Superclass not set for " + qualifiedName());
2127     }
2128     return mSuperclass.mQualifiedName;
2129   }
2130 
setAnnotations(ArrayList<AnnotationInstanceInfo> annotations)2131   public void setAnnotations(ArrayList<AnnotationInstanceInfo> annotations) {
2132     mAnnotations = annotations;
2133   }
2134 
isConsistent(ClassInfo cl)2135   public boolean isConsistent(ClassInfo cl) {
2136     return isConsistent(cl, null, null);
2137   }
2138 
isConsistent(ClassInfo cl, List<MethodInfo> newCtors, List<MethodInfo> newMethods)2139   public boolean isConsistent(ClassInfo cl, List<MethodInfo> newCtors, List<MethodInfo> newMethods) {
2140     boolean consistent = true;
2141     boolean diffMode = (newCtors != null) && (newMethods != null);
2142 
2143     if (isInterface() != cl.isInterface()) {
2144       Errors.error(Errors.CHANGED_CLASS, cl.position(), "Class " + cl.qualifiedName()
2145           + " changed class/interface declaration");
2146       consistent = false;
2147     }
2148     for (ClassInfo iface : mRealInterfaces) {
2149       if (!cl.implementsInterface(iface.mQualifiedName)) {
2150         Errors.error(Errors.REMOVED_INTERFACE, cl.position(), "Class " + qualifiedName()
2151             + " no longer implements " + iface);
2152       }
2153     }
2154     for (ClassInfo iface : cl.mRealInterfaces) {
2155       if (!implementsInterface(iface.mQualifiedName)) {
2156         Errors.error(Errors.ADDED_INTERFACE, cl.position(), "Added interface " + iface
2157             + " to class " + qualifiedName());
2158         consistent = false;
2159       }
2160     }
2161 
2162     for (MethodInfo mInfo : mApiCheckMethods.values()) {
2163       if (cl.mApiCheckMethods.containsKey(mInfo.getHashableName())) {
2164         if (!mInfo.isConsistent(cl.mApiCheckMethods.get(mInfo.getHashableName()))) {
2165           consistent = false;
2166         }
2167       } else {
2168         /*
2169          * This class formerly provided this method directly, and now does not. Check our ancestry
2170          * to see if there's an inherited version that still fulfills the API requirement.
2171          */
2172         MethodInfo mi = ClassInfo.overriddenMethod(mInfo, cl);
2173         if (mi == null) {
2174           mi = ClassInfo.interfaceMethod(mInfo, cl);
2175         }
2176         if (mi == null) {
2177           if (mInfo.isDeprecated()) {
2178             Errors.error(Errors.REMOVED_DEPRECATED_METHOD, mInfo.position(),
2179                 "Removed deprecated public method " + mInfo.prettyQualifiedSignature());
2180           } else {
2181             Errors.error(Errors.REMOVED_METHOD, mInfo.position(),
2182                 "Removed public method " + mInfo.prettyQualifiedSignature());
2183           }
2184           consistent = false;
2185         }
2186       }
2187     }
2188     for (MethodInfo mInfo : cl.mApiCheckMethods.values()) {
2189       if (!mApiCheckMethods.containsKey(mInfo.getHashableName())) {
2190         /*
2191          * Similarly to the above, do not fail if this "new" method is really an override of an
2192          * existing superclass method.
2193          * But we should fail if this is overriding an abstract method, because method's
2194          * abstractness affects how users use it. See also Stubs.methodIsOverride().
2195          */
2196         MethodInfo mi = ClassInfo.overriddenMethod(mInfo, this);
2197         if (mi == null && mInfo.isAbstract()) {
2198           Errors.error(Errors.ADDED_ABSTRACT_METHOD, mInfo.position(),
2199               "Added abstract public method "
2200               + mInfo.prettyQualifiedSignature() + " to existing class");
2201           consistent = false;
2202         } else if (mi == null || mi.isAbstract() != mInfo.isAbstract()) {
2203             Errors.error(Errors.ADDED_METHOD, mInfo.position(), "Added public method "
2204                 + mInfo.prettyQualifiedSignature());
2205             if (diffMode) {
2206               newMethods.add(mInfo);
2207             }
2208             consistent = false;
2209           }
2210         }
2211     }
2212     if (diffMode) {
2213       Collections.sort(newMethods, MethodInfo.comparator);
2214     }
2215 
2216     for (MethodInfo mInfo : mApiCheckConstructors.values()) {
2217       if (cl.mApiCheckConstructors.containsKey(mInfo.getHashableName())) {
2218         if (!mInfo.isConsistent(cl.mApiCheckConstructors.get(mInfo.getHashableName()))) {
2219           consistent = false;
2220         }
2221       } else {
2222         if (mInfo.isDeprecated()) {
2223           Errors.error(Errors.REMOVED_DEPRECATED_METHOD, mInfo.position(),
2224               "Removed deprecated public constructor " + mInfo.prettyQualifiedSignature());
2225         } else {
2226           Errors.error(Errors.REMOVED_METHOD, mInfo.position(),
2227               "Removed public constructor " + mInfo.prettyQualifiedSignature());
2228         }
2229         consistent = false;
2230       }
2231     }
2232     for (MethodInfo mInfo : cl.mApiCheckConstructors.values()) {
2233       if (!mApiCheckConstructors.containsKey(mInfo.getHashableName())) {
2234         Errors.error(Errors.ADDED_METHOD, mInfo.position(), "Added public constructor "
2235             + mInfo.prettyQualifiedSignature());
2236         if (diffMode) {
2237           newCtors.add(mInfo);
2238         }
2239         consistent = false;
2240       }
2241     }
2242     if (diffMode) {
2243       Collections.sort(newCtors, MethodInfo.comparator);
2244     }
2245 
2246     for (FieldInfo mInfo : mApiCheckFields.values()) {
2247       if (cl.mApiCheckFields.containsKey(mInfo.name())) {
2248         if (!mInfo.isConsistent(cl.mApiCheckFields.get(mInfo.name()))) {
2249           consistent = false;
2250         }
2251       } else {
2252         if (mInfo.isDeprecated()) {
2253           Errors.error(Errors.REMOVED_DEPRECATED_FIELD, mInfo.position(),
2254               "Removed deprecated field " + mInfo.qualifiedName());
2255         } else {
2256           Errors.error(Errors.REMOVED_FIELD, mInfo.position(),
2257               "Removed field " + mInfo.qualifiedName());
2258         }
2259         consistent = false;
2260       }
2261     }
2262     for (FieldInfo mInfo : cl.mApiCheckFields.values()) {
2263       if (!mApiCheckFields.containsKey(mInfo.name())) {
2264         Errors.error(Errors.ADDED_FIELD, mInfo.position(), "Added public field "
2265             + mInfo.qualifiedName());
2266         consistent = false;
2267       }
2268     }
2269 
2270     for (FieldInfo info : mApiCheckEnumConstants.values()) {
2271       if (cl.mApiCheckEnumConstants.containsKey(info.name())) {
2272         if (!info.isConsistent(cl.mApiCheckEnumConstants.get(info.name()))) {
2273           consistent = false;
2274         }
2275       } else {
2276         if (info.isDeprecated()) {
2277           Errors.error(Errors.REMOVED_DEPRECATED_FIELD, info.position(),
2278               "Removed deprecated enum constant " + info.qualifiedName());
2279         } else {
2280           Errors.error(Errors.REMOVED_FIELD, info.position(),
2281               "Removed enum constant " + info.qualifiedName());
2282         }
2283         consistent = false;
2284       }
2285     }
2286     for (FieldInfo info : cl.mApiCheckEnumConstants.values()) {
2287       if (!mApiCheckEnumConstants.containsKey(info.name())) {
2288         Errors.error(Errors.ADDED_FIELD, info.position(), "Added enum constant "
2289             + info.qualifiedName());
2290         consistent = false;
2291       }
2292     }
2293 
2294     if (mIsAbstract != cl.mIsAbstract) {
2295       consistent = false;
2296       Errors.error(Errors.CHANGED_ABSTRACT, cl.position(), "Class " + cl.qualifiedName()
2297           + " changed abstract qualifier");
2298     }
2299 
2300     if (!mIsFinal && cl.mIsFinal) {
2301       /*
2302        * It is safe to make a class final if it did not previously have any public
2303        * constructors because it was impossible for an application to create a subclass.
2304        */
2305       if (mApiCheckConstructors.isEmpty()) {
2306         consistent = false;
2307         Errors.error(Errors.ADDED_FINAL_UNINSTANTIABLE, cl.position(),
2308             "Class " + cl.qualifiedName() + " added final qualifier but "
2309             + "was previously uninstantiable and therefore could not be subclassed");
2310       } else {
2311         consistent = false;
2312         Errors.error(Errors.ADDED_FINAL, cl.position(), "Class " + cl.qualifiedName()
2313             + " added final qualifier");
2314       }
2315     } else if (mIsFinal && !cl.mIsFinal) {
2316       consistent = false;
2317       Errors.error(Errors.REMOVED_FINAL, cl.position(), "Class " + cl.qualifiedName()
2318           + " removed final qualifier");
2319     }
2320 
2321     if (mIsStatic != cl.mIsStatic) {
2322       consistent = false;
2323       Errors.error(Errors.CHANGED_STATIC, cl.position(), "Class " + cl.qualifiedName()
2324           + " changed static qualifier");
2325     }
2326 
2327     if (!scope().equals(cl.scope())) {
2328       consistent = false;
2329       Errors.error(Errors.CHANGED_SCOPE, cl.position(), "Class " + cl.qualifiedName()
2330           + " scope changed from " + scope() + " to " + cl.scope());
2331     }
2332 
2333     if (!isDeprecated() == cl.isDeprecated()) {
2334       consistent = false;
2335       Errors.error(Errors.CHANGED_DEPRECATED, cl.position(), "Class " + cl.qualifiedName()
2336           + " has changed deprecation state " + isDeprecated() + " --> " + cl.isDeprecated());
2337     }
2338 
2339     if (superclassName() != null) { // java.lang.Object can't have a superclass.
2340       if (!cl.extendsClass(superclassName())) {
2341         consistent = false;
2342         Errors.error(Errors.CHANGED_SUPERCLASS, cl.position(), "Class " + qualifiedName()
2343             + " superclass changed from " + superclassName() + " to " + cl.superclassName());
2344       }
2345     }
2346 
2347     if (hasTypeParameters() && cl.hasTypeParameters()) {
2348       ArrayList<TypeInfo> oldParams = typeParameters();
2349       ArrayList<TypeInfo> newParams = cl.typeParameters();
2350       if (oldParams.size() != newParams.size()) {
2351         consistent = false;
2352         Errors.error(Errors.CHANGED_TYPE, cl.position(), "Class " + qualifiedName()
2353             + " changed number of type parameters from " + oldParams.size()
2354             + " to " + newParams.size());
2355       }
2356     }
2357 
2358     return consistent;
2359   }
2360 
2361   // Find a superclass implementation of the given method based on the methods in mApiCheckMethods.
overriddenMethod(MethodInfo candidate, ClassInfo newClassObj)2362   public static MethodInfo overriddenMethod(MethodInfo candidate, ClassInfo newClassObj) {
2363     if (newClassObj == null) {
2364       return null;
2365     }
2366     for (MethodInfo mi : newClassObj.mApiCheckMethods.values()) {
2367       if (mi.matches(candidate)) {
2368         // found it
2369         return mi;
2370       }
2371     }
2372 
2373     // not found here. recursively search ancestors
2374     return ClassInfo.overriddenMethod(candidate, newClassObj.mSuperclass);
2375   }
2376 
2377   // Find a superinterface declaration of the given method.
interfaceMethod(MethodInfo candidate, ClassInfo newClassObj)2378   public static MethodInfo interfaceMethod(MethodInfo candidate, ClassInfo newClassObj) {
2379     if (newClassObj == null) {
2380       return null;
2381     }
2382     for (ClassInfo interfaceInfo : newClassObj.interfaces()) {
2383       for (MethodInfo mi : interfaceInfo.mApiCheckMethods.values()) {
2384         if (mi.matches(candidate)) {
2385           return mi;
2386         }
2387       }
2388     }
2389     return ClassInfo.interfaceMethod(candidate, newClassObj.mSuperclass);
2390   }
2391 
hasConstructor(MethodInfo constructor)2392   public boolean hasConstructor(MethodInfo constructor) {
2393     String name = constructor.getHashableName();
2394     for (MethodInfo ctor : mApiCheckConstructors.values()) {
2395       if (name.equals(ctor.getHashableName())) {
2396         return true;
2397       }
2398     }
2399     return false;
2400   }
2401 
setTypeInfo(TypeInfo typeInfo)2402   public void setTypeInfo(TypeInfo typeInfo) {
2403     mTypeInfo = typeInfo;
2404   }
2405 
type()2406   public TypeInfo type() {
2407       return mTypeInfo;
2408   }
2409 
hasTypeParameters()2410   public boolean hasTypeParameters() {
2411       if (mTypeInfo != null && mTypeInfo.typeArguments() != null) {
2412           return !mTypeInfo.typeArguments().isEmpty();
2413       }
2414       return false;
2415   }
2416 
typeParameters()2417   public ArrayList<TypeInfo> typeParameters() {
2418       if (hasTypeParameters()) {
2419           return mTypeInfo.typeArguments();
2420       }
2421       return null;
2422   }
2423 
addInnerClass(ClassInfo innerClass)2424   public void addInnerClass(ClassInfo innerClass) {
2425       if (mInnerClasses == null) {
2426           mInnerClasses = new ArrayList<ClassInfo>();
2427       }
2428 
2429       mInnerClasses.add(innerClass);
2430   }
2431 
setContainingClass(ClassInfo containingClass)2432   public void setContainingClass(ClassInfo containingClass) {
2433       mContainingClass = containingClass;
2434   }
2435 
setSuperclassType(TypeInfo superclassType)2436   public void setSuperclassType(TypeInfo superclassType) {
2437       mRealSuperclassType = superclassType;
2438   }
2439 
printResolutions()2440   public void printResolutions() {
2441       if (mResolutions == null || mResolutions.isEmpty()) {
2442           return;
2443       }
2444 
2445       System.out.println("Resolutions for Class " + mName + ":");
2446 
2447       for (Resolution r : mResolutions) {
2448           System.out.println(r);
2449       }
2450   }
2451 
addResolution(Resolution resolution)2452   public void addResolution(Resolution resolution) {
2453       if (mResolutions == null) {
2454           mResolutions = new ArrayList<Resolution>();
2455       }
2456 
2457       mResolutions.add(resolution);
2458   }
2459 
resolveResolutions()2460   public boolean resolveResolutions() {
2461       ArrayList<Resolution> resolutions = mResolutions;
2462       mResolutions = new ArrayList<Resolution>();
2463 
2464       boolean allResolved = true;
2465       for (Resolution resolution : resolutions) {
2466           StringBuilder qualifiedClassName = new StringBuilder();
2467           InfoBuilder.resolveQualifiedName(resolution.getValue(), qualifiedClassName,
2468                   resolution.getInfoBuilder());
2469 
2470           // if we still couldn't resolve it, save it for the next pass
2471           if ("".equals(qualifiedClassName.toString())) {
2472               mResolutions.add(resolution);
2473               allResolved = false;
2474           } else if ("superclassQualifiedName".equals(resolution.getVariable())) {
2475               setSuperClass(InfoBuilder.Caches.obtainClass(qualifiedClassName.toString()));
2476           } else if ("interfaceQualifiedName".equals(resolution.getVariable())) {
2477               addInterface(InfoBuilder.Caches.obtainClass(qualifiedClassName.toString()));
2478           }
2479       }
2480 
2481       return allResolved;
2482   }
2483 }
2484