blob: 8f0199e834eafc5dac5345bba2531760d2db8b52 [file] [log] [blame]
Ben Dodson920dbbb2010-08-04 15:21:06 -07001/*
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
17package com.google.doclava;
18
19import com.google.clearsilver.jsilver.data.Data;
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -070020import com.sun.javadoc.ClassDoc;
Ben Dodson920dbbb2010-08-04 15:21:06 -070021
Jeff Arnesond6570b02014-10-29 15:46:51 -070022import java.util.ArrayDeque;
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -070023import java.util.ArrayList;
24import java.util.Arrays;
25import java.util.Collections;
26import java.util.Comparator;
27import java.util.HashMap;
28import java.util.HashSet;
Jeff Arnesond6570b02014-10-29 15:46:51 -070029import java.util.Iterator;
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -070030import java.util.List;
31import java.util.Map;
Jeff Arnesond6570b02014-10-29 15:46:51 -070032import java.util.Queue;
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -070033import java.util.Set;
34import java.util.TreeMap;
Ben Dodson920dbbb2010-08-04 15:21:06 -070035
Andrew Sapperstein6ba612e2011-06-20 18:41:24 -070036public class ClassInfo extends DocInfo implements ContainerInfo, Comparable, Scoped, Resolvable {
Jeff Arnesond6570b02014-10-29 15:46:51 -070037
38 /**
39 * Contains a ClassInfo and a TypeInfo.
40 * <p>
41 * This is used to match a ClassInfo, which doesn't keep track of its type parameters
42 * and a type which does.
43 */
44 private class ClassTypePair {
45 private final ClassInfo mClassInfo;
46 private final TypeInfo mTypeInfo;
47
48 public ClassTypePair(ClassInfo cl, TypeInfo t) {
49 mClassInfo = cl;
50 mTypeInfo = t;
51 }
52
53 public ClassInfo classInfo() {
54 return mClassInfo;
55 }
56
57 public TypeInfo typeInfo() {
58 return mTypeInfo;
59 }
60
61 public Map<String, TypeInfo> getTypeArgumentMapping() {
62 return TypeInfo.getTypeArgumentMapping(classInfo(), typeInfo());
63 }
64 }
65
Ben Dodson920dbbb2010-08-04 15:21:06 -070066 public static final Comparator<ClassInfo> comparator = new Comparator<ClassInfo>() {
67 public int compare(ClassInfo a, ClassInfo b) {
68 return a.name().compareTo(b.name());
69 }
70 };
71
72 public static final Comparator<ClassInfo> qualifiedComparator = new Comparator<ClassInfo>() {
73 public int compare(ClassInfo a, ClassInfo b) {
74 return a.qualifiedName().compareTo(b.qualifiedName());
75 }
76 };
Dirk Dougherty9b316c82013-01-28 10:53:33 -080077
Ben Dodson920dbbb2010-08-04 15:21:06 -070078 /**
79 * Constructs a stub representation of a class.
80 */
81 public ClassInfo(String qualifiedName) {
82 super("", SourcePositionInfo.UNKNOWN);
Ben Dodson920dbbb2010-08-04 15:21:06 -070083 mQualifiedName = qualifiedName;
84 if (qualifiedName.lastIndexOf('.') != -1) {
85 mName = qualifiedName.substring(qualifiedName.lastIndexOf('.') + 1);
86 } else {
87 mName = qualifiedName;
88 }
89 }
90
91 public ClassInfo(ClassDoc cl, String rawCommentText, SourcePositionInfo position,
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -070092 boolean isPublic, boolean isProtected, boolean isPackagePrivate, boolean isPrivate,
93 boolean isStatic, boolean isInterface, boolean isAbstract, boolean isOrdinaryClass,
94 boolean isException, boolean isError, boolean isEnum, boolean isAnnotation, boolean isFinal,
95 boolean isIncluded, String name, String qualifiedName, String qualifiedTypeName,
96 boolean isPrimitive) {
97 super(rawCommentText, position);
Ben Dodson920dbbb2010-08-04 15:21:06 -070098
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -070099 initialize(rawCommentText, position,
100 isPublic, isProtected, isPackagePrivate, isPrivate,
101 isStatic, isInterface, isAbstract, isOrdinaryClass,
102 isException, isError, isEnum, isAnnotation, isFinal,
103 isIncluded, qualifiedTypeName, isPrimitive, null);
104
105 mName = name;
106 mQualifiedName = qualifiedName;
107 mNameParts = name.split("\\.");
108 mClass = cl;
109 }
110
111 public void initialize(String rawCommentText, SourcePositionInfo position,
112 boolean isPublic, boolean isProtected, boolean isPackagePrivate, boolean isPrivate,
113 boolean isStatic, boolean isInterface, boolean isAbstract, boolean isOrdinaryClass,
114 boolean isException, boolean isError, boolean isEnum, boolean isAnnotation, boolean isFinal,
115 boolean isIncluded, String qualifiedTypeName, boolean isPrimitive, ArrayList<AnnotationInstanceInfo> annotations) {
116
117 // calls
118 setPosition(position);
119 setRawCommentText(rawCommentText);
Ben Dodson920dbbb2010-08-04 15:21:06 -0700120 mIsPublic = isPublic;
121 mIsProtected = isProtected;
122 mIsPackagePrivate = isPackagePrivate;
123 mIsPrivate = isPrivate;
124 mIsStatic = isStatic;
125 mIsInterface = isInterface;
126 mIsAbstract = isAbstract;
127 mIsOrdinaryClass = isOrdinaryClass;
128 mIsException = isException;
129 mIsError = isError;
130 mIsEnum = isEnum;
131 mIsAnnotation = isAnnotation;
132 mIsFinal = isFinal;
133 mIsIncluded = isIncluded;
Ben Dodson920dbbb2010-08-04 15:21:06 -0700134 mQualifiedTypeName = qualifiedTypeName;
135 mIsPrimitive = isPrimitive;
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -0700136 mAnnotations = annotations;
Jeff Arnesonb84c41b2014-08-12 15:22:00 -0700137 mShowAnnotations = AnnotationInstanceInfo.getShowAnnotationsIntersection(annotations);
Ben Dodson920dbbb2010-08-04 15:21:06 -0700138 }
139
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -0700140 public void init(TypeInfo typeInfo, ArrayList<ClassInfo> interfaces,
141 ArrayList<TypeInfo> interfaceTypes, ArrayList<ClassInfo> innerClasses,
142 ArrayList<MethodInfo> constructors, ArrayList<MethodInfo> methods,
143 ArrayList<MethodInfo> annotationElements, ArrayList<FieldInfo> fields,
144 ArrayList<FieldInfo> enumConstants, PackageInfo containingPackage,
145 ClassInfo containingClass, ClassInfo superclass,
146 TypeInfo superclassType, ArrayList<AnnotationInstanceInfo> annotations) {
Ben Dodson920dbbb2010-08-04 15:21:06 -0700147 mTypeInfo = typeInfo;
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -0700148 mRealInterfaces = new ArrayList<ClassInfo>(interfaces);
Ben Dodson920dbbb2010-08-04 15:21:06 -0700149 mRealInterfaceTypes = interfaceTypes;
150 mInnerClasses = innerClasses;
Hui Shu5118ffe2014-02-18 14:06:42 -0800151 // mAllConstructors will not contain *all* constructors. Only the constructors that pass
152 // checkLevel. @see {@link Converter#convertMethods(ConstructorDoc[])}
Ben Dodson920dbbb2010-08-04 15:21:06 -0700153 mAllConstructors = constructors;
Hui Shu5118ffe2014-02-18 14:06:42 -0800154 // mAllSelfMethods will not contain *all* self methods. Only the methods that pass
155 // checkLevel. @see {@link Converter#convertMethods(MethodDoc[])}
Ben Dodson920dbbb2010-08-04 15:21:06 -0700156 mAllSelfMethods = methods;
157 mAnnotationElements = annotationElements;
Hui Shu5118ffe2014-02-18 14:06:42 -0800158 // mAllSelfFields will not contain *all* self fields. Only the fields that pass
159 // checkLevel. @see {@link Converter#convetFields(FieldDoc[])}
Ben Dodson920dbbb2010-08-04 15:21:06 -0700160 mAllSelfFields = fields;
Hui Shu5118ffe2014-02-18 14:06:42 -0800161 // mEnumConstants will not contain *all* enum constants. Only the enums that pass
162 // checkLevel. @see {@link Converter#convetFields(FieldDoc[])}
Ben Dodson920dbbb2010-08-04 15:21:06 -0700163 mEnumConstants = enumConstants;
164 mContainingPackage = containingPackage;
165 mContainingClass = containingClass;
166 mRealSuperclass = superclass;
167 mRealSuperclassType = superclassType;
168 mAnnotations = annotations;
Jeff Arnesonb84c41b2014-08-12 15:22:00 -0700169 mShowAnnotations = AnnotationInstanceInfo.getShowAnnotationsIntersection(annotations);
Ben Dodson920dbbb2010-08-04 15:21:06 -0700170
171 // after providing new methods and new superclass info,clear any cached
172 // lists of self + superclass methods, ctors, etc.
173 mSuperclassInit = false;
174 mConstructors = null;
175 mMethods = null;
176 mSelfMethods = null;
177 mFields = null;
178 mSelfFields = null;
179 mSelfAttributes = null;
180 mDeprecatedKnown = false;
Jeff Arnesond6570b02014-10-29 15:46:51 -0700181 mSuperclassesWithTypes = null;
182 mInterfacesWithTypes = null;
183 mAllInterfacesWithTypes = null;
Ben Dodson920dbbb2010-08-04 15:21:06 -0700184
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -0700185 Collections.sort(mEnumConstants, FieldInfo.comparator);
186 Collections.sort(mInnerClasses, ClassInfo.comparator);
Ben Dodson920dbbb2010-08-04 15:21:06 -0700187 }
188
189 public void init2() {
190 // calling this here forces the AttrTagInfo objects to be linked to the AttribtueInfo
191 // objects
192 selfAttributes();
193 }
194
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -0700195 public void init3(ArrayList<TypeInfo> types, ArrayList<ClassInfo> realInnerClasses) {
Ben Dodson920dbbb2010-08-04 15:21:06 -0700196 mTypeParameters = types;
197 mRealInnerClasses = realInnerClasses;
198 }
199
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -0700200 public ArrayList<ClassInfo> getRealInnerClasses() {
Ben Dodson920dbbb2010-08-04 15:21:06 -0700201 return mRealInnerClasses;
202 }
203
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -0700204 public ArrayList<TypeInfo> getTypeParameters() {
Ben Dodson920dbbb2010-08-04 15:21:06 -0700205 return mTypeParameters;
206 }
207
Hui Shu5118ffe2014-02-18 14:06:42 -0800208 /**
209 * @return true if this class needs to be shown in api txt, based on the
210 * hidden/removed status of the class and the show level setting in doclava.
211 */
Ben Dodson920dbbb2010-08-04 15:21:06 -0700212 public boolean checkLevel() {
Hui Shu5118ffe2014-02-18 14:06:42 -0800213 if (mCheckLevel == null) {
214 mCheckLevel = Doclava.checkLevel(mIsPublic, mIsProtected, mIsPackagePrivate, mIsPrivate,
215 isHiddenOrRemoved());
Ben Dodson920dbbb2010-08-04 15:21:06 -0700216 }
Hui Shu5118ffe2014-02-18 14:06:42 -0800217
218 return mCheckLevel;
Ben Dodson920dbbb2010-08-04 15:21:06 -0700219 }
220
221 public int compareTo(Object that) {
222 if (that instanceof ClassInfo) {
223 return mQualifiedName.compareTo(((ClassInfo) that).mQualifiedName);
224 } else {
225 return this.hashCode() - that.hashCode();
226 }
227 }
228
229 @Override
230 public ContainerInfo parent() {
231 return this;
232 }
233
234 public boolean isPublic() {
235 return mIsPublic;
236 }
237
238 public boolean isProtected() {
239 return mIsProtected;
240 }
241
242 public boolean isPackagePrivate() {
243 return mIsPackagePrivate;
244 }
245
246 public boolean isPrivate() {
247 return mIsPrivate;
248 }
249
250 public boolean isStatic() {
251 return mIsStatic;
252 }
253
254 public boolean isInterface() {
255 return mIsInterface;
256 }
257
258 public boolean isAbstract() {
259 return mIsAbstract;
260 }
261
262 public PackageInfo containingPackage() {
263 return mContainingPackage;
264 }
265
266 public ClassInfo containingClass() {
267 return mContainingClass;
268 }
269
270 public boolean isOrdinaryClass() {
271 return mIsOrdinaryClass;
272 }
273
274 public boolean isException() {
275 return mIsException;
276 }
277
278 public boolean isError() {
279 return mIsError;
280 }
281
282 public boolean isEnum() {
283 return mIsEnum;
284 }
285
286 public boolean isAnnotation() {
287 return mIsAnnotation;
288 }
289
290 public boolean isFinal() {
291 return mIsFinal;
292 }
293
Jeff Brown722ac6a2013-04-01 17:07:37 -0700294 public boolean isEffectivelyFinal() {
295 return mIsFinal || mApiCheckConstructors.isEmpty();
296 }
297
Ben Dodson920dbbb2010-08-04 15:21:06 -0700298 public boolean isIncluded() {
299 return mIsIncluded;
300 }
301
302 public HashSet<String> typeVariables() {
303 HashSet<String> result = TypeInfo.typeVariables(mTypeInfo.typeArguments());
304 ClassInfo cl = containingClass();
305 while (cl != null) {
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -0700306 ArrayList<TypeInfo> types = cl.asTypeInfo().typeArguments();
Ben Dodson920dbbb2010-08-04 15:21:06 -0700307 if (types != null) {
308 TypeInfo.typeVariables(types, result);
309 }
310 cl = cl.containingClass();
311 }
312 return result;
313 }
314
Jeff Arnesond6570b02014-10-29 15:46:51 -0700315 /**
316 * List of only direct interface's classes, without worrying about type param mapping.
317 * This can't be lazy loaded, because its overloads depend on changing type parameters
318 * passed in from the callers.
319 */
320 private List<ClassTypePair> justMyInterfacesWithTypes() {
321 return justMyInterfacesWithTypes(Collections.<String, TypeInfo>emptyMap());
322 }
323
324 /**
325 * List of only direct interface's classes and their parameterized types.
326 * This can't be lazy loaded, because of the passed in typeArgumentsMap.
327 */
328 private List<ClassTypePair> justMyInterfacesWithTypes(Map<String, TypeInfo> typeArgumentsMap) {
329 if (mRealInterfaces == null || mRealInterfaceTypes == null) {
330 return Collections.<ClassTypePair>emptyList();
331 }
332
333 List<ClassTypePair> list = new ArrayList<ClassTypePair>();
334 for (int i = 0; i < mRealInterfaces.size(); i++) {
335 ClassInfo iface = mRealInterfaces.get(i);
336 TypeInfo type = mRealInterfaceTypes.get(i);
337 if (iface != null && type != null) {
338 type = type.getTypeWithArguments(typeArgumentsMap);
339 if (iface.checkLevel()) {
340 list.add(new ClassTypePair(iface, type));
341 } else {
342 // add the interface's interfaces
343 Map<String, TypeInfo> map = TypeInfo.getTypeArgumentMapping(iface.asTypeInfo(), type);
344 list.addAll(iface.justMyInterfacesWithTypes(map));
345 }
346 }
347 }
348 return list;
349 }
350
351 /**
352 * List of only direct interface's classes, and any hidden superclass's direct interfaces
353 * between this class and the first visible superclass and those interface class's parameterized types.
354 */
355 private ArrayList<ClassTypePair> interfacesWithTypes() {
356 if (mInterfacesWithTypes == null) {
357 mInterfacesWithTypes = new ArrayList<ClassTypePair>();
358
359 Iterator<ClassTypePair> itr = superClassesWithTypes().iterator();
360 // skip the first one, which is this class
361 itr.next();
362 while (itr.hasNext()) {
363 ClassTypePair ctp = itr.next();
364 if (ctp.classInfo().checkLevel()) {
365 break;
366 } else {
367 // fill mInterfacesWithTypes from the hidden superclass
368 mInterfacesWithTypes.addAll(
369 ctp.classInfo().justMyInterfacesWithTypes(ctp.getTypeArgumentMapping()));
370 }
371 }
372 mInterfacesWithTypes.addAll(
373 justMyInterfacesWithTypes());
374 }
375 return mInterfacesWithTypes;
376 }
377
378 /**
379 * List of all interface's classes reachable in this class's inheritance hierarchy
380 * and those interface class's parameterized types.
381 */
382 private ArrayList<ClassTypePair> allInterfacesWithTypes() {
383 if (mAllInterfacesWithTypes == null) {
384 mAllInterfacesWithTypes = new ArrayList<ClassTypePair>();
385 Queue<ClassTypePair> toParse = new ArrayDeque<ClassTypePair>();
386 Set<String> visited = new HashSet<String>();
387
388 Iterator<ClassTypePair> itr = superClassesWithTypes().iterator();
389 // skip the first one, which is this class
390 itr.next();
391 while (itr.hasNext()) {
392 ClassTypePair ctp = itr.next();
393 toParse.addAll(
394 ctp.classInfo().justMyInterfacesWithTypes(ctp.getTypeArgumentMapping()));
395 }
396 toParse.addAll(justMyInterfacesWithTypes());
397 while (!toParse.isEmpty()) {
398 ClassTypePair ctp = toParse.remove();
399 if (!visited.contains(ctp.typeInfo().fullName())) {
400 mAllInterfacesWithTypes.add(ctp);
401 visited.add(ctp.typeInfo().fullName());
402 toParse.addAll(ctp.classInfo().justMyInterfacesWithTypes(ctp.getTypeArgumentMapping()));
403 }
404 }
405 }
406 return mAllInterfacesWithTypes;
407 }
408
409 /**
410 * A list of ClassTypePairs that contain all superclasses
411 * and their corresponding types. The types will have type parameters
412 * cascaded upwards so they match, if any classes along the way set them.
413 * The list includes the current class, and is an ascending order up the
414 * heirarchy tree.
415 * */
416 private ArrayList<ClassTypePair> superClassesWithTypes() {
417 if (mSuperclassesWithTypes == null) {
418 mSuperclassesWithTypes = new ArrayList<ClassTypePair>();
419
420 ClassTypePair lastCtp = new ClassTypePair(this, this.asTypeInfo());
421 mSuperclassesWithTypes.add(lastCtp);
422
423 Map<String, TypeInfo> typeArgumentsMap;
424 ClassInfo superclass = mRealSuperclass;
425 TypeInfo supertype = mRealSuperclassType;
426 TypeInfo nextType;
427 while (superclass != null && supertype != null) {
428 typeArgumentsMap = lastCtp.getTypeArgumentMapping();
429 lastCtp = new ClassTypePair(superclass, supertype.getTypeWithArguments(typeArgumentsMap));
430 mSuperclassesWithTypes.add(lastCtp);
431
432 supertype = superclass.mRealSuperclassType;
433 superclass = superclass.mRealSuperclass;
434 }
435 }
436 return mSuperclassesWithTypes;
437 }
438
Ben Dodson920dbbb2010-08-04 15:21:06 -0700439 private static void gatherHiddenInterfaces(ClassInfo cl, HashSet<ClassInfo> interfaces) {
440 for (ClassInfo iface : cl.mRealInterfaces) {
441 if (iface.checkLevel()) {
442 interfaces.add(iface);
443 } else {
444 gatherHiddenInterfaces(iface, interfaces);
445 }
446 }
447 }
448
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -0700449 public ArrayList<ClassInfo> interfaces() {
Ben Dodson920dbbb2010-08-04 15:21:06 -0700450 if (mInterfaces == null) {
451 if (checkLevel()) {
452 HashSet<ClassInfo> interfaces = new HashSet<ClassInfo>();
453 ClassInfo superclass = mRealSuperclass;
454 while (superclass != null && !superclass.checkLevel()) {
455 gatherHiddenInterfaces(superclass, interfaces);
456 superclass = superclass.mRealSuperclass;
457 }
458 gatherHiddenInterfaces(this, interfaces);
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -0700459 mInterfaces = new ArrayList<ClassInfo>(interfaces);
Ben Dodson920dbbb2010-08-04 15:21:06 -0700460 } else {
461 // put something here in case someone uses it
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -0700462 mInterfaces = new ArrayList<ClassInfo>(mRealInterfaces);
Ben Dodson920dbbb2010-08-04 15:21:06 -0700463 }
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -0700464 Collections.sort(mInterfaces, ClassInfo.qualifiedComparator);
Ben Dodson920dbbb2010-08-04 15:21:06 -0700465 }
466 return mInterfaces;
467 }
468
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -0700469 public ArrayList<ClassInfo> realInterfaces() {
470 return mRealInterfaces;
Ben Dodson920dbbb2010-08-04 15:21:06 -0700471 }
472
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -0700473 ArrayList<TypeInfo> realInterfaceTypes() {
Ben Dodson920dbbb2010-08-04 15:21:06 -0700474 return mRealInterfaceTypes;
475 }
476
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -0700477 public void addInterfaceType(TypeInfo type) {
478 if (mRealInterfaceTypes == null) {
479 mRealInterfaceTypes = new ArrayList<TypeInfo>();
480 }
481
482 mRealInterfaceTypes.add(type);
483 }
484
Ben Dodson920dbbb2010-08-04 15:21:06 -0700485 public String name() {
486 return mName;
487 }
488
489 public String[] nameParts() {
490 return mNameParts;
491 }
492
493 public String leafName() {
494 return mNameParts[mNameParts.length - 1];
495 }
496
497 public String qualifiedName() {
498 return mQualifiedName;
499 }
500
501 public String qualifiedTypeName() {
502 return mQualifiedTypeName;
503 }
504
505 public boolean isPrimitive() {
506 return mIsPrimitive;
507 }
508
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -0700509 public ArrayList<MethodInfo> allConstructors() {
Ben Dodson920dbbb2010-08-04 15:21:06 -0700510 return mAllConstructors;
511 }
512
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -0700513 public ArrayList<MethodInfo> constructors() {
Ben Dodson920dbbb2010-08-04 15:21:06 -0700514 if (mConstructors == null) {
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -0700515 if (mAllConstructors == null) {
516 return new ArrayList<MethodInfo>();
Joe Onorato04099252011-03-09 13:34:18 -0800517 }
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -0700518
519 mConstructors = new ArrayList<MethodInfo>();
520 for (MethodInfo m : mAllConstructors) {
Hui Shu5118ffe2014-02-18 14:06:42 -0800521 if (!m.isHiddenOrRemoved()) {
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -0700522 mConstructors.add(m);
Ben Dodson920dbbb2010-08-04 15:21:06 -0700523 }
524 }
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -0700525
526 Collections.sort(mConstructors, MethodInfo.comparator);
Ben Dodson920dbbb2010-08-04 15:21:06 -0700527 }
528 return mConstructors;
529 }
530
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -0700531 public ArrayList<ClassInfo> innerClasses() {
Ben Dodson920dbbb2010-08-04 15:21:06 -0700532 return mInnerClasses;
533 }
534
535 public TagInfo[] inlineTags() {
536 return comment().tags();
537 }
538
539 public TagInfo[] firstSentenceTags() {
540 return comment().briefTags();
541 }
542
Joe Onorato04099252011-03-09 13:34:18 -0800543 public void setDeprecated(boolean deprecated) {
544 mDeprecatedKnown = true;
545 mIsDeprecated = deprecated;
546 }
547
Ben Dodson920dbbb2010-08-04 15:21:06 -0700548 public boolean isDeprecated() {
Ben Dodson920dbbb2010-08-04 15:21:06 -0700549 if (!mDeprecatedKnown) {
550 boolean commentDeprecated = comment().isDeprecated();
551 boolean annotationDeprecated = false;
552 for (AnnotationInstanceInfo annotation : annotations()) {
553 if (annotation.type().qualifiedName().equals("java.lang.Deprecated")) {
554 annotationDeprecated = true;
555 break;
556 }
557 }
558
559 if (commentDeprecated != annotationDeprecated) {
560 Errors.error(Errors.DEPRECATION_MISMATCH, position(), "Class " + qualifiedName()
561 + ": @Deprecated annotation and @deprecated comment do not match");
562 }
563
564 mIsDeprecated = commentDeprecated | annotationDeprecated;
565 mDeprecatedKnown = true;
566 }
567 return mIsDeprecated;
568 }
569
570 public TagInfo[] deprecatedTags() {
571 // Should we also do the interfaces?
572 return comment().deprecatedTags();
573 }
574
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -0700575 public ArrayList<MethodInfo> methods() {
576 if (mMethods == null) {
577 TreeMap<String, MethodInfo> all = new TreeMap<String, MethodInfo>();
Ben Dodson920dbbb2010-08-04 15:21:06 -0700578
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -0700579 ArrayList<ClassInfo> interfaces = interfaces();
580 for (ClassInfo iface : interfaces) {
581 if (iface != null) {
582 for (MethodInfo method : iface.methods()) {
583 all.put(method.getHashableName(), method);
584 }
585 }
Ben Dodson920dbbb2010-08-04 15:21:06 -0700586 }
Ben Dodson920dbbb2010-08-04 15:21:06 -0700587
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -0700588 ClassInfo superclass = superclass();
589 if (superclass != null) {
590 for (MethodInfo method : superclass.methods()) {
591 all.put(method.getHashableName(), method);
592 }
593 }
Ben Dodson920dbbb2010-08-04 15:21:06 -0700594
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -0700595 for (MethodInfo method : selfMethods()) {
596 all.put(method.getHashableName(), method);
597 }
Ben Dodson920dbbb2010-08-04 15:21:06 -0700598
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -0700599 mMethods = new ArrayList<MethodInfo>(all.values());
600 Collections.sort(mMethods, MethodInfo.comparator);
601 }
Ben Dodson920dbbb2010-08-04 15:21:06 -0700602 return mMethods;
603 }
604
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -0700605 public ArrayList<MethodInfo> annotationElements() {
Ben Dodson920dbbb2010-08-04 15:21:06 -0700606 return mAnnotationElements;
607 }
608
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -0700609 public ArrayList<AnnotationInstanceInfo> annotations() {
Ben Dodson920dbbb2010-08-04 15:21:06 -0700610 return mAnnotations;
611 }
612
613 private static void addFields(ClassInfo cl, TreeMap<String, FieldInfo> all) {
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -0700614 for (FieldInfo field : cl.fields()) {
615 all.put(field.name(), field);
Ben Dodson920dbbb2010-08-04 15:21:06 -0700616 }
617 }
618
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -0700619 public ArrayList<FieldInfo> fields() {
Ben Dodson920dbbb2010-08-04 15:21:06 -0700620 if (mFields == null) {
Ben Dodson920dbbb2010-08-04 15:21:06 -0700621 TreeMap<String, FieldInfo> all = new TreeMap<String, FieldInfo>();
622
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -0700623 for (ClassInfo iface : interfaces()) {
624 addFields(iface, all);
Ben Dodson920dbbb2010-08-04 15:21:06 -0700625 }
626
627 ClassInfo superclass = superclass();
628 if (superclass != null) {
629 addFields(superclass, all);
630 }
631
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -0700632 for (FieldInfo field : selfFields()) {
Hui Shu5118ffe2014-02-18 14:06:42 -0800633 if (!field.isHiddenOrRemoved()) {
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -0700634 all.put(field.name(), field);
Ben Dodson920dbbb2010-08-04 15:21:06 -0700635 }
636 }
637
Scott Main18904802013-08-07 13:53:14 -0700638 for (FieldInfo enumConst : mEnumConstants) {
Hui Shu5118ffe2014-02-18 14:06:42 -0800639 if (!enumConst.isHiddenOrRemoved()) {
Scott Main18904802013-08-07 13:53:14 -0700640 all.put(enumConst.name(), enumConst);
641 }
642 }
643
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -0700644 mFields = new ArrayList<FieldInfo>(all.values());
Ben Dodson920dbbb2010-08-04 15:21:06 -0700645 }
646 return mFields;
647 }
648
649 public void gatherFields(ClassInfo owner, ClassInfo cl, HashMap<String, FieldInfo> fields) {
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -0700650 for (FieldInfo f : cl.selfFields()) {
Ben Dodson920dbbb2010-08-04 15:21:06 -0700651 if (f.checkLevel()) {
652 fields.put(f.name(), f.cloneForClass(owner));
653 }
654 }
655 }
656
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -0700657 public ArrayList<FieldInfo> selfFields() {
Ben Dodson920dbbb2010-08-04 15:21:06 -0700658 if (mSelfFields == null) {
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -0700659 HashMap<String, FieldInfo> fields = new HashMap<String, FieldInfo>();
Ben Dodson920dbbb2010-08-04 15:21:06 -0700660 // our hidden parents
661 if (mRealSuperclass != null && !mRealSuperclass.checkLevel()) {
662 gatherFields(this, mRealSuperclass, fields);
663 }
664 for (ClassInfo iface : mRealInterfaces) {
665 if (!iface.checkLevel()) {
666 gatherFields(this, iface, fields);
667 }
668 }
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -0700669
670 for (FieldInfo f : mAllSelfFields) {
Hui Shu5118ffe2014-02-18 14:06:42 -0800671 if (!f.isHiddenOrRemoved()) {
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -0700672 fields.put(f.name(), f);
673 }
Ben Dodson920dbbb2010-08-04 15:21:06 -0700674 }
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -0700675
676 mSelfFields = new ArrayList<FieldInfo>(fields.values());
677 Collections.sort(mSelfFields, FieldInfo.comparator);
Ben Dodson920dbbb2010-08-04 15:21:06 -0700678 }
679 return mSelfFields;
680 }
681
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -0700682 public ArrayList<FieldInfo> allSelfFields() {
Ben Dodson920dbbb2010-08-04 15:21:06 -0700683 return mAllSelfFields;
684 }
685
Jeff Arnesond6570b02014-10-29 15:46:51 -0700686 private void gatherMethods(ClassInfo owner, ClassTypePair ctp, HashMap<String, MethodInfo> methods) {
687 for (MethodInfo m : ctp.classInfo().selfMethods()) {
Ben Dodson920dbbb2010-08-04 15:21:06 -0700688 if (m.checkLevel()) {
Jeff Arnesond6570b02014-10-29 15:46:51 -0700689 methods.put(m.name() + m.signature(), m.cloneForClass(owner, ctp.getTypeArgumentMapping()));
Ben Dodson920dbbb2010-08-04 15:21:06 -0700690 }
691 }
692 }
693
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -0700694 public ArrayList<MethodInfo> selfMethods() {
Ben Dodson920dbbb2010-08-04 15:21:06 -0700695 if (mSelfMethods == null) {
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -0700696 HashMap<String, MethodInfo> methods = new HashMap<String, MethodInfo>();
Ben Dodson920dbbb2010-08-04 15:21:06 -0700697 // our hidden parents
Jeff Arnesond6570b02014-10-29 15:46:51 -0700698 for (ClassTypePair ctp : superClassesWithTypes()) {
699 // this class is included in this list, so skip it!
700 if (ctp.classInfo() != this) {
701 if (ctp.classInfo().checkLevel()) {
702 break;
703 }
704 gatherMethods(this, ctp, methods);
705 }
Ben Dodson920dbbb2010-08-04 15:21:06 -0700706 }
Jeff Arnesond6570b02014-10-29 15:46:51 -0700707 for (ClassTypePair ctp : justMyInterfacesWithTypes(Collections.<String, TypeInfo>emptyMap())) {
708 if (!ctp.classInfo().checkLevel()) {
709 gatherMethods(this, ctp, methods);
Ben Dodson920dbbb2010-08-04 15:21:06 -0700710 }
711 }
712 // mine
713 if (mAllSelfMethods != null) {
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -0700714 for (MethodInfo m : mAllSelfMethods) {
Ben Dodson920dbbb2010-08-04 15:21:06 -0700715 if (m.checkLevel()) {
Hui Shu5118ffe2014-02-18 14:06:42 -0800716 methods.put(m.name() + m.signature(), m);
Ben Dodson920dbbb2010-08-04 15:21:06 -0700717 }
718 }
719 }
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -0700720
721 // sort it
722 mSelfMethods = new ArrayList<MethodInfo>(methods.values());
723 Collections.sort(mSelfMethods, MethodInfo.comparator);
Ben Dodson920dbbb2010-08-04 15:21:06 -0700724 }
725 return mSelfMethods;
726 }
727
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -0700728 public ArrayList<MethodInfo> allSelfMethods() {
Ben Dodson920dbbb2010-08-04 15:21:06 -0700729 return mAllSelfMethods;
730 }
731
Hui Shu5118ffe2014-02-18 14:06:42 -0800732 /**
733 * @param removedMethods the removed methods regardless of access levels.
734 */
735 public void setRemovedMethods(List<MethodInfo> removedMethods) {
736 Collections.sort(removedMethods, MethodInfo.comparator);
737 mRemovedMethods = Collections.unmodifiableList(removedMethods);
738 }
739
740 /**
741 * @param allMethods all methods regardless of access levels. Selects the
742 * removed, public/protected ones and store them. If a class is removed, all its members
743 * are removed, even if the member may not have a @removed tag.
744 */
745 public void setRemovedSelfMethods(List<MethodInfo> allMethods) {
746 List<MethodInfo> removedSelfMethods = new ArrayList<MethodInfo>();
747 for (MethodInfo method : allMethods) {
748 if ((this.isRemoved() || method.isRemoved()) && (method.isPublic() || method.isProtected()) &&
749 (this.isPublic() || this.isProtected()) &&
750 (method.findOverriddenMethod(method.name(), method.signature()) == null)) {
751 removedSelfMethods.add(method);
752 }
753 }
754
755 Collections.sort(removedSelfMethods, MethodInfo.comparator);
756 mRemovedSelfMethods = Collections.unmodifiableList(removedSelfMethods);
757 }
758
759 /**
760 * @param allCtors all constructors regardless of access levels.
761 * But only the public/protected removed constructors will be stored by the method.
762 * Removed constructors should never be deleted from source code because
763 * they were once public API.
764 */
765 public void setRemovedConstructors(List<MethodInfo> allCtors) {
766 List<MethodInfo> ctors = new ArrayList<MethodInfo>();
767 for (MethodInfo ctor : allCtors) {
768 if ((this.isRemoved() || ctor.isRemoved()) && (ctor.isPublic() || ctor.isProtected()) &&
769 (this.isPublic() || this.isProtected())) {
770 ctors.add(ctor);
771 }
772 }
773
774 Collections.sort(ctors, MethodInfo.comparator);
775 mRemovedConstructors = Collections.unmodifiableList(ctors);
776 }
777
778 /**
779 * @param allFields all fields regardless of access levels. Selects the
780 * removed, public/protected ones and store them. If a class is removed, all its members
781 * are removed, even if the member may not have a @removed tag.
782 */
783 public void setRemovedSelfFields(List<FieldInfo> allFields) {
784 List<FieldInfo> fields = new ArrayList<FieldInfo>();
785 for (FieldInfo field : allFields) {
786 if ((this.isRemoved() || field.isRemoved()) && (field.isPublic() || field.isProtected()) &&
787 (this.isPublic() || this.isProtected())) {
788 fields.add(field);
789 }
790 }
791
792 Collections.sort(fields, FieldInfo.comparator);
793 mRemovedSelfFields = Collections.unmodifiableList(fields);
794 }
795
796 /**
797 * @param allEnumConstants all enum constants regardless of access levels. Selects the
798 * removed, public/protected ones and store them. If a class is removed, all its members
799 * are removed, even if the member may not have a @removed tag.
800 */
801 public void setRemovedEnumConstants(List<FieldInfo> allEnumConstants) {
802 List<FieldInfo> enums = new ArrayList<FieldInfo>();
803 for (FieldInfo field : allEnumConstants) {
804 if ((this.isRemoved() || field.isRemoved()) && (field.isPublic() || field.isProtected()) &&
805 (this.isPublic() || this.isProtected())) {
806 enums.add(field);
807 }
808 }
809
810 Collections.sort(enums, FieldInfo.comparator);
811 mRemovedEnumConstants = Collections.unmodifiableList(enums);
812 }
813
814 /**
815 * @return all methods that are marked as removed, regardless of access levels.
816 * The returned list is sorted and unmodifiable.
817 */
818 public List<MethodInfo> getRemovedMethods() {
819 return mRemovedMethods;
820 }
821
822 /**
823 * @return all public/protected methods that are removed. @removed methods should never be
824 * deleted from source code because they were once public API. Methods that override
825 * a parent method will not be included, because deleting them does not break the API.
826 */
827 public List<MethodInfo> getRemovedSelfMethods() {
828 return mRemovedSelfMethods;
829 }
830
831 /**
832 * @return all public constructors that are removed.
833 * removed constructors should never be deleted from source code because they
834 * were once public API.
835 * The returned list is sorted and unmodifiable.
836 */
837 public List<MethodInfo> getRemovedConstructors() {
838 return mRemovedConstructors;
839 }
840
841 /**
842 * @return all public/protected fields that are removed.
843 * removed members should never be deleted from source code because they were once public API.
844 * The returned list is sorted and unmodifiable.
845 */
846 public List<FieldInfo> getRemovedSelfFields() {
847 return mRemovedSelfFields;
848 }
849
850 /**
851 * @return all public/protected enumConstants that are removed.
852 * removed members should never be deleted from source code
853 * because they were once public API.
854 * The returned list is sorted and unmodifiable.
855 */
856 public List<FieldInfo> getRemovedSelfEnumConstants() {
857 return mRemovedEnumConstants;
858 }
859
860 /**
861 * @return true if this class contains any self members that are removed
862 */
863 public boolean hasRemovedSelfMembers() {
864 List<FieldInfo> removedSelfFields = getRemovedSelfFields();
865 List<FieldInfo> removedSelfEnumConstants = getRemovedSelfEnumConstants();
866 List<MethodInfo> removedSelfMethods = getRemovedSelfMethods();
867 List<MethodInfo> removedConstructors = getRemovedConstructors();
868 if (removedSelfFields.size() + removedSelfEnumConstants.size()
869 + removedSelfMethods.size() + removedConstructors.size() == 0) {
870 return false;
871 } else {
872 return true;
873 }
874 }
875
Ben Dodson920dbbb2010-08-04 15:21:06 -0700876 public void addMethod(MethodInfo method) {
877 mApiCheckMethods.put(method.getHashableName(), method);
Joe Onorato04099252011-03-09 13:34:18 -0800878
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -0700879 mAllSelfMethods.add(method);
Joe Onorato04099252011-03-09 13:34:18 -0800880 mSelfMethods = null; // flush this, hopefully it hasn't been used yet.
Ben Dodson920dbbb2010-08-04 15:21:06 -0700881 }
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -0700882
883 public void addAnnotationElement(MethodInfo method) {
Mathieu11b17962013-06-07 17:24:18 -0500884 mAnnotationElements.add(method);
885 }
886
887 // Called by PackageInfo when a ClassInfo is added to a package.
888 // This is needed because ApiCheck uses PackageInfo.addClass
889 // rather than using setContainingPackage to dispatch to the
890 // appropriate method. TODO: move ApiCheck away from addClass.
891 void setPackage(PackageInfo pkg) {
892 mContainingPackage = pkg;
Ben Dodson920dbbb2010-08-04 15:21:06 -0700893 }
894
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -0700895 public void setContainingPackage(PackageInfo pkg) {
896 mContainingPackage = pkg;
897
898 if (mContainingPackage != null) {
899 if (mIsEnum) {
900 mContainingPackage.addEnum(this);
901 } else if (mIsInterface) {
902 mContainingPackage.addInterface(this);
903 } else {
904 mContainingPackage.addOrdinaryClass(this);
905 }
906 }
907 }
908
909 public ArrayList<AttributeInfo> selfAttributes() {
Ben Dodson920dbbb2010-08-04 15:21:06 -0700910 if (mSelfAttributes == null) {
911 TreeMap<FieldInfo, AttributeInfo> attrs = new TreeMap<FieldInfo, AttributeInfo>();
912
913 // the ones in the class comment won't have any methods
914 for (AttrTagInfo tag : comment().attrTags()) {
915 FieldInfo field = tag.reference();
916 if (field != null) {
917 AttributeInfo attr = attrs.get(field);
918 if (attr == null) {
919 attr = new AttributeInfo(this, field);
920 attrs.put(field, attr);
921 }
922 tag.setAttribute(attr);
923 }
924 }
925
926 // in the methods
927 for (MethodInfo m : selfMethods()) {
928 for (AttrTagInfo tag : m.comment().attrTags()) {
929 FieldInfo field = tag.reference();
930 if (field != null) {
931 AttributeInfo attr = attrs.get(field);
932 if (attr == null) {
933 attr = new AttributeInfo(this, field);
934 attrs.put(field, attr);
935 }
936 tag.setAttribute(attr);
937 attr.methods.add(m);
938 }
939 }
940 }
941
942 // constructors too
943 for (MethodInfo m : constructors()) {
944 for (AttrTagInfo tag : m.comment().attrTags()) {
945 FieldInfo field = tag.reference();
946 if (field != null) {
947 AttributeInfo attr = attrs.get(field);
948 if (attr == null) {
949 attr = new AttributeInfo(this, field);
950 attrs.put(field, attr);
951 }
952 tag.setAttribute(attr);
953 attr.methods.add(m);
954 }
955 }
956 }
957
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -0700958 mSelfAttributes = new ArrayList<AttributeInfo>(attrs.values());
959 Collections.sort(mSelfAttributes, AttributeInfo.comparator);
Ben Dodson920dbbb2010-08-04 15:21:06 -0700960 }
961 return mSelfAttributes;
962 }
963
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -0700964 public ArrayList<FieldInfo> enumConstants() {
Ben Dodson920dbbb2010-08-04 15:21:06 -0700965 return mEnumConstants;
966 }
967
968 public ClassInfo superclass() {
969 if (!mSuperclassInit) {
970 if (this.checkLevel()) {
971 // rearrange our little inheritance hierarchy, because we need to hide classes that
972 // don't pass checkLevel
973 ClassInfo superclass = mRealSuperclass;
974 while (superclass != null && !superclass.checkLevel()) {
975 superclass = superclass.mRealSuperclass;
976 }
977 mSuperclass = superclass;
978 } else {
979 mSuperclass = mRealSuperclass;
980 }
981 }
982 return mSuperclass;
983 }
984
985 public ClassInfo realSuperclass() {
986 return mRealSuperclass;
987 }
988
989 /**
990 * always the real superclass, not the collapsed one we get through superclass(), also has the
991 * type parameter info if it's generic.
992 */
993 public TypeInfo superclassType() {
994 return mRealSuperclassType;
995 }
996
997 public TypeInfo asTypeInfo() {
998 return mTypeInfo;
999 }
1000
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -07001001 ArrayList<TypeInfo> interfaceTypes() {
1002 ArrayList<TypeInfo> types = new ArrayList<TypeInfo>();
1003 for (ClassInfo iface : interfaces()) {
1004 types.add(iface.asTypeInfo());
1005 }
1006 return types;
Ben Dodson920dbbb2010-08-04 15:21:06 -07001007 }
1008
1009 public String htmlPage() {
1010 String s = containingPackage().name();
1011 s = s.replace('.', '/');
1012 s += '/';
1013 s += name();
1014 s += ".html";
1015 s = Doclava.javadocDir + s;
1016 return s;
1017 }
1018
1019 /** Even indirectly */
1020 public boolean isDerivedFrom(ClassInfo cl) {
Joe Onorato59351352011-03-01 15:32:37 -08001021 return isDerivedFrom(cl.qualifiedName());
1022 }
1023
1024 /** Even indirectly */
1025 public boolean isDerivedFrom(String qualifiedName) {
Ben Dodson920dbbb2010-08-04 15:21:06 -07001026 ClassInfo dad = this.superclass();
1027 if (dad != null) {
Joe Onorato59351352011-03-01 15:32:37 -08001028 if (dad.mQualifiedName.equals(qualifiedName)) {
Ben Dodson920dbbb2010-08-04 15:21:06 -07001029 return true;
1030 } else {
Joe Onorato59351352011-03-01 15:32:37 -08001031 if (dad.isDerivedFrom(qualifiedName)) {
Ben Dodson920dbbb2010-08-04 15:21:06 -07001032 return true;
1033 }
1034 }
1035 }
1036 for (ClassInfo iface : interfaces()) {
Joe Onorato59351352011-03-01 15:32:37 -08001037 if (iface.mQualifiedName.equals(qualifiedName)) {
Ben Dodson920dbbb2010-08-04 15:21:06 -07001038 return true;
1039 } else {
Joe Onorato59351352011-03-01 15:32:37 -08001040 if (iface.isDerivedFrom(qualifiedName)) {
Ben Dodson920dbbb2010-08-04 15:21:06 -07001041 return true;
1042 }
1043 }
1044 }
1045 return false;
1046 }
1047
1048 public void makeKeywordEntries(List<KeywordEntry> keywords) {
1049 if (!checkLevel()) {
1050 return;
1051 }
1052
1053 String htmlPage = htmlPage();
1054 String qualifiedName = qualifiedName();
1055
1056 keywords.add(new KeywordEntry(name(), htmlPage, "class in " + containingPackage().name()));
1057
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -07001058 ArrayList<FieldInfo> fields = selfFields();
1059 //ArrayList<FieldInfo> enumConstants = enumConstants();
1060 ArrayList<MethodInfo> ctors = constructors();
1061 ArrayList<MethodInfo> methods = selfMethods();
Ben Dodson920dbbb2010-08-04 15:21:06 -07001062
1063 // enum constants
1064 for (FieldInfo field : enumConstants()) {
1065 if (field.checkLevel()) {
1066 keywords.add(new KeywordEntry(field.name(), htmlPage + "#" + field.anchor(),
1067 "enum constant in " + qualifiedName));
1068 }
1069 }
1070
1071 // constants
1072 for (FieldInfo field : fields) {
1073 if (field.isConstant() && field.checkLevel()) {
1074 keywords.add(new KeywordEntry(field.name(), htmlPage + "#" + field.anchor(), "constant in "
1075 + qualifiedName));
1076 }
1077 }
1078
1079 // fields
1080 for (FieldInfo field : fields) {
1081 if (!field.isConstant() && field.checkLevel()) {
1082 keywords.add(new KeywordEntry(field.name(), htmlPage + "#" + field.anchor(), "field in "
1083 + qualifiedName));
1084 }
1085 }
1086
1087 // public constructors
1088 for (MethodInfo m : ctors) {
1089 if (m.isPublic() && m.checkLevel()) {
1090 keywords.add(new KeywordEntry(m.prettySignature(), htmlPage + "#" + m.anchor(),
1091 "constructor in " + qualifiedName));
1092 }
1093 }
1094
1095 // protected constructors
1096 if (Doclava.checkLevel(Doclava.SHOW_PROTECTED)) {
1097 for (MethodInfo m : ctors) {
1098 if (m.isProtected() && m.checkLevel()) {
1099 keywords.add(new KeywordEntry(m.prettySignature(),
1100 htmlPage + "#" + m.anchor(), "constructor in " + qualifiedName));
1101 }
1102 }
1103 }
1104
1105 // package private constructors
1106 if (Doclava.checkLevel(Doclava.SHOW_PACKAGE)) {
1107 for (MethodInfo m : ctors) {
1108 if (m.isPackagePrivate() && m.checkLevel()) {
1109 keywords.add(new KeywordEntry(m.prettySignature(),
1110 htmlPage + "#" + m.anchor(), "constructor in " + qualifiedName));
1111 }
1112 }
1113 }
1114
1115 // private constructors
1116 if (Doclava.checkLevel(Doclava.SHOW_PRIVATE)) {
1117 for (MethodInfo m : ctors) {
1118 if (m.isPrivate() && m.checkLevel()) {
1119 keywords.add(new KeywordEntry(m.name() + m.prettySignature(),
1120 htmlPage + "#" + m.anchor(), "constructor in " + qualifiedName));
1121 }
1122 }
1123 }
1124
1125 // public methods
1126 for (MethodInfo m : methods) {
1127 if (m.isPublic() && m.checkLevel()) {
1128 keywords.add(new KeywordEntry(m.name() + m.prettySignature(), htmlPage + "#" + m.anchor(),
1129 "method in " + qualifiedName));
1130 }
1131 }
1132
1133 // protected methods
1134 if (Doclava.checkLevel(Doclava.SHOW_PROTECTED)) {
1135 for (MethodInfo m : methods) {
1136 if (m.isProtected() && m.checkLevel()) {
1137 keywords.add(new KeywordEntry(m.name() + m.prettySignature(),
1138 htmlPage + "#" + m.anchor(), "method in " + qualifiedName));
1139 }
1140 }
1141 }
1142
1143 // package private methods
1144 if (Doclava.checkLevel(Doclava.SHOW_PACKAGE)) {
1145 for (MethodInfo m : methods) {
1146 if (m.isPackagePrivate() && m.checkLevel()) {
1147 keywords.add(new KeywordEntry(m.name() + m.prettySignature(),
1148 htmlPage + "#" + m.anchor(), "method in " + qualifiedName));
1149 }
1150 }
1151 }
1152
1153 // private methods
1154 if (Doclava.checkLevel(Doclava.SHOW_PRIVATE)) {
1155 for (MethodInfo m : methods) {
1156 if (m.isPrivate() && m.checkLevel()) {
1157 keywords.add(new KeywordEntry(m.name() + m.prettySignature(),
1158 htmlPage + "#" + m.anchor(), "method in " + qualifiedName));
1159 }
1160 }
1161 }
1162 }
1163
1164 public void makeLink(Data data, String base) {
1165 data.setValue(base + ".label", this.name());
1166 if (!this.isPrimitive() && this.isIncluded() && this.checkLevel()) {
1167 data.setValue(base + ".link", this.htmlPage());
1168 }
1169 }
1170
1171 public static void makeLinkListHDF(Data data, String base, ClassInfo[] classes) {
1172 final int N = classes.length;
1173 for (int i = 0; i < N; i++) {
1174 ClassInfo cl = classes[i];
1175 if (cl.checkLevel()) {
1176 cl.asTypeInfo().makeHDF(data, base + "." + i);
1177 }
1178 }
1179 }
1180
1181 /**
1182 * Used in lists of this class (packages, nested classes, known subclasses)
1183 */
1184 public void makeShortDescrHDF(Data data, String base) {
1185 mTypeInfo.makeHDF(data, base + ".type");
1186 data.setValue(base + ".kind", this.kind());
1187 TagInfo.makeHDF(data, base + ".shortDescr", this.firstSentenceTags());
1188 TagInfo.makeHDF(data, base + ".deprecated", deprecatedTags());
1189 data.setValue(base + ".since", getSince());
Scott Main40ad1472012-10-24 18:19:17 -07001190 if (isDeprecated()) {
1191 data.setValue(base + ".deprecatedsince", getDeprecatedSince());
1192 }
Jeff Arnesonb84c41b2014-08-12 15:22:00 -07001193
Jeff Arneson9ee73fd2014-10-08 14:42:29 -07001194 ArrayList<AnnotationInstanceInfo> showAnnos = getShowAnnotationsIncludeOuters();
Jeff Arnesonb84c41b2014-08-12 15:22:00 -07001195 AnnotationInstanceInfo.makeLinkListHDF(
1196 data,
1197 base + ".showAnnotations",
Jeff Arneson9ee73fd2014-10-08 14:42:29 -07001198 showAnnos.toArray(new AnnotationInstanceInfo[showAnnos.size()]));
Jeff Arnesonb84c41b2014-08-12 15:22:00 -07001199
Ben Dodson920dbbb2010-08-04 15:21:06 -07001200 setFederatedReferences(data, base);
1201 }
1202
1203 /**
1204 * Turns into the main class page
1205 */
1206 public void makeHDF(Data data) {
1207 int i, j, n;
1208 String name = name();
1209 String qualified = qualifiedName();
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -07001210 ArrayList<AttributeInfo> selfAttributes = selfAttributes();
1211 ArrayList<MethodInfo> methods = selfMethods();
1212 ArrayList<FieldInfo> fields = selfFields();
1213 ArrayList<FieldInfo> enumConstants = enumConstants();
1214 ArrayList<MethodInfo> ctors = constructors();
1215 ArrayList<ClassInfo> inners = innerClasses();
Ben Dodson920dbbb2010-08-04 15:21:06 -07001216
1217 // class name
1218 mTypeInfo.makeHDF(data, "class.type");
1219 mTypeInfo.makeQualifiedHDF(data, "class.qualifiedType");
1220 data.setValue("class.name", name);
1221 data.setValue("class.qualified", qualified);
Ben Dodson920dbbb2010-08-04 15:21:06 -07001222 if (isProtected()) {
1223 data.setValue("class.scope", "protected");
1224 } else if (isPublic()) {
1225 data.setValue("class.scope", "public");
1226 }
1227 if (isStatic()) {
1228 data.setValue("class.static", "static");
1229 }
1230 if (isFinal()) {
1231 data.setValue("class.final", "final");
1232 }
1233 if (isAbstract() && !isInterface()) {
1234 data.setValue("class.abstract", "abstract");
1235 }
1236
Jeff Arnesonb2a6c042015-03-27 14:54:47 -07001237 int numAnnotationDocumentation = 0;
1238 for (AnnotationInstanceInfo aii : annotations()) {
1239 String annotationDocumentation = Doclava.getDocumentationStringForAnnotation(
1240 aii.type().qualifiedName());
1241 if (annotationDocumentation != null) {
1242 data.setValue("class.annotationdocumentation." + numAnnotationDocumentation + ".text",
1243 annotationDocumentation);
1244 numAnnotationDocumentation++;
1245 }
1246 }
1247
Jeff Arneson9ee73fd2014-10-08 14:42:29 -07001248 ArrayList<AnnotationInstanceInfo> showAnnos = getShowAnnotationsIncludeOuters();
Jeff Arnesonb84c41b2014-08-12 15:22:00 -07001249 AnnotationInstanceInfo.makeLinkListHDF(
1250 data,
1251 "class.showAnnotations",
Jeff Arneson9ee73fd2014-10-08 14:42:29 -07001252 showAnnos.toArray(new AnnotationInstanceInfo[showAnnos.size()]));
Jeff Arnesonb84c41b2014-08-12 15:22:00 -07001253
Ben Dodson920dbbb2010-08-04 15:21:06 -07001254 // class info
1255 String kind = kind();
1256 if (kind != null) {
1257 data.setValue("class.kind", kind);
1258 }
1259 data.setValue("class.since", getSince());
Scott Main40ad1472012-10-24 18:19:17 -07001260 if (isDeprecated()) {
1261 data.setValue("class.deprecatedsince", getDeprecatedSince());
1262 }
Ben Dodson920dbbb2010-08-04 15:21:06 -07001263 setFederatedReferences(data, "class");
1264
1265 // the containing package -- note that this can be passed to type_link,
1266 // but it also contains the list of all of the packages
1267 containingPackage().makeClassLinkListHDF(data, "class.package");
1268
1269 // inheritance hierarchy
Jeff Arnesond6570b02014-10-29 15:46:51 -07001270 List<ClassTypePair> ctplist = superClassesWithTypes();
1271 n = ctplist.size();
1272 for (i = 0; i < ctplist.size(); i++) {
1273 // go in reverse order
1274 ClassTypePair ctp = ctplist.get(n - i - 1);
1275 if (ctp.classInfo().checkLevel()) {
1276 ctp.typeInfo().makeQualifiedHDF(data, "class.inheritance." + i + ".class");
1277 ctp.typeInfo().makeHDF(data, "class.inheritance." + i + ".short_class");
1278 j = 0;
1279 for (ClassTypePair t : ctp.classInfo().interfacesWithTypes()) {
1280 t.typeInfo().makeHDF(data, "class.inheritance." + i + ".interfaces." + j);
1281 j++;
1282 }
Ben Dodson920dbbb2010-08-04 15:21:06 -07001283 }
1284 }
1285
1286 // class description
1287 TagInfo.makeHDF(data, "class.descr", inlineTags());
1288 TagInfo.makeHDF(data, "class.seeAlso", comment().seeTags());
1289 TagInfo.makeHDF(data, "class.deprecated", deprecatedTags());
1290
1291 // known subclasses
1292 TreeMap<String, ClassInfo> direct = new TreeMap<String, ClassInfo>();
1293 TreeMap<String, ClassInfo> indirect = new TreeMap<String, ClassInfo>();
1294 ClassInfo[] all = Converter.rootClasses();
1295 for (ClassInfo cl : all) {
1296 if (cl.superclass() != null && cl.superclass().equals(this)) {
1297 direct.put(cl.name(), cl);
1298 } else if (cl.isDerivedFrom(this)) {
1299 indirect.put(cl.name(), cl);
1300 }
1301 }
1302 // direct
1303 i = 0;
1304 for (ClassInfo cl : direct.values()) {
1305 if (cl.checkLevel()) {
1306 cl.makeShortDescrHDF(data, "class.subclasses.direct." + i);
1307 }
1308 i++;
1309 }
1310 // indirect
1311 i = 0;
1312 for (ClassInfo cl : indirect.values()) {
1313 if (cl.checkLevel()) {
1314 cl.makeShortDescrHDF(data, "class.subclasses.indirect." + i);
1315 }
1316 i++;
1317 }
1318
1319 // hide special cases
1320 if ("java.lang.Object".equals(qualified) || "java.io.Serializable".equals(qualified)) {
1321 data.setValue("class.subclasses.hidden", "1");
1322 } else {
1323 data.setValue("class.subclasses.hidden", "0");
1324 }
1325
1326 // nested classes
1327 i = 0;
1328 for (ClassInfo inner : inners) {
1329 if (inner.checkLevel()) {
1330 inner.makeShortDescrHDF(data, "class.inners." + i);
1331 }
1332 i++;
1333 }
1334
1335 // enum constants
1336 i = 0;
1337 for (FieldInfo field : enumConstants) {
Jesse Wilson331b8a22011-03-01 19:31:07 -08001338 field.makeHDF(data, "class.enumConstants." + i);
1339 i++;
Ben Dodson920dbbb2010-08-04 15:21:06 -07001340 }
1341
1342 // constants
1343 i = 0;
1344 for (FieldInfo field : fields) {
1345 if (field.isConstant()) {
1346 field.makeHDF(data, "class.constants." + i);
1347 i++;
1348 }
1349 }
1350
1351 // fields
1352 i = 0;
1353 for (FieldInfo field : fields) {
1354 if (!field.isConstant()) {
1355 field.makeHDF(data, "class.fields." + i);
1356 i++;
1357 }
1358 }
1359
1360 // public constructors
1361 i = 0;
1362 for (MethodInfo ctor : ctors) {
1363 if (ctor.isPublic()) {
1364 ctor.makeHDF(data, "class.ctors.public." + i);
1365 i++;
1366 }
1367 }
1368
1369 // protected constructors
1370 if (Doclava.checkLevel(Doclava.SHOW_PROTECTED)) {
1371 i = 0;
1372 for (MethodInfo ctor : ctors) {
1373 if (ctor.isProtected()) {
1374 ctor.makeHDF(data, "class.ctors.protected." + i);
1375 i++;
1376 }
1377 }
1378 }
1379
1380 // package private constructors
1381 if (Doclava.checkLevel(Doclava.SHOW_PACKAGE)) {
1382 i = 0;
1383 for (MethodInfo ctor : ctors) {
1384 if (ctor.isPackagePrivate()) {
1385 ctor.makeHDF(data, "class.ctors.package." + i);
1386 i++;
1387 }
1388 }
1389 }
1390
1391 // private constructors
1392 if (Doclava.checkLevel(Doclava.SHOW_PRIVATE)) {
1393 i = 0;
1394 for (MethodInfo ctor : ctors) {
1395 if (ctor.isPrivate()) {
1396 ctor.makeHDF(data, "class.ctors.private." + i);
1397 i++;
1398 }
1399 }
1400 }
1401
1402 // public methods
1403 i = 0;
1404 for (MethodInfo method : methods) {
1405 if (method.isPublic()) {
1406 method.makeHDF(data, "class.methods.public." + i);
1407 i++;
1408 }
1409 }
1410
1411 // protected methods
1412 if (Doclava.checkLevel(Doclava.SHOW_PROTECTED)) {
1413 i = 0;
1414 for (MethodInfo method : methods) {
1415 if (method.isProtected()) {
1416 method.makeHDF(data, "class.methods.protected." + i);
1417 i++;
1418 }
1419 }
1420 }
1421
1422 // package private methods
1423 if (Doclava.checkLevel(Doclava.SHOW_PACKAGE)) {
1424 i = 0;
1425 for (MethodInfo method : methods) {
1426 if (method.isPackagePrivate()) {
1427 method.makeHDF(data, "class.methods.package." + i);
1428 i++;
1429 }
1430 }
1431 }
1432
1433 // private methods
1434 if (Doclava.checkLevel(Doclava.SHOW_PRIVATE)) {
1435 i = 0;
1436 for (MethodInfo method : methods) {
1437 if (method.isPrivate()) {
1438 method.makeHDF(data, "class.methods.private." + i);
1439 i++;
1440 }
1441 }
1442 }
1443
1444 // xml attributes
1445 i = 0;
1446 for (AttributeInfo attr : selfAttributes) {
1447 if (attr.checkLevel()) {
1448 attr.makeHDF(data, "class.attrs." + i);
1449 i++;
1450 }
1451 }
1452
1453 // inherited methods
Jeff Arnesond6570b02014-10-29 15:46:51 -07001454 Iterator<ClassTypePair> superclassesItr = superClassesWithTypes().iterator();
1455 superclassesItr.next(); // skip the first one, which is the current class
1456 ClassTypePair superCtp;
Ben Dodson920dbbb2010-08-04 15:21:06 -07001457 i = 0;
Jeff Arnesond6570b02014-10-29 15:46:51 -07001458 while (superclassesItr.hasNext()) {
1459 superCtp = superclassesItr.next();
1460 if (superCtp.classInfo().checkLevel()) {
1461 makeInheritedHDF(data, i, superCtp);
1462 i++;
1463 }
Ben Dodson920dbbb2010-08-04 15:21:06 -07001464 }
Jeff Arnesond6570b02014-10-29 15:46:51 -07001465 Iterator<ClassTypePair> interfacesItr = allInterfacesWithTypes().iterator();
1466 while (interfacesItr.hasNext()) {
1467 superCtp = interfacesItr.next();
1468 if (superCtp.classInfo().checkLevel()) {
1469 makeInheritedHDF(data, i, superCtp);
1470 i++;
1471 }
Ben Dodson920dbbb2010-08-04 15:21:06 -07001472 }
1473 }
1474
Jeff Arnesond6570b02014-10-29 15:46:51 -07001475 private static void makeInheritedHDF(Data data, int index, ClassTypePair ctp) {
Ben Dodson920dbbb2010-08-04 15:21:06 -07001476 int i;
1477
1478 String base = "class.inherited." + index;
Jeff Arnesond6570b02014-10-29 15:46:51 -07001479 data.setValue(base + ".qualified", ctp.classInfo().qualifiedName());
1480 if (ctp.classInfo().checkLevel()) {
1481 data.setValue(base + ".link", ctp.classInfo().htmlPage());
Ben Dodson920dbbb2010-08-04 15:21:06 -07001482 }
Jeff Arnesond6570b02014-10-29 15:46:51 -07001483 String kind = ctp.classInfo().kind();
Ben Dodson920dbbb2010-08-04 15:21:06 -07001484 if (kind != null) {
1485 data.setValue(base + ".kind", kind);
1486 }
1487
Jeff Arnesond6570b02014-10-29 15:46:51 -07001488 if (ctp.classInfo().mIsIncluded) {
Ben Dodson920dbbb2010-08-04 15:21:06 -07001489 data.setValue(base + ".included", "true");
1490 } else {
Jeff Arnesond6570b02014-10-29 15:46:51 -07001491 Doclava.federationTagger.tagAll(new ClassInfo[] {ctp.classInfo()});
1492 if (!ctp.classInfo().getFederatedReferences().isEmpty()) {
1493 FederatedSite site = ctp.classInfo().getFederatedReferences().iterator().next();
1494 data.setValue(base + ".link", site.linkFor(ctp.classInfo().htmlPage()));
Ben Dodson920dbbb2010-08-04 15:21:06 -07001495 data.setValue(base + ".federated", site.name());
1496 }
1497 }
1498
1499 // xml attributes
1500 i = 0;
Jeff Arnesond6570b02014-10-29 15:46:51 -07001501 for (AttributeInfo attr : ctp.classInfo().selfAttributes()) {
Ben Dodson920dbbb2010-08-04 15:21:06 -07001502 attr.makeHDF(data, base + ".attrs." + i);
1503 i++;
1504 }
1505
1506 // methods
1507 i = 0;
Jeff Arnesond6570b02014-10-29 15:46:51 -07001508 for (MethodInfo method : ctp.classInfo().selfMethods()) {
1509 method.makeHDF(data, base + ".methods." + i, ctp.getTypeArgumentMapping());
Ben Dodson920dbbb2010-08-04 15:21:06 -07001510 i++;
1511 }
1512
1513 // fields
1514 i = 0;
Jeff Arnesond6570b02014-10-29 15:46:51 -07001515 for (FieldInfo field : ctp.classInfo().selfFields()) {
Ben Dodson920dbbb2010-08-04 15:21:06 -07001516 if (!field.isConstant()) {
1517 field.makeHDF(data, base + ".fields." + i);
1518 i++;
1519 }
1520 }
1521
1522 // constants
1523 i = 0;
Jeff Arnesond6570b02014-10-29 15:46:51 -07001524 for (FieldInfo field : ctp.classInfo().selfFields()) {
Ben Dodson920dbbb2010-08-04 15:21:06 -07001525 if (field.isConstant()) {
1526 field.makeHDF(data, base + ".constants." + i);
1527 i++;
1528 }
1529 }
1530 }
1531
1532 @Override
1533 public boolean isHidden() {
Hui Shu5118ffe2014-02-18 14:06:42 -08001534 if (mHidden == null) {
1535 mHidden = isHiddenImpl();
Ben Dodson920dbbb2010-08-04 15:21:06 -07001536 }
Hui Shu5118ffe2014-02-18 14:06:42 -08001537
1538 return mHidden;
Ben Dodson920dbbb2010-08-04 15:21:06 -07001539 }
1540
Hui Shu5118ffe2014-02-18 14:06:42 -08001541 /**
1542 * @return true if the containing package has @hide comment, or an ancestor
1543 * class of this class is hidden, or this class has @hide comment.
1544 */
Ben Dodson920dbbb2010-08-04 15:21:06 -07001545 public boolean isHiddenImpl() {
1546 ClassInfo cl = this;
1547 while (cl != null) {
Adam Metcalfe1b2ef42014-02-14 11:16:30 -08001548 if (cl.hasShowAnnotation()) {
Tim Murray3acc9d12014-05-22 19:21:55 +00001549 return false;
Adam Metcalfe1b2ef42014-02-14 11:16:30 -08001550 }
Tim Murray3acc9d12014-05-22 19:21:55 +00001551 PackageInfo pkg = cl.containingPackage();
Adam Metcalff2d2e932013-08-19 17:12:24 -07001552 if (pkg != null && pkg.hasHideComment()) {
1553 return true;
Dirk Dougherty9b316c82013-01-28 10:53:33 -08001554 }
Ben Dodson920dbbb2010-08-04 15:21:06 -07001555 if (cl.comment().isHidden()) {
1556 return true;
1557 }
1558 cl = cl.containingClass();
1559 }
1560 return false;
1561 }
1562
Hui Shu5118ffe2014-02-18 14:06:42 -08001563 @Override
1564 public boolean isRemoved() {
1565 if (mRemoved == null) {
1566 mRemoved = isRemovedImpl();
1567 }
1568
1569 return mRemoved;
1570 }
1571
1572 /**
1573 * @return true if the containing package has @removed comment, or an ancestor
1574 * class of this class is removed, or this class has @removed comment.
1575 */
1576 public boolean isRemovedImpl() {
1577 ClassInfo cl = this;
1578 while (cl != null) {
1579 if (cl.hasShowAnnotation()) {
1580 return false;
1581 }
1582 PackageInfo pkg = cl.containingPackage();
1583 if (pkg != null && pkg.hasRemovedComment()) {
1584 return true;
1585 }
1586 if (cl.comment().isRemoved()) {
1587 return true;
1588 }
1589 cl = cl.containingClass();
1590 }
1591 return false;
1592 }
1593
1594 @Override
1595 public boolean isHiddenOrRemoved() {
1596 return isHidden() || isRemoved();
1597 }
1598
Adam Metcalff2d2e932013-08-19 17:12:24 -07001599 public boolean hasShowAnnotation() {
Brett Chabota2769ed2014-09-10 15:02:18 -07001600 return mShowAnnotations != null && mShowAnnotations.size() > 0;
Jeff Arnesonb84c41b2014-08-12 15:22:00 -07001601 }
1602
1603 public ArrayList<AnnotationInstanceInfo> showAnnotations() {
1604 return mShowAnnotations;
Adam Metcalff2d2e932013-08-19 17:12:24 -07001605 }
1606
Jeff Arneson9ee73fd2014-10-08 14:42:29 -07001607 public ArrayList<AnnotationInstanceInfo> getShowAnnotationsIncludeOuters() {
1608 ArrayList<AnnotationInstanceInfo> allAnnotations = new ArrayList<AnnotationInstanceInfo>();
1609 ClassInfo cl = this;
1610 while (cl != null) {
1611 if (cl.showAnnotations() != null) {
1612 // Don't allow duplicates into the merged list
1613 for (AnnotationInstanceInfo newAii : cl.showAnnotations()) {
1614 boolean addIt = true;
1615 for (AnnotationInstanceInfo existingAii : allAnnotations) {
1616 if (existingAii.type().name() == newAii.type().name()) {
1617 addIt = false;
1618 break;
1619 }
1620 }
1621 if (addIt) {
1622 allAnnotations.add(newAii);
1623 }
1624 }
1625 }
1626 cl = cl.containingClass();
1627 }
1628 return allAnnotations;
1629 }
1630
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -07001631 private MethodInfo matchMethod(ArrayList<MethodInfo> methods, String name, String[] params,
Ben Dodson920dbbb2010-08-04 15:21:06 -07001632 String[] dimensions, boolean varargs) {
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -07001633 for (MethodInfo method : methods) {
Ben Dodson920dbbb2010-08-04 15:21:06 -07001634 if (method.name().equals(name)) {
1635 if (params == null) {
1636 return method;
1637 } else {
1638 if (method.matchesParams(params, dimensions, varargs)) {
1639 return method;
1640 }
1641 }
1642 }
1643 }
1644 return null;
1645 }
1646
1647 public MethodInfo findMethod(String name, String[] params, String[] dimensions, boolean varargs) {
1648 // first look on our class, and our superclasses
1649
1650 // for methods
1651 MethodInfo rv;
1652 rv = matchMethod(methods(), name, params, dimensions, varargs);
1653
1654 if (rv != null) {
1655 return rv;
1656 }
1657
1658 // for constructors
1659 rv = matchMethod(constructors(), name, params, dimensions, varargs);
1660 if (rv != null) {
1661 return rv;
1662 }
1663
1664 // then recursively look at our containing class
1665 ClassInfo containing = containingClass();
1666 if (containing != null) {
1667 return containing.findMethod(name, params, dimensions, varargs);
1668 }
1669
1670 return null;
1671 }
Dirk Dougherty9b316c82013-01-28 10:53:33 -08001672
Ben Dodson920dbbb2010-08-04 15:21:06 -07001673 public boolean supportsMethod(MethodInfo method) {
1674 for (MethodInfo m : methods()) {
1675 if (m.getHashableName().equals(method.getHashableName())) {
1676 return true;
1677 }
1678 }
1679 return false;
1680 }
1681
1682 private ClassInfo searchInnerClasses(String[] nameParts, int index) {
1683 String part = nameParts[index];
1684
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -07001685 ArrayList<ClassInfo> inners = mInnerClasses;
Ben Dodson920dbbb2010-08-04 15:21:06 -07001686 for (ClassInfo in : inners) {
1687 String[] innerParts = in.nameParts();
1688 if (part.equals(innerParts[innerParts.length - 1])) {
1689 if (index == nameParts.length - 1) {
1690 return in;
1691 } else {
1692 return in.searchInnerClasses(nameParts, index + 1);
1693 }
1694 }
1695 }
1696 return null;
1697 }
1698
1699 public ClassInfo extendedFindClass(String className) {
1700 // ClassDoc.findClass has this bug that we're working around here:
1701 // If you have a class PackageManager with an inner class PackageInfo
1702 // and you call it with "PackageInfo" it doesn't find it.
1703 return searchInnerClasses(className.split("\\."), 0);
1704 }
1705
1706 public ClassInfo findClass(String className) {
1707 return Converter.obtainClass(mClass.findClass(className));
1708 }
1709
1710 public ClassInfo findInnerClass(String className) {
1711 // ClassDoc.findClass won't find inner classes. To deal with that,
1712 // we try what they gave us first, but if that didn't work, then
1713 // we see if there are any periods in className, and start searching
1714 // from there.
1715 String[] nodes = className.split("\\.");
1716 ClassDoc cl = mClass;
Narayan Kamathb1b0ee72013-10-24 15:57:08 +01001717
1718 int N = nodes.length;
1719 for (int i = 0; i < N; ++i) {
1720 final String n = nodes[i];
1721 if (n.isEmpty() && i == 0) {
1722 // We skip over an empty classname component if it's at location 0. This is
1723 // to deal with names like ".Inner". java7 will return a bogus ClassInfo when
1724 // we call "findClass("") and the next iteration of the loop will throw a
1725 // runtime exception.
1726 continue;
1727 }
1728
Ben Dodson920dbbb2010-08-04 15:21:06 -07001729 cl = cl.findClass(n);
1730 if (cl == null) {
1731 return null;
1732 }
1733 }
Narayan Kamathb1b0ee72013-10-24 15:57:08 +01001734
Ben Dodson920dbbb2010-08-04 15:21:06 -07001735 return Converter.obtainClass(cl);
1736 }
1737
1738 public FieldInfo findField(String name) {
1739 // first look on our class, and our superclasses
1740 for (FieldInfo f : fields()) {
1741 if (f.name().equals(name)) {
1742 return f;
1743 }
1744 }
1745
1746 // then look at our enum constants (these are really fields, maybe
1747 // they should be mixed into fields(). not sure)
1748 for (FieldInfo f : enumConstants()) {
1749 if (f.name().equals(name)) {
1750 return f;
1751 }
1752 }
1753
1754 // then recursively look at our containing class
1755 ClassInfo containing = containingClass();
1756 if (containing != null) {
1757 return containing.findField(name);
1758 }
1759
1760 return null;
1761 }
1762
1763 public static ClassInfo[] sortByName(ClassInfo[] classes) {
1764 int i;
1765 Sorter[] sorted = new Sorter[classes.length];
1766 for (i = 0; i < sorted.length; i++) {
1767 ClassInfo cl = classes[i];
1768 sorted[i] = new Sorter(cl.name(), cl);
1769 }
1770
1771 Arrays.sort(sorted);
1772
1773 ClassInfo[] rv = new ClassInfo[classes.length];
1774 for (i = 0; i < rv.length; i++) {
1775 rv[i] = (ClassInfo) sorted[i].data;
1776 }
1777
1778 return rv;
1779 }
1780
1781 public boolean equals(ClassInfo that) {
1782 if (that != null) {
1783 return this.qualifiedName().equals(that.qualifiedName());
1784 } else {
1785 return false;
1786 }
1787 }
1788
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -07001789 public void setNonWrittenConstructors(ArrayList<MethodInfo> nonWritten) {
Ben Dodson920dbbb2010-08-04 15:21:06 -07001790 mNonWrittenConstructors = nonWritten;
1791 }
1792
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -07001793 public ArrayList<MethodInfo> getNonWrittenConstructors() {
Ben Dodson920dbbb2010-08-04 15:21:06 -07001794 return mNonWrittenConstructors;
1795 }
1796
1797 public String kind() {
1798 if (isOrdinaryClass()) {
1799 return "class";
1800 } else if (isInterface()) {
1801 return "interface";
1802 } else if (isEnum()) {
1803 return "enum";
1804 } else if (isError()) {
1805 return "class";
1806 } else if (isException()) {
1807 return "class";
1808 } else if (isAnnotation()) {
1809 return "@interface";
1810 }
1811 return null;
1812 }
Dirk Dougherty9b316c82013-01-28 10:53:33 -08001813
Ben Dodson920dbbb2010-08-04 15:21:06 -07001814 public String scope() {
1815 if (isPublic()) {
1816 return "public";
1817 } else if (isProtected()) {
1818 return "protected";
1819 } else if (isPackagePrivate()) {
1820 return "";
1821 } else if (isPrivate()) {
1822 return "private";
1823 } else {
1824 throw new RuntimeException("invalid scope for object " + this);
1825 }
1826 }
1827
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -07001828 public void setHiddenMethods(ArrayList<MethodInfo> mInfo) {
Ben Dodson920dbbb2010-08-04 15:21:06 -07001829 mHiddenMethods = mInfo;
1830 }
1831
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -07001832 public ArrayList<MethodInfo> getHiddenMethods() {
Ben Dodson920dbbb2010-08-04 15:21:06 -07001833 return mHiddenMethods;
1834 }
1835
1836 @Override
1837 public String toString() {
1838 return this.qualifiedName();
1839 }
1840
1841 public void setReasonIncluded(String reason) {
1842 mReasonIncluded = reason;
1843 }
1844
1845 public String getReasonIncluded() {
1846 return mReasonIncluded;
1847 }
1848
1849 private ClassDoc mClass;
1850
1851 // ctor
1852 private boolean mIsPublic;
1853 private boolean mIsProtected;
1854 private boolean mIsPackagePrivate;
1855 private boolean mIsPrivate;
1856 private boolean mIsStatic;
1857 private boolean mIsInterface;
1858 private boolean mIsAbstract;
1859 private boolean mIsOrdinaryClass;
1860 private boolean mIsException;
1861 private boolean mIsError;
1862 private boolean mIsEnum;
1863 private boolean mIsAnnotation;
1864 private boolean mIsFinal;
1865 private boolean mIsIncluded;
1866 private String mName;
1867 private String mQualifiedName;
1868 private String mQualifiedTypeName;
1869 private boolean mIsPrimitive;
1870 private TypeInfo mTypeInfo;
1871 private String[] mNameParts;
1872
1873 // init
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -07001874 private ArrayList<ClassInfo> mRealInterfaces = new ArrayList<ClassInfo>();
1875 private ArrayList<ClassInfo> mInterfaces;
1876 private ArrayList<TypeInfo> mRealInterfaceTypes;
1877 private ArrayList<ClassInfo> mInnerClasses;
Hui Shu5118ffe2014-02-18 14:06:42 -08001878 // mAllConstructors will not contain *all* constructors. Only the constructors that pass
1879 // checkLevel. @see {@link Converter#convertMethods(ConstructorDoc[])}
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -07001880 private ArrayList<MethodInfo> mAllConstructors = new ArrayList<MethodInfo>();
Hui Shu5118ffe2014-02-18 14:06:42 -08001881 // mAllSelfMethods will not contain *all* self methods. Only the methods that pass
1882 // checkLevel. @see {@link Converter#convertMethods(MethodDoc[])}
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -07001883 private ArrayList<MethodInfo> mAllSelfMethods = new ArrayList<MethodInfo>();
1884 private ArrayList<MethodInfo> mAnnotationElements = new ArrayList<MethodInfo>(); // if this class is an annotation
1885 private ArrayList<FieldInfo> mAllSelfFields = new ArrayList<FieldInfo>();
1886 private ArrayList<FieldInfo> mEnumConstants = new ArrayList<FieldInfo>();
Ben Dodson920dbbb2010-08-04 15:21:06 -07001887 private PackageInfo mContainingPackage;
1888 private ClassInfo mContainingClass;
1889 private ClassInfo mRealSuperclass;
1890 private TypeInfo mRealSuperclassType;
1891 private ClassInfo mSuperclass;
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -07001892 private ArrayList<AnnotationInstanceInfo> mAnnotations;
Jeff Arnesonb84c41b2014-08-12 15:22:00 -07001893 private ArrayList<AnnotationInstanceInfo> mShowAnnotations;
Ben Dodson920dbbb2010-08-04 15:21:06 -07001894 private boolean mSuperclassInit;
1895 private boolean mDeprecatedKnown;
1896
1897 // lazy
Jeff Arnesond6570b02014-10-29 15:46:51 -07001898 private ArrayList<ClassTypePair> mSuperclassesWithTypes;
1899 private ArrayList<ClassTypePair> mInterfacesWithTypes;
1900 private ArrayList<ClassTypePair> mAllInterfacesWithTypes;
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -07001901 private ArrayList<MethodInfo> mConstructors;
1902 private ArrayList<ClassInfo> mRealInnerClasses;
1903 private ArrayList<MethodInfo> mSelfMethods;
1904 private ArrayList<FieldInfo> mSelfFields;
1905 private ArrayList<AttributeInfo> mSelfAttributes;
1906 private ArrayList<MethodInfo> mMethods;
1907 private ArrayList<FieldInfo> mFields;
1908 private ArrayList<TypeInfo> mTypeParameters;
1909 private ArrayList<MethodInfo> mHiddenMethods;
Hui Shu5118ffe2014-02-18 14:06:42 -08001910 private Boolean mHidden = null;
1911 private Boolean mRemoved = null;
1912 private Boolean mCheckLevel = null;
Ben Dodson920dbbb2010-08-04 15:21:06 -07001913 private String mReasonIncluded;
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -07001914 private ArrayList<MethodInfo> mNonWrittenConstructors;
Ben Dodson920dbbb2010-08-04 15:21:06 -07001915 private boolean mIsDeprecated;
Dirk Dougherty9b316c82013-01-28 10:53:33 -08001916
Ben Dodson920dbbb2010-08-04 15:21:06 -07001917 // TODO: Temporary members from apicheck migration.
Joe Onorato04099252011-03-09 13:34:18 -08001918 private HashMap<String, MethodInfo> mApiCheckConstructors = new HashMap<String, MethodInfo>();
Ben Dodson920dbbb2010-08-04 15:21:06 -07001919 private HashMap<String, MethodInfo> mApiCheckMethods = new HashMap<String, MethodInfo>();
1920 private HashMap<String, FieldInfo> mApiCheckFields = new HashMap<String, FieldInfo>();
Joe Onorato132afe42011-05-31 18:13:38 -07001921 private HashMap<String, FieldInfo> mApiCheckEnumConstants = new HashMap<String, FieldInfo>();
Andrew Sapperstein6ba612e2011-06-20 18:41:24 -07001922
1923 // Resolutions
1924 private ArrayList<Resolution> mResolutions;
Dirk Dougherty9b316c82013-01-28 10:53:33 -08001925
Hui Shu5118ffe2014-02-18 14:06:42 -08001926 private List<MethodInfo> mRemovedConstructors; // immutable after you set its value.
1927 // @removed self methods that do not override any parent methods
1928 private List<MethodInfo> mRemovedSelfMethods; // immutable after you set its value.
1929 private List<MethodInfo> mRemovedMethods; // immutable after you set its value.
1930 private List<FieldInfo> mRemovedSelfFields; // immutable after you set its value.
1931 private List<FieldInfo> mRemovedEnumConstants; // immutable after you set its value.
1932
Ben Dodson920dbbb2010-08-04 15:21:06 -07001933 /**
1934 * Returns true if {@code cl} implements the interface {@code iface} either by either being that
1935 * interface, implementing that interface or extending a type that implements the interface.
1936 */
Mathieu11b17962013-06-07 17:24:18 -05001937 public boolean implementsInterface(String iface) {
1938 if (qualifiedName().equals(iface)) {
Ben Dodson920dbbb2010-08-04 15:21:06 -07001939 return true;
1940 }
Florian Uunk53d13be2014-06-25 17:01:21 +01001941 for (ClassInfo clImplements : realInterfaces()) {
Mathieu11b17962013-06-07 17:24:18 -05001942 if (clImplements.implementsInterface(iface)) {
Ben Dodson920dbbb2010-08-04 15:21:06 -07001943 return true;
1944 }
1945 }
Mathieu11b17962013-06-07 17:24:18 -05001946 if (mSuperclass != null && mSuperclass.implementsInterface(iface)) {
Ben Dodson920dbbb2010-08-04 15:21:06 -07001947 return true;
1948 }
1949 return false;
1950 }
1951
Mathieuffecf3c2013-06-05 20:35:37 -05001952 /**
Mathieu11b17962013-06-07 17:24:18 -05001953 * Returns true if {@code this} extends the class {@code ext}.
Mathieuffecf3c2013-06-05 20:35:37 -05001954 */
Mathieu11b17962013-06-07 17:24:18 -05001955 public boolean extendsClass(String cl) {
1956 if (qualifiedName().equals(cl)) {
Mathieuffecf3c2013-06-05 20:35:37 -05001957 return true;
1958 }
Mathieu11b17962013-06-07 17:24:18 -05001959 if (mSuperclass != null && mSuperclass.extendsClass(cl)) {
Mathieuffecf3c2013-06-05 20:35:37 -05001960 return true;
1961 }
1962 return false;
1963 }
1964
Mathieu11b17962013-06-07 17:24:18 -05001965 /**
1966 * Returns true if {@code this} is assignable to cl
1967 */
1968 public boolean isAssignableTo(String cl) {
1969 return implementsInterface(cl) || extendsClass(cl);
1970 }
1971
Ben Dodson920dbbb2010-08-04 15:21:06 -07001972 public void addInterface(ClassInfo iface) {
1973 mRealInterfaces.add(iface);
1974 }
1975
Joe Onorato04099252011-03-09 13:34:18 -08001976 public void addConstructor(MethodInfo ctor) {
1977 mApiCheckConstructors.put(ctor.getHashableName(), ctor);
Ben Dodson920dbbb2010-08-04 15:21:06 -07001978
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -07001979 mAllConstructors.add(ctor);
Joe Onorato04099252011-03-09 13:34:18 -08001980 mConstructors = null; // flush this, hopefully it hasn't been used yet.
Ben Dodson920dbbb2010-08-04 15:21:06 -07001981 }
1982
Joe Onorato04099252011-03-09 13:34:18 -08001983 public void addField(FieldInfo field) {
1984 mApiCheckFields.put(field.name(), field);
Ben Dodson920dbbb2010-08-04 15:21:06 -07001985
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -07001986 mAllSelfFields.add(field);
1987
Joe Onorato04099252011-03-09 13:34:18 -08001988 mSelfFields = null; // flush this, hopefully it hasn't been used yet.
Ben Dodson920dbbb2010-08-04 15:21:06 -07001989 }
1990
Joe Onorato132afe42011-05-31 18:13:38 -07001991 public void addEnumConstant(FieldInfo field) {
1992 mApiCheckEnumConstants.put(field.name(), field);
1993
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -07001994 mEnumConstants.add(field);
Joe Onorato132afe42011-05-31 18:13:38 -07001995 }
1996
Ben Dodson920dbbb2010-08-04 15:21:06 -07001997 public void setSuperClass(ClassInfo superclass) {
Joe Onorato04099252011-03-09 13:34:18 -08001998 mRealSuperclass = superclass;
Ben Dodson920dbbb2010-08-04 15:21:06 -07001999 mSuperclass = superclass;
2000 }
2001
Joe Onorato04099252011-03-09 13:34:18 -08002002 public Map<String, MethodInfo> allConstructorsMap() {
Ben Dodson920dbbb2010-08-04 15:21:06 -07002003 return mApiCheckConstructors;
2004 }
2005
2006 public Map<String, FieldInfo> allFields() {
2007 return mApiCheckFields;
2008 }
2009
Scott Main18904802013-08-07 13:53:14 -07002010 public Map<String, FieldInfo> allEnums() {
2011 return mApiCheckEnumConstants;
2012 }
2013
Ben Dodson920dbbb2010-08-04 15:21:06 -07002014 /**
2015 * Returns all methods defined directly in this class. For a list of all
2016 * methods supported by this class, see {@link #methods()}.
2017 */
Ben Dodson920dbbb2010-08-04 15:21:06 -07002018 public Map<String, MethodInfo> allMethods() {
2019 return mApiCheckMethods;
2020 }
2021
2022 /**
2023 * Returns the class hierarchy for this class, starting with this class.
2024 */
2025 public Iterable<ClassInfo> hierarchy() {
2026 List<ClassInfo> result = new ArrayList<ClassInfo>(4);
2027 for (ClassInfo c = this; c != null; c = c.mSuperclass) {
2028 result.add(c);
2029 }
2030 return result;
2031 }
Dirk Dougherty9b316c82013-01-28 10:53:33 -08002032
Ben Dodson920dbbb2010-08-04 15:21:06 -07002033 public String superclassName() {
2034 if (mSuperclass == null) {
2035 if (mQualifiedName.equals("java.lang.Object")) {
2036 return null;
2037 }
2038 throw new UnsupportedOperationException("Superclass not set for " + qualifiedName());
2039 }
2040 return mSuperclass.mQualifiedName;
2041 }
Dirk Dougherty9b316c82013-01-28 10:53:33 -08002042
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -07002043 public void setAnnotations(ArrayList<AnnotationInstanceInfo> annotations) {
Ben Dodson920dbbb2010-08-04 15:21:06 -07002044 mAnnotations = annotations;
2045 }
Dirk Dougherty9b316c82013-01-28 10:53:33 -08002046
Ben Dodson920dbbb2010-08-04 15:21:06 -07002047 public boolean isConsistent(ClassInfo cl) {
Guang Zhuf9b7c1b2015-04-24 16:45:42 -07002048 return isConsistent(cl, null, null);
2049 }
2050
2051 public boolean isConsistent(ClassInfo cl, List<MethodInfo> newCtors, List<MethodInfo> newMethods) {
Ben Dodson920dbbb2010-08-04 15:21:06 -07002052 boolean consistent = true;
Guang Zhuf9b7c1b2015-04-24 16:45:42 -07002053 boolean diffMode = (newCtors != null) && (newMethods != null);
Ben Dodson920dbbb2010-08-04 15:21:06 -07002054
2055 if (isInterface() != cl.isInterface()) {
2056 Errors.error(Errors.CHANGED_CLASS, cl.position(), "Class " + cl.qualifiedName()
2057 + " changed class/interface declaration");
2058 consistent = false;
2059 }
2060 for (ClassInfo iface : mRealInterfaces) {
Mathieu11b17962013-06-07 17:24:18 -05002061 if (!cl.implementsInterface(iface.mQualifiedName)) {
Ben Dodson920dbbb2010-08-04 15:21:06 -07002062 Errors.error(Errors.REMOVED_INTERFACE, cl.position(), "Class " + qualifiedName()
2063 + " no longer implements " + iface);
2064 }
2065 }
2066 for (ClassInfo iface : cl.mRealInterfaces) {
Mathieu11b17962013-06-07 17:24:18 -05002067 if (!implementsInterface(iface.mQualifiedName)) {
Ben Dodson920dbbb2010-08-04 15:21:06 -07002068 Errors.error(Errors.ADDED_INTERFACE, cl.position(), "Added interface " + iface
2069 + " to class " + qualifiedName());
2070 consistent = false;
2071 }
2072 }
2073
2074 for (MethodInfo mInfo : mApiCheckMethods.values()) {
2075 if (cl.mApiCheckMethods.containsKey(mInfo.getHashableName())) {
2076 if (!mInfo.isConsistent(cl.mApiCheckMethods.get(mInfo.getHashableName()))) {
2077 consistent = false;
2078 }
2079 } else {
2080 /*
2081 * This class formerly provided this method directly, and now does not. Check our ancestry
2082 * to see if there's an inherited version that still fulfills the API requirement.
2083 */
2084 MethodInfo mi = ClassInfo.overriddenMethod(mInfo, cl);
2085 if (mi == null) {
2086 mi = ClassInfo.interfaceMethod(mInfo, cl);
2087 }
2088 if (mi == null) {
2089 Errors.error(Errors.REMOVED_METHOD, mInfo.position(), "Removed public method "
C. Sean Younga7e5c7e2015-05-08 15:35:06 -05002090 + mInfo.prettyQualifiedSignature());
Ben Dodson920dbbb2010-08-04 15:21:06 -07002091 consistent = false;
2092 }
2093 }
2094 }
2095 for (MethodInfo mInfo : cl.mApiCheckMethods.values()) {
2096 if (!mApiCheckMethods.containsKey(mInfo.getHashableName())) {
2097 /*
2098 * Similarly to the above, do not fail if this "new" method is really an override of an
2099 * existing superclass method.
Ying Wang67e440b2015-03-31 12:24:02 -07002100 * But we should fail if this is overriding an abstract method, because method's
2101 * abstractness affects how users use it. See also Stubs.methodIsOverride().
Ben Dodson920dbbb2010-08-04 15:21:06 -07002102 */
2103 MethodInfo mi = ClassInfo.overriddenMethod(mInfo, this);
Ying Wang67e440b2015-03-31 12:24:02 -07002104 if (mi == null ||
2105 mi.isAbstract() != mInfo.isAbstract()) {
Ben Dodson920dbbb2010-08-04 15:21:06 -07002106 Errors.error(Errors.ADDED_METHOD, mInfo.position(), "Added public method "
C. Sean Younga7e5c7e2015-05-08 15:35:06 -05002107 + mInfo.prettyQualifiedSignature());
Guang Zhuf9b7c1b2015-04-24 16:45:42 -07002108 if (diffMode) {
2109 newMethods.add(mInfo);
2110 }
Ben Dodson920dbbb2010-08-04 15:21:06 -07002111 consistent = false;
2112 }
2113 }
2114 }
Guang Zhuf9b7c1b2015-04-24 16:45:42 -07002115 if (diffMode) {
2116 Collections.sort(newMethods, MethodInfo.comparator);
2117 }
Ben Dodson920dbbb2010-08-04 15:21:06 -07002118
Joe Onorato04099252011-03-09 13:34:18 -08002119 for (MethodInfo mInfo : mApiCheckConstructors.values()) {
Ben Dodson920dbbb2010-08-04 15:21:06 -07002120 if (cl.mApiCheckConstructors.containsKey(mInfo.getHashableName())) {
2121 if (!mInfo.isConsistent(cl.mApiCheckConstructors.get(mInfo.getHashableName()))) {
2122 consistent = false;
2123 }
2124 } else {
2125 Errors.error(Errors.REMOVED_METHOD, mInfo.position(), "Removed public constructor "
C. Sean Younga7e5c7e2015-05-08 15:35:06 -05002126 + mInfo.prettyQualifiedSignature());
Ben Dodson920dbbb2010-08-04 15:21:06 -07002127 consistent = false;
2128 }
2129 }
Joe Onorato04099252011-03-09 13:34:18 -08002130 for (MethodInfo mInfo : cl.mApiCheckConstructors.values()) {
Ben Dodson920dbbb2010-08-04 15:21:06 -07002131 if (!mApiCheckConstructors.containsKey(mInfo.getHashableName())) {
2132 Errors.error(Errors.ADDED_METHOD, mInfo.position(), "Added public constructor "
C. Sean Younga7e5c7e2015-05-08 15:35:06 -05002133 + mInfo.prettyQualifiedSignature());
Guang Zhuf9b7c1b2015-04-24 16:45:42 -07002134 if (diffMode) {
2135 newCtors.add(mInfo);
2136 }
Ben Dodson920dbbb2010-08-04 15:21:06 -07002137 consistent = false;
2138 }
2139 }
Guang Zhuf9b7c1b2015-04-24 16:45:42 -07002140 if (diffMode) {
2141 Collections.sort(newCtors, MethodInfo.comparator);
2142 }
Ben Dodson920dbbb2010-08-04 15:21:06 -07002143
2144 for (FieldInfo mInfo : mApiCheckFields.values()) {
2145 if (cl.mApiCheckFields.containsKey(mInfo.name())) {
2146 if (!mInfo.isConsistent(cl.mApiCheckFields.get(mInfo.name()))) {
2147 consistent = false;
2148 }
2149 } else {
2150 Errors.error(Errors.REMOVED_FIELD, mInfo.position(), "Removed field "
2151 + mInfo.qualifiedName());
2152 consistent = false;
2153 }
2154 }
2155 for (FieldInfo mInfo : cl.mApiCheckFields.values()) {
2156 if (!mApiCheckFields.containsKey(mInfo.name())) {
2157 Errors.error(Errors.ADDED_FIELD, mInfo.position(), "Added public field "
2158 + mInfo.qualifiedName());
2159 consistent = false;
2160 }
2161 }
2162
Joe Onorato132afe42011-05-31 18:13:38 -07002163 for (FieldInfo info : mApiCheckEnumConstants.values()) {
2164 if (cl.mApiCheckEnumConstants.containsKey(info.name())) {
2165 if (!info.isConsistent(cl.mApiCheckEnumConstants.get(info.name()))) {
2166 consistent = false;
2167 }
2168 } else {
2169 Errors.error(Errors.REMOVED_FIELD, info.position(), "Removed enum constant "
2170 + info.qualifiedName());
2171 consistent = false;
2172 }
2173 }
2174 for (FieldInfo info : cl.mApiCheckEnumConstants.values()) {
2175 if (!mApiCheckEnumConstants.containsKey(info.name())) {
2176 Errors.error(Errors.ADDED_FIELD, info.position(), "Added enum constant "
2177 + info.qualifiedName());
2178 consistent = false;
2179 }
2180 }
2181
Ben Dodson920dbbb2010-08-04 15:21:06 -07002182 if (mIsAbstract != cl.mIsAbstract) {
2183 consistent = false;
2184 Errors.error(Errors.CHANGED_ABSTRACT, cl.position(), "Class " + cl.qualifiedName()
2185 + " changed abstract qualifier");
2186 }
2187
Jeff Brown43d2ac82013-04-01 13:40:01 -07002188 if (!mIsFinal && cl.mIsFinal) {
2189 /*
2190 * It is safe to make a class final if it did not previously have any public
2191 * constructors because it was impossible for an application to create a subclass.
2192 */
2193 if (mApiCheckConstructors.isEmpty()) {
2194 consistent = false;
2195 Errors.error(Errors.ADDED_FINAL_UNINSTANTIABLE, cl.position(),
2196 "Class " + cl.qualifiedName() + " added final qualifier but "
2197 + "was previously uninstantiable and therefore could not be subclassed");
2198 } else {
2199 consistent = false;
2200 Errors.error(Errors.ADDED_FINAL, cl.position(), "Class " + cl.qualifiedName()
2201 + " added final qualifier");
2202 }
2203 } else if (mIsFinal && !cl.mIsFinal) {
Ben Dodson920dbbb2010-08-04 15:21:06 -07002204 consistent = false;
Jeff Brown43d2ac82013-04-01 13:40:01 -07002205 Errors.error(Errors.REMOVED_FINAL, cl.position(), "Class " + cl.qualifiedName()
2206 + " removed final qualifier");
Ben Dodson920dbbb2010-08-04 15:21:06 -07002207 }
2208
2209 if (mIsStatic != cl.mIsStatic) {
2210 consistent = false;
2211 Errors.error(Errors.CHANGED_STATIC, cl.position(), "Class " + cl.qualifiedName()
2212 + " changed static qualifier");
2213 }
2214
2215 if (!scope().equals(cl.scope())) {
2216 consistent = false;
2217 Errors.error(Errors.CHANGED_SCOPE, cl.position(), "Class " + cl.qualifiedName()
2218 + " scope changed from " + scope() + " to " + cl.scope());
2219 }
2220
2221 if (!isDeprecated() == cl.isDeprecated()) {
2222 consistent = false;
2223 Errors.error(Errors.CHANGED_DEPRECATED, cl.position(), "Class " + cl.qualifiedName()
C. Sean Younga7e5c7e2015-05-08 15:35:06 -05002224 + " has changed deprecation state " + isDeprecated() + " --> " + cl.isDeprecated());
Ben Dodson920dbbb2010-08-04 15:21:06 -07002225 }
2226
Mathieuffecf3c2013-06-05 20:35:37 -05002227 if (superclassName() != null) { // java.lang.Object can't have a superclass.
Mathieu11b17962013-06-07 17:24:18 -05002228 if (!cl.extendsClass(superclassName())) {
Ben Dodson920dbbb2010-08-04 15:21:06 -07002229 consistent = false;
2230 Errors.error(Errors.CHANGED_SUPERCLASS, cl.position(), "Class " + qualifiedName()
2231 + " superclass changed from " + superclassName() + " to " + cl.superclassName());
2232 }
Ben Dodson920dbbb2010-08-04 15:21:06 -07002233 }
2234
2235 return consistent;
2236 }
Dirk Dougherty9b316c82013-01-28 10:53:33 -08002237
Hui Shu5118ffe2014-02-18 14:06:42 -08002238 // Find a superclass implementation of the given method based on the methods in mApiCheckMethods.
Ben Dodson920dbbb2010-08-04 15:21:06 -07002239 public static MethodInfo overriddenMethod(MethodInfo candidate, ClassInfo newClassObj) {
2240 if (newClassObj == null) {
2241 return null;
2242 }
2243 for (MethodInfo mi : newClassObj.mApiCheckMethods.values()) {
2244 if (mi.matches(candidate)) {
2245 // found it
2246 return mi;
2247 }
2248 }
2249
2250 // not found here. recursively search ancestors
2251 return ClassInfo.overriddenMethod(candidate, newClassObj.mSuperclass);
2252 }
2253
2254 // Find a superinterface declaration of the given method.
2255 public static MethodInfo interfaceMethod(MethodInfo candidate, ClassInfo newClassObj) {
2256 if (newClassObj == null) {
2257 return null;
2258 }
2259 for (ClassInfo interfaceInfo : newClassObj.interfaces()) {
2260 for (MethodInfo mi : interfaceInfo.mApiCheckMethods.values()) {
2261 if (mi.matches(candidate)) {
2262 return mi;
2263 }
2264 }
2265 }
2266 return ClassInfo.interfaceMethod(candidate, newClassObj.mSuperclass);
2267 }
Dirk Dougherty9b316c82013-01-28 10:53:33 -08002268
Ben Dodson920dbbb2010-08-04 15:21:06 -07002269 public boolean hasConstructor(MethodInfo constructor) {
2270 String name = constructor.getHashableName();
Joe Onorato04099252011-03-09 13:34:18 -08002271 for (MethodInfo ctor : mApiCheckConstructors.values()) {
Ben Dodson920dbbb2010-08-04 15:21:06 -07002272 if (name.equals(ctor.getHashableName())) {
2273 return true;
2274 }
2275 }
2276 return false;
2277 }
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -07002278
Ben Dodson920dbbb2010-08-04 15:21:06 -07002279 public void setTypeInfo(TypeInfo typeInfo) {
2280 mTypeInfo = typeInfo;
2281 }
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -07002282
2283 public TypeInfo type() {
2284 return mTypeInfo;
2285 }
2286
2287 public void addInnerClass(ClassInfo innerClass) {
2288 if (mInnerClasses == null) {
2289 mInnerClasses = new ArrayList<ClassInfo>();
2290 }
2291
2292 mInnerClasses.add(innerClass);
2293 }
2294
2295 public void setContainingClass(ClassInfo containingClass) {
2296 mContainingClass = containingClass;
2297 }
2298
2299 public void setSuperclassType(TypeInfo superclassType) {
2300 mRealSuperclassType = superclassType;
2301 }
2302
2303 public void printResolutions() {
Andrew Sapperstein6ba612e2011-06-20 18:41:24 -07002304 if (mResolutions == null || mResolutions.isEmpty()) {
2305 return;
2306 }
2307
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -07002308 System.out.println("Resolutions for Class " + mName + ":");
2309
Andrew Sapperstein6ba612e2011-06-20 18:41:24 -07002310 for (Resolution r : mResolutions) {
2311 System.out.println(r);
2312 }
2313 }
2314
2315 public void addResolution(Resolution resolution) {
2316 if (mResolutions == null) {
2317 mResolutions = new ArrayList<Resolution>();
2318 }
2319
2320 mResolutions.add(resolution);
2321 }
2322
2323 public boolean resolveResolutions() {
2324 ArrayList<Resolution> resolutions = mResolutions;
2325 mResolutions = new ArrayList<Resolution>();
2326
2327 boolean allResolved = true;
2328 for (Resolution resolution : resolutions) {
2329 StringBuilder qualifiedClassName = new StringBuilder();
2330 InfoBuilder.resolveQualifiedName(resolution.getValue(), qualifiedClassName,
2331 resolution.getInfoBuilder());
2332
2333 // if we still couldn't resolve it, save it for the next pass
2334 if ("".equals(qualifiedClassName.toString())) {
2335 mResolutions.add(resolution);
2336 allResolved = false;
2337 } else if ("superclassQualifiedName".equals(resolution.getVariable())) {
2338 setSuperClass(InfoBuilder.Caches.obtainClass(qualifiedClassName.toString()));
2339 } else if ("interfaceQualifiedName".equals(resolution.getVariable())) {
2340 addInterface(InfoBuilder.Caches.obtainClass(qualifiedClassName.toString()));
2341 }
2342 }
2343
2344 return allResolved;
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -07002345 }
Ben Dodson920dbbb2010-08-04 15:21:06 -07002346}