• 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     if (isDeprecated()) {
1259       data.setValue(base + ".deprecatedsince", getDeprecatedSince());
1260     }
1261     data.setValue(base + ".artifact", getArtifact());
1262 
1263     ArrayList<AnnotationInstanceInfo> showAnnos = getShowAnnotationsIncludeOuters();
1264     AnnotationInstanceInfo.makeLinkListHDF(
1265       data,
1266       base + ".showAnnotations",
1267       showAnnos.toArray(new AnnotationInstanceInfo[showAnnos.size()]));
1268 
1269     setFederatedReferences(data, base);
1270   }
1271 
1272   /**
1273    * Turns into the main class page
1274    */
makeHDF(Data data)1275   public void makeHDF(Data data) {
1276     int i, j, n;
1277     String name = name();
1278     String qualified = qualifiedName();
1279     ArrayList<AttributeInfo> selfAttributes = selfAttributes();
1280     ArrayList<MethodInfo> methods = selfMethods();
1281     ArrayList<FieldInfo> fields = selfFields();
1282     ArrayList<FieldInfo> enumConstants = enumConstants();
1283     ArrayList<MethodInfo> ctors = constructors();
1284     ArrayList<ClassInfo> inners = innerClasses();
1285 
1286     // class name
1287     mTypeInfo.makeHDF(data, "class.type");
1288     mTypeInfo.makeQualifiedHDF(data, "class.qualifiedType");
1289     data.setValue("class.name", name);
1290     data.setValue("class.qualified", qualified);
1291     if (isProtected()) {
1292       data.setValue("class.scope", "protected");
1293     } else if (isPublic()) {
1294       data.setValue("class.scope", "public");
1295     }
1296     if (isStatic()) {
1297       data.setValue("class.static", "static");
1298     }
1299     if (isFinal()) {
1300       data.setValue("class.final", "final");
1301     }
1302     if (isAbstract() && !isInterface()) {
1303       data.setValue("class.abstract", "abstract");
1304     }
1305 
1306     int numAnnotationDocumentation = 0;
1307     for (AnnotationInstanceInfo aii : annotations()) {
1308       String annotationDocumentation = Doclava.getDocumentationStringForAnnotation(
1309           aii.type().qualifiedName());
1310       if (annotationDocumentation != null) {
1311         data.setValue("class.annotationdocumentation." + numAnnotationDocumentation + ".text",
1312             annotationDocumentation);
1313         numAnnotationDocumentation++;
1314       }
1315     }
1316 
1317     ArrayList<AnnotationInstanceInfo> showAnnos = getShowAnnotationsIncludeOuters();
1318     AnnotationInstanceInfo.makeLinkListHDF(
1319       data,
1320       "class.showAnnotations",
1321       showAnnos.toArray(new AnnotationInstanceInfo[showAnnos.size()]));
1322 
1323     // class info
1324     String kind = kind();
1325     if (kind != null) {
1326       data.setValue("class.kind", kind);
1327     }
1328     data.setValue("class.since", getSince());
1329     if (isDeprecated()) {
1330       data.setValue("class.deprecatedsince", getDeprecatedSince());
1331     }
1332     data.setValue("class.artifact", getArtifact());
1333     setFederatedReferences(data, "class");
1334 
1335     // the containing package -- note that this can be passed to type_link,
1336     // but it also contains the list of all of the packages
1337     containingPackage().makeClassLinkListHDF(data, "class.package");
1338 
1339     // inheritance hierarchy
1340     List<ClassTypePair> ctplist = superClassesWithTypes();
1341     n = ctplist.size();
1342     for (i = 0; i < ctplist.size(); i++) {
1343       // go in reverse order
1344       ClassTypePair ctp = ctplist.get(n - i - 1);
1345       if (ctp.classInfo().checkLevel()) {
1346         ctp.typeInfo().makeQualifiedHDF(data, "class.inheritance." + i + ".class");
1347         ctp.typeInfo().makeHDF(data, "class.inheritance." + i + ".short_class");
1348         j = 0;
1349         for (ClassTypePair t : ctp.classInfo().interfacesWithTypes()) {
1350           t.typeInfo().makeHDF(data, "class.inheritance." + i + ".interfaces." + j);
1351           j++;
1352         }
1353       }
1354     }
1355 
1356     // class description
1357     TagInfo.makeHDF(data, "class.descr", inlineTags());
1358     TagInfo.makeHDF(data, "class.descrAux", Doclava.auxSource.classAuxTags(this));
1359     TagInfo.makeHDF(data, "class.seeAlso", comment().seeTags());
1360     TagInfo.makeHDF(data, "class.deprecated", deprecatedTags());
1361 
1362     // known subclasses
1363     TreeMap<String, ClassInfo> direct = new TreeMap<String, ClassInfo>();
1364     TreeMap<String, ClassInfo> indirect = new TreeMap<String, ClassInfo>();
1365     Collection<ClassInfo> all = Converter.rootClasses();
1366     for (ClassInfo cl : all) {
1367       if (cl.superclass() != null && cl.superclass().equals(this)) {
1368         direct.put(cl.name(), cl);
1369       } else if (cl.isDerivedFrom(this)) {
1370         indirect.put(cl.name(), cl);
1371       }
1372     }
1373     // direct
1374     i = 0;
1375     for (ClassInfo cl : direct.values()) {
1376       if (cl.checkLevel()) {
1377         cl.makeShortDescrHDF(data, "class.subclasses.direct." + i);
1378       }
1379       i++;
1380     }
1381     // indirect
1382     i = 0;
1383     for (ClassInfo cl : indirect.values()) {
1384       if (cl.checkLevel()) {
1385         cl.makeShortDescrHDF(data, "class.subclasses.indirect." + i);
1386       }
1387       i++;
1388     }
1389 
1390     // hide special cases
1391     if ("java.lang.Object".equals(qualified) || "java.io.Serializable".equals(qualified)) {
1392       data.setValue("class.subclasses.hidden", "1");
1393     } else {
1394       data.setValue("class.subclasses.hidden", "0");
1395     }
1396 
1397     // nested classes
1398     i = 0;
1399     for (ClassInfo inner : inners) {
1400       if (inner.checkLevel()) {
1401         inner.makeShortDescrHDF(data, "class.inners." + i);
1402       }
1403       i++;
1404     }
1405 
1406     // enum constants
1407     i = 0;
1408     for (FieldInfo field : enumConstants) {
1409       field.makeHDF(data, "class.enumConstants." + i);
1410       i++;
1411     }
1412 
1413     // constants
1414     i = 0;
1415     for (FieldInfo field : fields) {
1416       if (field.isConstant()) {
1417         field.makeHDF(data, "class.constants." + i);
1418         i++;
1419       }
1420     }
1421 
1422     // fields
1423     i = 0;
1424     for (FieldInfo field : fields) {
1425       if (!field.isConstant()) {
1426         field.makeHDF(data, "class.fields." + i);
1427         i++;
1428       }
1429     }
1430 
1431     // public constructors
1432     i = 0;
1433     for (MethodInfo ctor : ctors) {
1434       if (ctor.isPublic()) {
1435         ctor.makeHDF(data, "class.ctors.public." + i);
1436         i++;
1437       }
1438     }
1439 
1440     // protected constructors
1441     if (Doclava.checkLevel(Doclava.SHOW_PROTECTED)) {
1442       i = 0;
1443       for (MethodInfo ctor : ctors) {
1444         if (ctor.isProtected()) {
1445           ctor.makeHDF(data, "class.ctors.protected." + i);
1446           i++;
1447         }
1448       }
1449     }
1450 
1451     // package private constructors
1452     if (Doclava.checkLevel(Doclava.SHOW_PACKAGE)) {
1453       i = 0;
1454       for (MethodInfo ctor : ctors) {
1455         if (ctor.isPackagePrivate()) {
1456           ctor.makeHDF(data, "class.ctors.package." + i);
1457           i++;
1458         }
1459       }
1460     }
1461 
1462     // private constructors
1463     if (Doclava.checkLevel(Doclava.SHOW_PRIVATE)) {
1464       i = 0;
1465       for (MethodInfo ctor : ctors) {
1466         if (ctor.isPrivate()) {
1467           ctor.makeHDF(data, "class.ctors.private." + i);
1468           i++;
1469         }
1470       }
1471     }
1472 
1473     // public methods
1474     i = 0;
1475     for (MethodInfo method : methods) {
1476       if (method.isPublic()) {
1477         method.makeHDF(data, "class.methods.public." + i);
1478         i++;
1479       }
1480     }
1481 
1482     // protected methods
1483     if (Doclava.checkLevel(Doclava.SHOW_PROTECTED)) {
1484       i = 0;
1485       for (MethodInfo method : methods) {
1486         if (method.isProtected()) {
1487           method.makeHDF(data, "class.methods.protected." + i);
1488           i++;
1489         }
1490       }
1491     }
1492 
1493     // package private methods
1494     if (Doclava.checkLevel(Doclava.SHOW_PACKAGE)) {
1495       i = 0;
1496       for (MethodInfo method : methods) {
1497         if (method.isPackagePrivate()) {
1498           method.makeHDF(data, "class.methods.package." + i);
1499           i++;
1500         }
1501       }
1502     }
1503 
1504     // private methods
1505     if (Doclava.checkLevel(Doclava.SHOW_PRIVATE)) {
1506       i = 0;
1507       for (MethodInfo method : methods) {
1508         if (method.isPrivate()) {
1509           method.makeHDF(data, "class.methods.private." + i);
1510           i++;
1511         }
1512       }
1513     }
1514 
1515     // xml attributes
1516     i = 0;
1517     for (AttributeInfo attr : selfAttributes) {
1518       if (attr.checkLevel()) {
1519         attr.makeHDF(data, "class.attrs." + i);
1520         i++;
1521       }
1522     }
1523 
1524     // inherited methods
1525     Iterator<ClassTypePair> superclassesItr = superClassesWithTypes().iterator();
1526     superclassesItr.next(); // skip the first one, which is the current class
1527     ClassTypePair superCtp;
1528     i = 0;
1529     while (superclassesItr.hasNext()) {
1530       superCtp = superclassesItr.next();
1531       if (superCtp.classInfo().checkLevel()) {
1532         makeInheritedHDF(data, i, superCtp);
1533         i++;
1534       }
1535     }
1536     Iterator<ClassTypePair> interfacesItr = allInterfacesWithTypes().iterator();
1537     while (interfacesItr.hasNext()) {
1538       superCtp = interfacesItr.next();
1539       if (superCtp.classInfo().checkLevel()) {
1540         makeInheritedHDF(data, i, superCtp);
1541         i++;
1542       }
1543     }
1544   }
1545 
makeInheritedHDF(Data data, int index, ClassTypePair ctp)1546   private static void makeInheritedHDF(Data data, int index, ClassTypePair ctp) {
1547     int i;
1548 
1549     String base = "class.inherited." + index;
1550     data.setValue(base + ".qualified", ctp.classInfo().qualifiedName());
1551     if (ctp.classInfo().checkLevel()) {
1552       data.setValue(base + ".link", ctp.classInfo().htmlPage());
1553     }
1554     String kind = ctp.classInfo().kind();
1555     if (kind != null) {
1556       data.setValue(base + ".kind", kind);
1557     }
1558 
1559     if (ctp.classInfo().mIsIncluded) {
1560       data.setValue(base + ".included", "true");
1561     } else {
1562       Doclava.federationTagger.tagAll(Arrays.asList(ctp.classInfo()));
1563       if (!ctp.classInfo().getFederatedReferences().isEmpty()) {
1564         FederatedSite site = ctp.classInfo().getFederatedReferences().iterator().next();
1565         data.setValue(base + ".link", site.linkFor(ctp.classInfo().htmlPage()));
1566         data.setValue(base + ".federated", site.name());
1567       }
1568     }
1569 
1570     // xml attributes
1571     i = 0;
1572     for (AttributeInfo attr : ctp.classInfo().selfAttributes()) {
1573       attr.makeHDF(data, base + ".attrs." + i);
1574       i++;
1575     }
1576 
1577     // methods
1578     i = 0;
1579     for (MethodInfo method : ctp.classInfo().selfMethods()) {
1580       method.makeHDF(data, base + ".methods." + i, ctp.getTypeArgumentMapping());
1581       i++;
1582     }
1583 
1584     // fields
1585     i = 0;
1586     for (FieldInfo field : ctp.classInfo().selfFields()) {
1587       if (!field.isConstant()) {
1588         field.makeHDF(data, base + ".fields." + i);
1589         i++;
1590       }
1591     }
1592 
1593     // constants
1594     i = 0;
1595     for (FieldInfo field : ctp.classInfo().selfFields()) {
1596       if (field.isConstant()) {
1597         field.makeHDF(data, base + ".constants." + i);
1598         i++;
1599       }
1600     }
1601   }
1602 
1603   @Override
isHidden()1604   public boolean isHidden() {
1605     if (mHidden == null) {
1606       mHidden = isHiddenImpl();
1607     }
1608 
1609     return mHidden;
1610   }
1611 
1612   /**
1613    * @return true if the containing package has @hide comment, a hide annotaion,
1614    * or a containing class of this class is hidden.
1615    */
isHiddenImpl()1616   public boolean isHiddenImpl() {
1617     ClassInfo cl = this;
1618     while (cl != null) {
1619       if (cl.hasShowAnnotation()) {
1620         return false;
1621       }
1622       PackageInfo pkg = cl.containingPackage();
1623       if (pkg != null && pkg.hasHideComment()) {
1624         return true;
1625       }
1626       if (cl.comment().isHidden() || cl.hasHideAnnotation()) {
1627         return true;
1628       }
1629       cl = cl.containingClass();
1630     }
1631     return false;
1632   }
1633 
1634   @Override
isRemoved()1635   public boolean isRemoved() {
1636     if (mRemoved == null) {
1637       mRemoved = isRemovedImpl();
1638     }
1639 
1640     return mRemoved;
1641   }
1642 
1643   /**
1644    * @return true if the containing package has @removed comment, or an ancestor
1645    * class of this class is removed, or this class has @removed comment.
1646    */
isRemovedImpl()1647   public boolean isRemovedImpl() {
1648     ClassInfo cl = this;
1649     while (cl != null) {
1650       PackageInfo pkg = cl.containingPackage();
1651       if (pkg != null && pkg.hasRemovedComment()) {
1652         return true;
1653       }
1654       if (cl.comment().isRemoved()) {
1655         return true;
1656       }
1657       cl = cl.containingClass();
1658     }
1659     return false;
1660   }
1661 
1662   @Override
isHiddenOrRemoved()1663   public boolean isHiddenOrRemoved() {
1664     return isHidden() || isRemoved();
1665   }
1666 
hasShowAnnotation()1667   public boolean hasShowAnnotation() {
1668     return mShowAnnotations != null && mShowAnnotations.size() > 0;
1669   }
1670 
showAnnotations()1671   public ArrayList<AnnotationInstanceInfo> showAnnotations() {
1672     return mShowAnnotations;
1673   }
1674 
hasHideAnnotation()1675   public boolean hasHideAnnotation() {
1676     return mHideAnnotations != null && mHideAnnotations.size() > 0;
1677   }
1678 
hideAnnotations()1679   public ArrayList<AnnotationInstanceInfo> hideAnnotations() {
1680     return mHideAnnotations;
1681   }
1682 
getShowAnnotationsIncludeOuters()1683   public ArrayList<AnnotationInstanceInfo> getShowAnnotationsIncludeOuters() {
1684     ArrayList<AnnotationInstanceInfo> allAnnotations = new ArrayList<AnnotationInstanceInfo>();
1685     ClassInfo cl = this;
1686     while (cl != null) {
1687       if (cl.showAnnotations() != null) {
1688         // Don't allow duplicates into the merged list
1689         for (AnnotationInstanceInfo newAii : cl.showAnnotations()) {
1690           boolean addIt = true;
1691           for (AnnotationInstanceInfo existingAii : allAnnotations) {
1692             if (existingAii.type().name() == newAii.type().name()) {
1693               addIt = false;
1694               break;
1695             }
1696           }
1697           if (addIt) {
1698             allAnnotations.add(newAii);
1699           }
1700         }
1701       }
1702       cl = cl.containingClass();
1703     }
1704     return allAnnotations;
1705   }
1706 
matchMethod(ArrayList<MethodInfo> methods, String name, String[] params, String[] dimensions, boolean varargs)1707   private MethodInfo matchMethod(ArrayList<MethodInfo> methods, String name, String[] params,
1708       String[] dimensions, boolean varargs) {
1709     for (MethodInfo method : methods) {
1710       if (method.name().equals(name)) {
1711         if (params == null) {
1712           return method;
1713         } else {
1714           if (method.matchesParams(params, dimensions, varargs)) {
1715             return method;
1716           }
1717         }
1718       }
1719     }
1720     return null;
1721   }
1722 
findMethod(String name, String[] params, String[] dimensions, boolean varargs)1723   public MethodInfo findMethod(String name, String[] params, String[] dimensions, boolean varargs) {
1724     // first look on our class, and our superclasses
1725 
1726     // for methods
1727     MethodInfo rv;
1728     rv = matchMethod(methods(), name, params, dimensions, varargs);
1729 
1730     if (rv != null) {
1731       return rv;
1732     }
1733 
1734     // for constructors
1735     rv = matchMethod(constructors(), name, params, dimensions, varargs);
1736     if (rv != null) {
1737       return rv;
1738     }
1739 
1740     // then recursively look at our containing class
1741     ClassInfo containing = containingClass();
1742     if (containing != null) {
1743       return containing.findMethod(name, params, dimensions, varargs);
1744     }
1745 
1746     return null;
1747   }
1748 
supportsMethod(MethodInfo method)1749   public boolean supportsMethod(MethodInfo method) {
1750     for (MethodInfo m : methods()) {
1751       if (m.getHashableName().equals(method.getHashableName())) {
1752         return true;
1753       }
1754     }
1755     return false;
1756   }
1757 
searchInnerClasses(String[] nameParts, int index)1758   private ClassInfo searchInnerClasses(String[] nameParts, int index) {
1759     String part = nameParts[index];
1760 
1761     ArrayList<ClassInfo> inners = mInnerClasses;
1762     for (ClassInfo in : inners) {
1763       String[] innerParts = in.nameParts();
1764       if (part.equals(innerParts[innerParts.length - 1])) {
1765         if (index == nameParts.length - 1) {
1766           return in;
1767         } else {
1768           return in.searchInnerClasses(nameParts, index + 1);
1769         }
1770       }
1771     }
1772     return null;
1773   }
1774 
extendedFindClass(String className)1775   public ClassInfo extendedFindClass(String className) {
1776     // ClassDoc.findClass has this bug that we're working around here:
1777     // If you have a class PackageManager with an inner class PackageInfo
1778     // and you call it with "PackageInfo" it doesn't find it.
1779     return searchInnerClasses(className.split("\\."), 0);
1780   }
1781 
findClass(String className)1782   public ClassInfo findClass(String className) {
1783     return Converter.obtainClass(mClass.findClass(className));
1784   }
1785 
findInnerClass(String className)1786   public ClassInfo findInnerClass(String className) {
1787     // ClassDoc.findClass won't find inner classes. To deal with that,
1788     // we try what they gave us first, but if that didn't work, then
1789     // we see if there are any periods in className, and start searching
1790     // from there.
1791     String[] nodes = className.split("\\.");
1792     ClassDoc cl = mClass;
1793 
1794     int N = nodes.length;
1795     for (int i = 0; i < N; ++i) {
1796       final String n = nodes[i];
1797       if (n.isEmpty() && i == 0) {
1798         // We skip over an empty classname component if it's at location 0. This is
1799         // to deal with names like ".Inner". java7 will return a bogus ClassInfo when
1800         // we call "findClass("") and the next iteration of the loop will throw a
1801         // runtime exception.
1802         continue;
1803       }
1804 
1805       cl = cl.findClass(n);
1806       if (cl == null) {
1807         return null;
1808       }
1809     }
1810 
1811     return Converter.obtainClass(cl);
1812   }
1813 
findField(String name)1814   public FieldInfo findField(String name) {
1815     // first look on our class, and our superclasses
1816     for (FieldInfo f : fields()) {
1817       if (f.name().equals(name)) {
1818         return f;
1819       }
1820     }
1821 
1822     // then look at our enum constants (these are really fields, maybe
1823     // they should be mixed into fields(). not sure)
1824     for (FieldInfo f : enumConstants()) {
1825       if (f.name().equals(name)) {
1826         return f;
1827       }
1828     }
1829 
1830     // then recursively look at our containing class
1831     ClassInfo containing = containingClass();
1832     if (containing != null) {
1833       return containing.findField(name);
1834     }
1835 
1836     return null;
1837   }
1838 
sortByName(ClassInfo[] classes)1839   public static ClassInfo[] sortByName(ClassInfo[] classes) {
1840     int i;
1841     Sorter[] sorted = new Sorter[classes.length];
1842     for (i = 0; i < sorted.length; i++) {
1843       ClassInfo cl = classes[i];
1844       sorted[i] = new Sorter(cl.name(), cl);
1845     }
1846 
1847     Arrays.sort(sorted);
1848 
1849     ClassInfo[] rv = new ClassInfo[classes.length];
1850     for (i = 0; i < rv.length; i++) {
1851       rv[i] = (ClassInfo) sorted[i].data;
1852     }
1853 
1854     return rv;
1855   }
1856 
setNonWrittenConstructors(ArrayList<MethodInfo> nonWritten)1857   public void setNonWrittenConstructors(ArrayList<MethodInfo> nonWritten) {
1858     mNonWrittenConstructors = nonWritten;
1859   }
1860 
getNonWrittenConstructors()1861   public ArrayList<MethodInfo> getNonWrittenConstructors() {
1862     return mNonWrittenConstructors;
1863   }
1864 
kind()1865   public String kind() {
1866     if (isOrdinaryClass()) {
1867       return "class";
1868     } else if (isInterface()) {
1869       return "interface";
1870     } else if (isEnum()) {
1871       return "enum";
1872     } else if (isError()) {
1873       return "class";
1874     } else if (isException()) {
1875       return "class";
1876     } else if (isAnnotation()) {
1877       return "@interface";
1878     }
1879     return null;
1880   }
1881 
scope()1882   public String scope() {
1883     if (isPublic()) {
1884       return "public";
1885     } else if (isProtected()) {
1886       return "protected";
1887     } else if (isPackagePrivate()) {
1888       return "";
1889     } else if (isPrivate()) {
1890       return "private";
1891     } else {
1892       throw new RuntimeException("invalid scope for object " + this);
1893     }
1894   }
1895 
setHiddenMethods(ArrayList<MethodInfo> mInfo)1896   public void setHiddenMethods(ArrayList<MethodInfo> mInfo) {
1897     mHiddenMethods = mInfo;
1898   }
1899 
getHiddenMethods()1900   public ArrayList<MethodInfo> getHiddenMethods() {
1901     return mHiddenMethods;
1902   }
1903 
1904   @Override
toString()1905   public String toString() {
1906     return this.qualifiedName();
1907   }
1908 
1909   @Override
equals(Object o)1910   public boolean equals(Object o) {
1911     if (this == o) {
1912       return true;
1913     } else if (o instanceof ClassInfo) {
1914       final ClassInfo c = (ClassInfo) o;
1915       return mQualifiedName.equals(c.mQualifiedName);
1916     } else {
1917       return false;
1918     }
1919   }
1920 
1921   @Override
hashCode()1922   public int hashCode() {
1923     return mQualifiedName.hashCode();
1924   }
1925 
setReasonIncluded(String reason)1926   public void setReasonIncluded(String reason) {
1927     mReasonIncluded = reason;
1928   }
1929 
getReasonIncluded()1930   public String getReasonIncluded() {
1931     return mReasonIncluded;
1932   }
1933 
1934   private ClassDoc mClass;
1935 
1936   // ctor
1937   private boolean mIsPublic;
1938   private boolean mIsProtected;
1939   private boolean mIsPackagePrivate;
1940   private boolean mIsPrivate;
1941   private boolean mIsStatic;
1942   private boolean mIsInterface;
1943   private boolean mIsAbstract;
1944   private boolean mIsOrdinaryClass;
1945   private boolean mIsException;
1946   private boolean mIsError;
1947   private boolean mIsEnum;
1948   private boolean mIsAnnotation;
1949   private boolean mIsFinal;
1950   private boolean mIsIncluded;
1951   private String mName;
1952   private String mQualifiedName;
1953   private String mQualifiedTypeName;
1954   private boolean mIsPrimitive;
1955   private TypeInfo mTypeInfo;
1956   private String[] mNameParts;
1957 
1958   // init
1959   private ArrayList<ClassInfo> mRealInterfaces = new ArrayList<ClassInfo>();
1960   private ArrayList<ClassInfo> mInterfaces;
1961   private ArrayList<TypeInfo> mRealInterfaceTypes;
1962   private ArrayList<ClassInfo> mInnerClasses;
1963   // mAllConstructors will not contain *all* constructors. Only the constructors that pass
1964   // checkLevel. @see {@link Converter#convertMethods(ConstructorDoc[])}
1965   private ArrayList<MethodInfo> mAllConstructors = new ArrayList<MethodInfo>();
1966   // mAllSelfMethods will not contain *all* self methods. Only the methods that pass
1967   // checkLevel. @see {@link Converter#convertMethods(MethodDoc[])}
1968   private ArrayList<MethodInfo> mAllSelfMethods = new ArrayList<MethodInfo>();
1969   private ArrayList<MethodInfo> mAnnotationElements = new ArrayList<MethodInfo>(); // if this class is an annotation
1970   private ArrayList<FieldInfo> mAllSelfFields = new ArrayList<FieldInfo>();
1971   private ArrayList<FieldInfo> mEnumConstants = new ArrayList<FieldInfo>();
1972   private PackageInfo mContainingPackage;
1973   private ClassInfo mContainingClass;
1974   private ClassInfo mRealSuperclass;
1975   private TypeInfo mRealSuperclassType;
1976   private ClassInfo mSuperclass;
1977   private ArrayList<AnnotationInstanceInfo> mAnnotations;
1978   private ArrayList<AnnotationInstanceInfo> mShowAnnotations;
1979   private ArrayList<AnnotationInstanceInfo> mHideAnnotations;
1980   private boolean mSuperclassInit;
1981   private boolean mDeprecatedKnown;
1982 
1983   // lazy
1984   private ArrayList<ClassTypePair> mSuperclassesWithTypes;
1985   private ArrayList<ClassTypePair> mInterfacesWithTypes;
1986   private ArrayList<ClassTypePair> mAllInterfacesWithTypes;
1987   private ArrayList<MethodInfo> mConstructors;
1988   private ArrayList<ClassInfo> mRealInnerClasses;
1989   private ArrayList<MethodInfo> mSelfMethods;
1990   private ArrayList<FieldInfo> mSelfFields;
1991   private ArrayList<AttributeInfo> mSelfAttributes;
1992   private ArrayList<MethodInfo> mMethods;
1993   private ArrayList<FieldInfo> mFields;
1994   private ArrayList<TypeInfo> mTypeParameters;
1995   private ArrayList<MethodInfo> mHiddenMethods;
1996   private Boolean mHidden = null;
1997   private Boolean mRemoved = null;
1998   private Boolean mCheckLevel = null;
1999   private String mReasonIncluded;
2000   private ArrayList<MethodInfo> mNonWrittenConstructors;
2001   private boolean mIsDeprecated;
2002 
2003   // TODO: Temporary members from apicheck migration.
2004   private HashMap<String, MethodInfo> mApiCheckConstructors = new HashMap<String, MethodInfo>();
2005   private HashMap<String, MethodInfo> mApiCheckMethods = new HashMap<String, MethodInfo>();
2006   private HashMap<String, FieldInfo> mApiCheckFields = new HashMap<String, FieldInfo>();
2007   private HashMap<String, FieldInfo> mApiCheckEnumConstants = new HashMap<String, FieldInfo>();
2008 
2009   // Resolutions
2010   private ArrayList<Resolution> mResolutions;
2011 
2012   private List<MethodInfo> mRemovedMethods; // immutable after you set its value.
2013 
2014   private List<MethodInfo> mExhaustiveConstructors; // immutable after you set its value.
2015   private List<MethodInfo> mExhaustiveMethods; // immutable after you set its value.
2016   private List<FieldInfo> mExhaustiveEnumConstants; // immutable after you set its value.
2017   private List<FieldInfo> mExhaustiveFields; // immutable after you set its value.
2018 
2019   /**
2020    * Returns true if {@code cl} implements the interface {@code iface} either by either being that
2021    * interface, implementing that interface or extending a type that implements the interface.
2022    */
implementsInterface(String iface)2023   public boolean implementsInterface(String iface) {
2024     if (qualifiedName().equals(iface)) {
2025       return true;
2026     }
2027     for (ClassInfo clImplements : realInterfaces()) {
2028       if (clImplements.implementsInterface(iface)) {
2029         return true;
2030       }
2031     }
2032     if (mSuperclass != null && mSuperclass.implementsInterface(iface)) {
2033       return true;
2034     }
2035     return false;
2036   }
2037 
2038   /**
2039    * Returns true if {@code this} extends the class {@code ext}.
2040    */
extendsClass(String cl)2041   public boolean extendsClass(String cl) {
2042     if (qualifiedName().equals(cl)) {
2043       return true;
2044     }
2045     if (mSuperclass != null && mSuperclass.extendsClass(cl)) {
2046       return true;
2047     }
2048     return false;
2049   }
2050 
2051   /**
2052    * Returns true if {@code this} is assignable to cl
2053    */
isAssignableTo(String cl)2054   public boolean isAssignableTo(String cl) {
2055     return implementsInterface(cl) || extendsClass(cl);
2056   }
2057 
addInterface(ClassInfo iface)2058   public void addInterface(ClassInfo iface) {
2059     mRealInterfaces.add(iface);
2060   }
2061 
addConstructor(MethodInfo ctor)2062   public void addConstructor(MethodInfo ctor) {
2063     mApiCheckConstructors.put(ctor.getHashableName(), ctor);
2064 
2065     mAllConstructors.add(ctor);
2066     mConstructors = null; // flush this, hopefully it hasn't been used yet.
2067   }
2068 
addField(FieldInfo field)2069   public void addField(FieldInfo field) {
2070     mApiCheckFields.put(field.name(), field);
2071 
2072     mAllSelfFields.add(field);
2073 
2074     mSelfFields = null; // flush this, hopefully it hasn't been used yet.
2075   }
2076 
addEnumConstant(FieldInfo field)2077   public void addEnumConstant(FieldInfo field) {
2078     mApiCheckEnumConstants.put(field.name(), field);
2079 
2080     mEnumConstants.add(field);
2081   }
2082 
setSuperClass(ClassInfo superclass)2083   public void setSuperClass(ClassInfo superclass) {
2084     mRealSuperclass = superclass;
2085     mSuperclass = superclass;
2086   }
2087 
allConstructorsMap()2088   public Map<String, MethodInfo> allConstructorsMap() {
2089     return mApiCheckConstructors;
2090   }
2091 
allFields()2092   public Map<String, FieldInfo> allFields() {
2093     return mApiCheckFields;
2094   }
2095 
allEnums()2096   public Map<String, FieldInfo> allEnums() {
2097     return mApiCheckEnumConstants;
2098   }
2099 
2100   /**
2101    * Returns all methods defined directly in this class. For a list of all
2102    * methods supported by this class, see {@link #methods()}.
2103    */
allMethods()2104   public Map<String, MethodInfo> allMethods() {
2105     return mApiCheckMethods;
2106   }
2107 
2108   /**
2109    * Returns the class hierarchy for this class, starting with this class.
2110    */
hierarchy()2111   public Iterable<ClassInfo> hierarchy() {
2112     List<ClassInfo> result = new ArrayList<ClassInfo>(4);
2113     for (ClassInfo c = this; c != null; c = c.mSuperclass) {
2114       result.add(c);
2115     }
2116     return result;
2117   }
2118 
superclassName()2119   public String superclassName() {
2120     if (mSuperclass == null) {
2121       if (mQualifiedName.equals("java.lang.Object")) {
2122         return null;
2123       }
2124       throw new UnsupportedOperationException("Superclass not set for " + qualifiedName());
2125     }
2126     return mSuperclass.mQualifiedName;
2127   }
2128 
setAnnotations(ArrayList<AnnotationInstanceInfo> annotations)2129   public void setAnnotations(ArrayList<AnnotationInstanceInfo> annotations) {
2130     mAnnotations = annotations;
2131   }
2132 
isConsistent(ClassInfo cl)2133   public boolean isConsistent(ClassInfo cl) {
2134     return isConsistent(cl, null, null);
2135   }
2136 
isConsistent(ClassInfo cl, List<MethodInfo> newCtors, List<MethodInfo> newMethods)2137   public boolean isConsistent(ClassInfo cl, List<MethodInfo> newCtors, List<MethodInfo> newMethods) {
2138     boolean consistent = true;
2139     boolean diffMode = (newCtors != null) && (newMethods != null);
2140 
2141     if (isInterface() != cl.isInterface()) {
2142       Errors.error(Errors.CHANGED_CLASS, cl.position(), "Class " + cl.qualifiedName()
2143           + " changed class/interface declaration");
2144       consistent = false;
2145     }
2146     for (ClassInfo iface : mRealInterfaces) {
2147       if (!cl.implementsInterface(iface.mQualifiedName)) {
2148         Errors.error(Errors.REMOVED_INTERFACE, cl.position(), "Class " + qualifiedName()
2149             + " no longer implements " + iface);
2150       }
2151     }
2152     for (ClassInfo iface : cl.mRealInterfaces) {
2153       if (!implementsInterface(iface.mQualifiedName)) {
2154         Errors.error(Errors.ADDED_INTERFACE, cl.position(), "Added interface " + iface
2155             + " to class " + qualifiedName());
2156         consistent = false;
2157       }
2158     }
2159 
2160     for (MethodInfo mInfo : mApiCheckMethods.values()) {
2161       if (cl.mApiCheckMethods.containsKey(mInfo.getHashableName())) {
2162         if (!mInfo.isConsistent(cl.mApiCheckMethods.get(mInfo.getHashableName()))) {
2163           consistent = false;
2164         }
2165       } else {
2166         /*
2167          * This class formerly provided this method directly, and now does not. Check our ancestry
2168          * to see if there's an inherited version that still fulfills the API requirement.
2169          */
2170         MethodInfo mi = ClassInfo.overriddenMethod(mInfo, cl);
2171         if (mi == null) {
2172           mi = ClassInfo.interfaceMethod(mInfo, cl);
2173         }
2174         if (mi == null) {
2175           if (mInfo.isDeprecated()) {
2176             Errors.error(Errors.REMOVED_DEPRECATED_METHOD, mInfo.position(),
2177                 "Removed deprecated public method " + mInfo.prettyQualifiedSignature());
2178           } else {
2179             Errors.error(Errors.REMOVED_METHOD, mInfo.position(),
2180                 "Removed public method " + mInfo.prettyQualifiedSignature());
2181           }
2182           consistent = false;
2183         }
2184       }
2185     }
2186     for (MethodInfo mInfo : cl.mApiCheckMethods.values()) {
2187       if (!mApiCheckMethods.containsKey(mInfo.getHashableName())) {
2188         /*
2189          * Similarly to the above, do not fail if this "new" method is really an override of an
2190          * existing superclass method.
2191          * But we should fail if this is overriding an abstract method, because method's
2192          * abstractness affects how users use it. See also Stubs.methodIsOverride().
2193          */
2194         MethodInfo mi = ClassInfo.overriddenMethod(mInfo, this);
2195         if (mi == null && mInfo.isAbstract()) {
2196           Errors.error(Errors.ADDED_ABSTRACT_METHOD, mInfo.position(),
2197               "Added abstract public method "
2198               + mInfo.prettyQualifiedSignature() + " to existing class");
2199           consistent = false;
2200         } else if (mi == null || mi.isAbstract() != mInfo.isAbstract()) {
2201             Errors.error(Errors.ADDED_METHOD, mInfo.position(), "Added public method "
2202                 + mInfo.prettyQualifiedSignature());
2203             if (diffMode) {
2204               newMethods.add(mInfo);
2205             }
2206             consistent = false;
2207           }
2208         }
2209     }
2210     if (diffMode) {
2211       Collections.sort(newMethods, MethodInfo.comparator);
2212     }
2213 
2214     for (MethodInfo mInfo : mApiCheckConstructors.values()) {
2215       if (cl.mApiCheckConstructors.containsKey(mInfo.getHashableName())) {
2216         if (!mInfo.isConsistent(cl.mApiCheckConstructors.get(mInfo.getHashableName()))) {
2217           consistent = false;
2218         }
2219       } else {
2220         if (mInfo.isDeprecated()) {
2221           Errors.error(Errors.REMOVED_DEPRECATED_METHOD, mInfo.position(),
2222               "Removed deprecated public constructor " + mInfo.prettyQualifiedSignature());
2223         } else {
2224           Errors.error(Errors.REMOVED_METHOD, mInfo.position(),
2225               "Removed public constructor " + mInfo.prettyQualifiedSignature());
2226         }
2227         consistent = false;
2228       }
2229     }
2230     for (MethodInfo mInfo : cl.mApiCheckConstructors.values()) {
2231       if (!mApiCheckConstructors.containsKey(mInfo.getHashableName())) {
2232         Errors.error(Errors.ADDED_METHOD, mInfo.position(), "Added public constructor "
2233             + mInfo.prettyQualifiedSignature());
2234         if (diffMode) {
2235           newCtors.add(mInfo);
2236         }
2237         consistent = false;
2238       }
2239     }
2240     if (diffMode) {
2241       Collections.sort(newCtors, MethodInfo.comparator);
2242     }
2243 
2244     for (FieldInfo mInfo : mApiCheckFields.values()) {
2245       if (cl.mApiCheckFields.containsKey(mInfo.name())) {
2246         if (!mInfo.isConsistent(cl.mApiCheckFields.get(mInfo.name()))) {
2247           consistent = false;
2248         }
2249       } else {
2250         if (mInfo.isDeprecated()) {
2251           Errors.error(Errors.REMOVED_DEPRECATED_FIELD, mInfo.position(),
2252               "Removed deprecated field " + mInfo.qualifiedName());
2253         } else {
2254           Errors.error(Errors.REMOVED_FIELD, mInfo.position(),
2255               "Removed field " + mInfo.qualifiedName());
2256         }
2257         consistent = false;
2258       }
2259     }
2260     for (FieldInfo mInfo : cl.mApiCheckFields.values()) {
2261       if (!mApiCheckFields.containsKey(mInfo.name())) {
2262         Errors.error(Errors.ADDED_FIELD, mInfo.position(), "Added public field "
2263             + mInfo.qualifiedName());
2264         consistent = false;
2265       }
2266     }
2267 
2268     for (FieldInfo info : mApiCheckEnumConstants.values()) {
2269       if (cl.mApiCheckEnumConstants.containsKey(info.name())) {
2270         if (!info.isConsistent(cl.mApiCheckEnumConstants.get(info.name()))) {
2271           consistent = false;
2272         }
2273       } else {
2274         if (info.isDeprecated()) {
2275           Errors.error(Errors.REMOVED_DEPRECATED_FIELD, info.position(),
2276               "Removed deprecated enum constant " + info.qualifiedName());
2277         } else {
2278           Errors.error(Errors.REMOVED_FIELD, info.position(),
2279               "Removed enum constant " + info.qualifiedName());
2280         }
2281         consistent = false;
2282       }
2283     }
2284     for (FieldInfo info : cl.mApiCheckEnumConstants.values()) {
2285       if (!mApiCheckEnumConstants.containsKey(info.name())) {
2286         Errors.error(Errors.ADDED_FIELD, info.position(), "Added enum constant "
2287             + info.qualifiedName());
2288         consistent = false;
2289       }
2290     }
2291 
2292     if (mIsAbstract != cl.mIsAbstract) {
2293       consistent = false;
2294       Errors.error(Errors.CHANGED_ABSTRACT, cl.position(), "Class " + cl.qualifiedName()
2295           + " changed abstract qualifier");
2296     }
2297 
2298     if (!mIsFinal && cl.mIsFinal) {
2299       /*
2300        * It is safe to make a class final if it did not previously have any public
2301        * constructors because it was impossible for an application to create a subclass.
2302        */
2303       if (mApiCheckConstructors.isEmpty()) {
2304         consistent = false;
2305         Errors.error(Errors.ADDED_FINAL_UNINSTANTIABLE, cl.position(),
2306             "Class " + cl.qualifiedName() + " added final qualifier but "
2307             + "was previously uninstantiable and therefore could not be subclassed");
2308       } else {
2309         consistent = false;
2310         Errors.error(Errors.ADDED_FINAL, cl.position(), "Class " + cl.qualifiedName()
2311             + " added final qualifier");
2312       }
2313     } else if (mIsFinal && !cl.mIsFinal) {
2314       consistent = false;
2315       Errors.error(Errors.REMOVED_FINAL, cl.position(), "Class " + cl.qualifiedName()
2316           + " removed final qualifier");
2317     }
2318 
2319     if (mIsStatic != cl.mIsStatic) {
2320       consistent = false;
2321       Errors.error(Errors.CHANGED_STATIC, cl.position(), "Class " + cl.qualifiedName()
2322           + " changed static qualifier");
2323     }
2324 
2325     if (!scope().equals(cl.scope())) {
2326       consistent = false;
2327       Errors.error(Errors.CHANGED_SCOPE, cl.position(), "Class " + cl.qualifiedName()
2328           + " scope changed from " + scope() + " to " + cl.scope());
2329     }
2330 
2331     if (!isDeprecated() == cl.isDeprecated()) {
2332       consistent = false;
2333       Errors.error(Errors.CHANGED_DEPRECATED, cl.position(), "Class " + cl.qualifiedName()
2334           + " has changed deprecation state " + isDeprecated() + " --> " + cl.isDeprecated());
2335     }
2336 
2337     if (superclassName() != null) { // java.lang.Object can't have a superclass.
2338       if (!cl.extendsClass(superclassName())) {
2339         consistent = false;
2340         Errors.error(Errors.CHANGED_SUPERCLASS, cl.position(), "Class " + qualifiedName()
2341             + " superclass changed from " + superclassName() + " to " + cl.superclassName());
2342       }
2343     }
2344 
2345     if (hasTypeParameters() && cl.hasTypeParameters()) {
2346       ArrayList<TypeInfo> oldParams = typeParameters();
2347       ArrayList<TypeInfo> newParams = cl.typeParameters();
2348       if (oldParams.size() != newParams.size()) {
2349         consistent = false;
2350         Errors.error(Errors.CHANGED_TYPE, cl.position(), "Class " + qualifiedName()
2351             + " changed number of type parameters from " + oldParams.size()
2352             + " to " + newParams.size());
2353       }
2354     }
2355 
2356     return consistent;
2357   }
2358 
2359   // Find a superclass implementation of the given method based on the methods in mApiCheckMethods.
overriddenMethod(MethodInfo candidate, ClassInfo newClassObj)2360   public static MethodInfo overriddenMethod(MethodInfo candidate, ClassInfo newClassObj) {
2361     if (newClassObj == null) {
2362       return null;
2363     }
2364     for (MethodInfo mi : newClassObj.mApiCheckMethods.values()) {
2365       if (mi.matches(candidate)) {
2366         // found it
2367         return mi;
2368       }
2369     }
2370 
2371     // not found here. recursively search ancestors
2372     return ClassInfo.overriddenMethod(candidate, newClassObj.mSuperclass);
2373   }
2374 
2375   // Find a superinterface declaration of the given method.
interfaceMethod(MethodInfo candidate, ClassInfo newClassObj)2376   public static MethodInfo interfaceMethod(MethodInfo candidate, ClassInfo newClassObj) {
2377     if (newClassObj == null) {
2378       return null;
2379     }
2380     for (ClassInfo interfaceInfo : newClassObj.interfaces()) {
2381       for (MethodInfo mi : interfaceInfo.mApiCheckMethods.values()) {
2382         if (mi.matches(candidate)) {
2383           return mi;
2384         }
2385       }
2386     }
2387     return ClassInfo.interfaceMethod(candidate, newClassObj.mSuperclass);
2388   }
2389 
hasConstructor(MethodInfo constructor)2390   public boolean hasConstructor(MethodInfo constructor) {
2391     String name = constructor.getHashableName();
2392     for (MethodInfo ctor : mApiCheckConstructors.values()) {
2393       if (name.equals(ctor.getHashableName())) {
2394         return true;
2395       }
2396     }
2397     return false;
2398   }
2399 
setTypeInfo(TypeInfo typeInfo)2400   public void setTypeInfo(TypeInfo typeInfo) {
2401     mTypeInfo = typeInfo;
2402   }
2403 
type()2404   public TypeInfo type() {
2405       return mTypeInfo;
2406   }
2407 
hasTypeParameters()2408   public boolean hasTypeParameters() {
2409       if (mTypeInfo != null && mTypeInfo.typeArguments() != null) {
2410           return !mTypeInfo.typeArguments().isEmpty();
2411       }
2412       return false;
2413   }
2414 
typeParameters()2415   public ArrayList<TypeInfo> typeParameters() {
2416       if (hasTypeParameters()) {
2417           return mTypeInfo.typeArguments();
2418       }
2419       return null;
2420   }
2421 
addInnerClass(ClassInfo innerClass)2422   public void addInnerClass(ClassInfo innerClass) {
2423       if (mInnerClasses == null) {
2424           mInnerClasses = new ArrayList<ClassInfo>();
2425       }
2426 
2427       mInnerClasses.add(innerClass);
2428   }
2429 
setContainingClass(ClassInfo containingClass)2430   public void setContainingClass(ClassInfo containingClass) {
2431       mContainingClass = containingClass;
2432   }
2433 
setSuperclassType(TypeInfo superclassType)2434   public void setSuperclassType(TypeInfo superclassType) {
2435       mRealSuperclassType = superclassType;
2436   }
2437 
printResolutions()2438   public void printResolutions() {
2439       if (mResolutions == null || mResolutions.isEmpty()) {
2440           return;
2441       }
2442 
2443       System.out.println("Resolutions for Class " + mName + ":");
2444 
2445       for (Resolution r : mResolutions) {
2446           System.out.println(r);
2447       }
2448   }
2449 
addResolution(Resolution resolution)2450   public void addResolution(Resolution resolution) {
2451       if (mResolutions == null) {
2452           mResolutions = new ArrayList<Resolution>();
2453       }
2454 
2455       mResolutions.add(resolution);
2456   }
2457 
resolveResolutions()2458   public boolean resolveResolutions() {
2459       ArrayList<Resolution> resolutions = mResolutions;
2460       mResolutions = new ArrayList<Resolution>();
2461 
2462       boolean allResolved = true;
2463       for (Resolution resolution : resolutions) {
2464           StringBuilder qualifiedClassName = new StringBuilder();
2465           InfoBuilder.resolveQualifiedName(resolution.getValue(), qualifiedClassName,
2466                   resolution.getInfoBuilder());
2467 
2468           // if we still couldn't resolve it, save it for the next pass
2469           if ("".equals(qualifiedClassName.toString())) {
2470               mResolutions.add(resolution);
2471               allResolved = false;
2472           } else if ("superclassQualifiedName".equals(resolution.getVariable())) {
2473               setSuperClass(InfoBuilder.Caches.obtainClass(qualifiedClassName.toString()));
2474           } else if ("interfaceQualifiedName".equals(resolution.getVariable())) {
2475               addInterface(InfoBuilder.Caches.obtainClass(qualifiedClassName.toString()));
2476           }
2477       }
2478 
2479       return allResolved;
2480   }
2481 }
2482