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