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 } 139 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)140 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) { 147 mTypeInfo = typeInfo; 148 mRealInterfaces = new ArrayList<ClassInfo>(interfaces); 149 mRealInterfaceTypes = interfaceTypes; 150 mInnerClasses = innerClasses; 151 // mAllConstructors will not contain *all* constructors. Only the constructors that pass 152 // checkLevel. @see {@link Converter#convertMethods(ConstructorDoc[])} 153 mAllConstructors = constructors; 154 // mAllSelfMethods will not contain *all* self methods. Only the methods that pass 155 // checkLevel. @see {@link Converter#convertMethods(MethodDoc[])} 156 mAllSelfMethods = methods; 157 mAnnotationElements = annotationElements; 158 // mAllSelfFields will not contain *all* self fields. Only the fields that pass 159 // checkLevel. @see {@link Converter#convetFields(FieldDoc[])} 160 mAllSelfFields = fields; 161 // mEnumConstants will not contain *all* enum constants. Only the enums that pass 162 // checkLevel. @see {@link Converter#convetFields(FieldDoc[])} 163 mEnumConstants = enumConstants; 164 mContainingPackage = containingPackage; 165 mContainingClass = containingClass; 166 mRealSuperclass = superclass; 167 mRealSuperclassType = superclassType; 168 mAnnotations = annotations; 169 mShowAnnotations = AnnotationInstanceInfo.getShowAnnotationsIntersection(annotations); 170 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; 181 mSuperclassesWithTypes = null; 182 mInterfacesWithTypes = null; 183 mAllInterfacesWithTypes = null; 184 185 Collections.sort(mEnumConstants, FieldInfo.comparator); 186 Collections.sort(mInnerClasses, ClassInfo.comparator); 187 } 188 init2()189 public void init2() { 190 // calling this here forces the AttrTagInfo objects to be linked to the AttribtueInfo 191 // objects 192 selfAttributes(); 193 } 194 init3(ArrayList<TypeInfo> types, ArrayList<ClassInfo> realInnerClasses)195 public void init3(ArrayList<TypeInfo> types, ArrayList<ClassInfo> realInnerClasses) { 196 mTypeParameters = types; 197 mRealInnerClasses = realInnerClasses; 198 } 199 getRealInnerClasses()200 public ArrayList<ClassInfo> getRealInnerClasses() { 201 return mRealInnerClasses; 202 } 203 getTypeParameters()204 public ArrayList<TypeInfo> getTypeParameters() { 205 return mTypeParameters; 206 } 207 208 /** 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 */ checkLevel()212 public boolean checkLevel() { 213 if (mCheckLevel == null) { 214 mCheckLevel = Doclava.checkLevel(mIsPublic, mIsProtected, mIsPackagePrivate, mIsPrivate, 215 isHiddenOrRemoved()); 216 } 217 218 return mCheckLevel; 219 } 220 compareTo(Object that)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 parent()230 public ContainerInfo parent() { 231 return this; 232 } 233 isPublic()234 public boolean isPublic() { 235 return mIsPublic; 236 } 237 isProtected()238 public boolean isProtected() { 239 return mIsProtected; 240 } 241 isPackagePrivate()242 public boolean isPackagePrivate() { 243 return mIsPackagePrivate; 244 } 245 isPrivate()246 public boolean isPrivate() { 247 return mIsPrivate; 248 } 249 isStatic()250 public boolean isStatic() { 251 return mIsStatic; 252 } 253 isInterface()254 public boolean isInterface() { 255 return mIsInterface; 256 } 257 isAbstract()258 public boolean isAbstract() { 259 return mIsAbstract; 260 } 261 containingPackage()262 public PackageInfo containingPackage() { 263 return mContainingPackage; 264 } 265 containingClass()266 public ClassInfo containingClass() { 267 return mContainingClass; 268 } 269 isOrdinaryClass()270 public boolean isOrdinaryClass() { 271 return mIsOrdinaryClass; 272 } 273 isException()274 public boolean isException() { 275 return mIsException; 276 } 277 isError()278 public boolean isError() { 279 return mIsError; 280 } 281 isEnum()282 public boolean isEnum() { 283 return mIsEnum; 284 } 285 isAnnotation()286 public boolean isAnnotation() { 287 return mIsAnnotation; 288 } 289 isFinal()290 public boolean isFinal() { 291 return mIsFinal; 292 } 293 isEffectivelyFinal()294 public boolean isEffectivelyFinal() { 295 return mIsFinal || mApiCheckConstructors.isEmpty(); 296 } 297 isIncluded()298 public boolean isIncluded() { 299 return mIsIncluded; 300 } 301 typeVariables()302 public HashSet<String> typeVariables() { 303 HashSet<String> result = TypeInfo.typeVariables(mTypeInfo.typeArguments()); 304 ClassInfo cl = containingClass(); 305 while (cl != null) { 306 ArrayList<TypeInfo> types = cl.asTypeInfo().typeArguments(); 307 if (types != null) { 308 TypeInfo.typeVariables(types, result); 309 } 310 cl = cl.containingClass(); 311 } 312 return result; 313 } 314 315 /** 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 */ justMyInterfacesWithTypes()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 */ justMyInterfacesWithTypes(Map<String, TypeInfo> typeArgumentsMap)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 */ interfacesWithTypes()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 */ allInterfacesWithTypes()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 * */ superClassesWithTypes()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 gatherHiddenInterfaces(ClassInfo cl, HashSet<ClassInfo> interfaces)439 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 interfaces()449 public ArrayList<ClassInfo> interfaces() { 450 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); 459 mInterfaces = new ArrayList<ClassInfo>(interfaces); 460 } else { 461 // put something here in case someone uses it 462 mInterfaces = new ArrayList<ClassInfo>(mRealInterfaces); 463 } 464 Collections.sort(mInterfaces, ClassInfo.qualifiedComparator); 465 } 466 return mInterfaces; 467 } 468 realInterfaces()469 public ArrayList<ClassInfo> realInterfaces() { 470 return mRealInterfaces; 471 } 472 realInterfaceTypes()473 ArrayList<TypeInfo> realInterfaceTypes() { 474 return mRealInterfaceTypes; 475 } 476 addInterfaceType(TypeInfo type)477 public void addInterfaceType(TypeInfo type) { 478 if (mRealInterfaceTypes == null) { 479 mRealInterfaceTypes = new ArrayList<TypeInfo>(); 480 } 481 482 mRealInterfaceTypes.add(type); 483 } 484 name()485 public String name() { 486 return mName; 487 } 488 nameParts()489 public String[] nameParts() { 490 return mNameParts; 491 } 492 leafName()493 public String leafName() { 494 return mNameParts[mNameParts.length - 1]; 495 } 496 qualifiedName()497 public String qualifiedName() { 498 return mQualifiedName; 499 } 500 qualifiedTypeName()501 public String qualifiedTypeName() { 502 return mQualifiedTypeName; 503 } 504 isPrimitive()505 public boolean isPrimitive() { 506 return mIsPrimitive; 507 } 508 allConstructors()509 public ArrayList<MethodInfo> allConstructors() { 510 return mAllConstructors; 511 } 512 constructors()513 public ArrayList<MethodInfo> constructors() { 514 if (mConstructors == null) { 515 if (mAllConstructors == null) { 516 return new ArrayList<MethodInfo>(); 517 } 518 519 mConstructors = new ArrayList<MethodInfo>(); 520 for (MethodInfo m : mAllConstructors) { 521 if (!m.isHiddenOrRemoved()) { 522 mConstructors.add(m); 523 } 524 } 525 526 Collections.sort(mConstructors, MethodInfo.comparator); 527 } 528 return mConstructors; 529 } 530 innerClasses()531 public ArrayList<ClassInfo> innerClasses() { 532 return mInnerClasses; 533 } 534 inlineTags()535 public TagInfo[] inlineTags() { 536 return comment().tags(); 537 } 538 firstSentenceTags()539 public TagInfo[] firstSentenceTags() { 540 return comment().briefTags(); 541 } 542 setDeprecated(boolean deprecated)543 public void setDeprecated(boolean deprecated) { 544 mDeprecatedKnown = true; 545 mIsDeprecated = deprecated; 546 } 547 isDeprecated()548 public boolean isDeprecated() { 549 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 deprecatedTags()570 public TagInfo[] deprecatedTags() { 571 // Should we also do the interfaces? 572 return comment().deprecatedTags(); 573 } 574 methods()575 public ArrayList<MethodInfo> methods() { 576 if (mMethods == null) { 577 TreeMap<String, MethodInfo> all = new TreeMap<String, MethodInfo>(); 578 579 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 } 586 } 587 588 ClassInfo superclass = superclass(); 589 if (superclass != null) { 590 for (MethodInfo method : superclass.methods()) { 591 all.put(method.getHashableName(), method); 592 } 593 } 594 595 for (MethodInfo method : selfMethods()) { 596 all.put(method.getHashableName(), method); 597 } 598 599 mMethods = new ArrayList<MethodInfo>(all.values()); 600 Collections.sort(mMethods, MethodInfo.comparator); 601 } 602 return mMethods; 603 } 604 annotationElements()605 public ArrayList<MethodInfo> annotationElements() { 606 return mAnnotationElements; 607 } 608 annotations()609 public ArrayList<AnnotationInstanceInfo> annotations() { 610 return mAnnotations; 611 } 612 addFields(ClassInfo cl, TreeMap<String, FieldInfo> all)613 private static void addFields(ClassInfo cl, TreeMap<String, FieldInfo> all) { 614 for (FieldInfo field : cl.fields()) { 615 all.put(field.name(), field); 616 } 617 } 618 fields()619 public ArrayList<FieldInfo> fields() { 620 if (mFields == null) { 621 TreeMap<String, FieldInfo> all = new TreeMap<String, FieldInfo>(); 622 623 for (ClassInfo iface : interfaces()) { 624 addFields(iface, all); 625 } 626 627 ClassInfo superclass = superclass(); 628 if (superclass != null) { 629 addFields(superclass, all); 630 } 631 632 for (FieldInfo field : selfFields()) { 633 if (!field.isHiddenOrRemoved()) { 634 all.put(field.name(), field); 635 } 636 } 637 638 for (FieldInfo enumConst : mEnumConstants) { 639 if (!enumConst.isHiddenOrRemoved()) { 640 all.put(enumConst.name(), enumConst); 641 } 642 } 643 644 mFields = new ArrayList<FieldInfo>(all.values()); 645 } 646 return mFields; 647 } 648 gatherFields(ClassInfo owner, ClassInfo cl, HashMap<String, FieldInfo> fields)649 public void gatherFields(ClassInfo owner, ClassInfo cl, HashMap<String, FieldInfo> fields) { 650 for (FieldInfo f : cl.selfFields()) { 651 if (f.checkLevel()) { 652 fields.put(f.name(), f.cloneForClass(owner)); 653 } 654 } 655 } 656 selfFields()657 public ArrayList<FieldInfo> selfFields() { 658 if (mSelfFields == null) { 659 HashMap<String, FieldInfo> fields = new HashMap<String, FieldInfo>(); 660 // 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 } 669 670 for (FieldInfo f : mAllSelfFields) { 671 if (!f.isHiddenOrRemoved()) { 672 fields.put(f.name(), f); 673 } 674 } 675 676 mSelfFields = new ArrayList<FieldInfo>(fields.values()); 677 Collections.sort(mSelfFields, FieldInfo.comparator); 678 } 679 return mSelfFields; 680 } 681 allSelfFields()682 public ArrayList<FieldInfo> allSelfFields() { 683 return mAllSelfFields; 684 } 685 gatherMethods(ClassInfo owner, ClassTypePair ctp, HashMap<String, MethodInfo> methods)686 private void gatherMethods(ClassInfo owner, ClassTypePair ctp, HashMap<String, MethodInfo> methods) { 687 for (MethodInfo m : ctp.classInfo().selfMethods()) { 688 if (m.checkLevel()) { 689 methods.put(m.name() + m.signature(), m.cloneForClass(owner, ctp.getTypeArgumentMapping())); 690 } 691 } 692 } 693 selfMethods()694 public ArrayList<MethodInfo> selfMethods() { 695 if (mSelfMethods == null) { 696 HashMap<String, MethodInfo> methods = new HashMap<String, MethodInfo>(); 697 // our hidden parents 698 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 } 706 } 707 for (ClassTypePair ctp : justMyInterfacesWithTypes(Collections.<String, TypeInfo>emptyMap())) { 708 if (!ctp.classInfo().checkLevel()) { 709 gatherMethods(this, ctp, methods); 710 } 711 } 712 // mine 713 if (mAllSelfMethods != null) { 714 for (MethodInfo m : mAllSelfMethods) { 715 if (m.checkLevel()) { 716 methods.put(m.name() + m.signature(), m); 717 } 718 } 719 } 720 721 // sort it 722 mSelfMethods = new ArrayList<MethodInfo>(methods.values()); 723 Collections.sort(mSelfMethods, MethodInfo.comparator); 724 } 725 return mSelfMethods; 726 } 727 allSelfMethods()728 public ArrayList<MethodInfo> allSelfMethods() { 729 return mAllSelfMethods; 730 } 731 732 /** 733 * @param removedMethods the removed methods regardless of access levels. 734 */ setRemovedMethods(List<MethodInfo> removedMethods)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 */ setRemovedSelfMethods(List<MethodInfo> allMethods)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 */ setRemovedConstructors(List<MethodInfo> allCtors)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 */ setRemovedSelfFields(List<FieldInfo> allFields)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 */ setRemovedEnumConstants(List<FieldInfo> allEnumConstants)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 */ getRemovedMethods()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 */ getRemovedSelfMethods()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 */ getRemovedConstructors()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 */ getRemovedSelfFields()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 */ getRemovedSelfEnumConstants()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 */ hasRemovedSelfMembers()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 addMethod(MethodInfo method)876 public void addMethod(MethodInfo method) { 877 mApiCheckMethods.put(method.getHashableName(), method); 878 879 mAllSelfMethods.add(method); 880 mSelfMethods = null; // flush this, hopefully it hasn't been used yet. 881 } 882 addAnnotationElement(MethodInfo method)883 public void addAnnotationElement(MethodInfo method) { 884 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. setPackage(PackageInfo pkg)891 void setPackage(PackageInfo pkg) { 892 mContainingPackage = pkg; 893 } 894 setContainingPackage(PackageInfo pkg)895 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 selfAttributes()909 public ArrayList<AttributeInfo> selfAttributes() { 910 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 958 mSelfAttributes = new ArrayList<AttributeInfo>(attrs.values()); 959 Collections.sort(mSelfAttributes, AttributeInfo.comparator); 960 } 961 return mSelfAttributes; 962 } 963 enumConstants()964 public ArrayList<FieldInfo> enumConstants() { 965 return mEnumConstants; 966 } 967 superclass()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 realSuperclass()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 */ superclassType()993 public TypeInfo superclassType() { 994 return mRealSuperclassType; 995 } 996 asTypeInfo()997 public TypeInfo asTypeInfo() { 998 return mTypeInfo; 999 } 1000 interfaceTypes()1001 ArrayList<TypeInfo> interfaceTypes() { 1002 ArrayList<TypeInfo> types = new ArrayList<TypeInfo>(); 1003 for (ClassInfo iface : interfaces()) { 1004 types.add(iface.asTypeInfo()); 1005 } 1006 return types; 1007 } 1008 htmlPage()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 */ isDerivedFrom(ClassInfo cl)1020 public boolean isDerivedFrom(ClassInfo cl) { 1021 return isDerivedFrom(cl.qualifiedName()); 1022 } 1023 1024 /** Even indirectly */ isDerivedFrom(String qualifiedName)1025 public boolean isDerivedFrom(String qualifiedName) { 1026 ClassInfo dad = this.superclass(); 1027 if (dad != null) { 1028 if (dad.mQualifiedName.equals(qualifiedName)) { 1029 return true; 1030 } else { 1031 if (dad.isDerivedFrom(qualifiedName)) { 1032 return true; 1033 } 1034 } 1035 } 1036 for (ClassInfo iface : interfaces()) { 1037 if (iface.mQualifiedName.equals(qualifiedName)) { 1038 return true; 1039 } else { 1040 if (iface.isDerivedFrom(qualifiedName)) { 1041 return true; 1042 } 1043 } 1044 } 1045 return false; 1046 } 1047 makeKeywordEntries(List<KeywordEntry> keywords)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 1058 ArrayList<FieldInfo> fields = selfFields(); 1059 //ArrayList<FieldInfo> enumConstants = enumConstants(); 1060 ArrayList<MethodInfo> ctors = constructors(); 1061 ArrayList<MethodInfo> methods = selfMethods(); 1062 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 makeLink(Data data, String base)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 makeLinkListHDF(Data data, String base, ClassInfo[] classes)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 */ makeShortDescrHDF(Data data, String base)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()); 1190 if (isDeprecated()) { 1191 data.setValue(base + ".deprecatedsince", getDeprecatedSince()); 1192 } 1193 1194 ArrayList<AnnotationInstanceInfo> showAnnos = getShowAnnotationsIncludeOuters(); 1195 AnnotationInstanceInfo.makeLinkListHDF( 1196 data, 1197 base + ".showAnnotations", 1198 showAnnos.toArray(new AnnotationInstanceInfo[showAnnos.size()])); 1199 1200 setFederatedReferences(data, base); 1201 } 1202 1203 /** 1204 * Turns into the main class page 1205 */ makeHDF(Data data)1206 public void makeHDF(Data data) { 1207 int i, j, n; 1208 String name = name(); 1209 String qualified = qualifiedName(); 1210 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(); 1216 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); 1222 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 1237 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 1248 ArrayList<AnnotationInstanceInfo> showAnnos = getShowAnnotationsIncludeOuters(); 1249 AnnotationInstanceInfo.makeLinkListHDF( 1250 data, 1251 "class.showAnnotations", 1252 showAnnos.toArray(new AnnotationInstanceInfo[showAnnos.size()])); 1253 1254 // class info 1255 String kind = kind(); 1256 if (kind != null) { 1257 data.setValue("class.kind", kind); 1258 } 1259 data.setValue("class.since", getSince()); 1260 if (isDeprecated()) { 1261 data.setValue("class.deprecatedsince", getDeprecatedSince()); 1262 } 1263 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 1270 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 } 1283 } 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) { 1338 field.makeHDF(data, "class.enumConstants." + i); 1339 i++; 1340 } 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 1454 Iterator<ClassTypePair> superclassesItr = superClassesWithTypes().iterator(); 1455 superclassesItr.next(); // skip the first one, which is the current class 1456 ClassTypePair superCtp; 1457 i = 0; 1458 while (superclassesItr.hasNext()) { 1459 superCtp = superclassesItr.next(); 1460 if (superCtp.classInfo().checkLevel()) { 1461 makeInheritedHDF(data, i, superCtp); 1462 i++; 1463 } 1464 } 1465 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 } 1472 } 1473 } 1474 makeInheritedHDF(Data data, int index, ClassTypePair ctp)1475 private static void makeInheritedHDF(Data data, int index, ClassTypePair ctp) { 1476 int i; 1477 1478 String base = "class.inherited." + index; 1479 data.setValue(base + ".qualified", ctp.classInfo().qualifiedName()); 1480 if (ctp.classInfo().checkLevel()) { 1481 data.setValue(base + ".link", ctp.classInfo().htmlPage()); 1482 } 1483 String kind = ctp.classInfo().kind(); 1484 if (kind != null) { 1485 data.setValue(base + ".kind", kind); 1486 } 1487 1488 if (ctp.classInfo().mIsIncluded) { 1489 data.setValue(base + ".included", "true"); 1490 } else { 1491 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())); 1495 data.setValue(base + ".federated", site.name()); 1496 } 1497 } 1498 1499 // xml attributes 1500 i = 0; 1501 for (AttributeInfo attr : ctp.classInfo().selfAttributes()) { 1502 attr.makeHDF(data, base + ".attrs." + i); 1503 i++; 1504 } 1505 1506 // methods 1507 i = 0; 1508 for (MethodInfo method : ctp.classInfo().selfMethods()) { 1509 method.makeHDF(data, base + ".methods." + i, ctp.getTypeArgumentMapping()); 1510 i++; 1511 } 1512 1513 // fields 1514 i = 0; 1515 for (FieldInfo field : ctp.classInfo().selfFields()) { 1516 if (!field.isConstant()) { 1517 field.makeHDF(data, base + ".fields." + i); 1518 i++; 1519 } 1520 } 1521 1522 // constants 1523 i = 0; 1524 for (FieldInfo field : ctp.classInfo().selfFields()) { 1525 if (field.isConstant()) { 1526 field.makeHDF(data, base + ".constants." + i); 1527 i++; 1528 } 1529 } 1530 } 1531 1532 @Override isHidden()1533 public boolean isHidden() { 1534 if (mHidden == null) { 1535 mHidden = isHiddenImpl(); 1536 } 1537 1538 return mHidden; 1539 } 1540 1541 /** 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 */ isHiddenImpl()1545 public boolean isHiddenImpl() { 1546 ClassInfo cl = this; 1547 while (cl != null) { 1548 if (cl.hasShowAnnotation()) { 1549 return false; 1550 } 1551 PackageInfo pkg = cl.containingPackage(); 1552 if (pkg != null && pkg.hasHideComment()) { 1553 return true; 1554 } 1555 if (cl.comment().isHidden()) { 1556 return true; 1557 } 1558 cl = cl.containingClass(); 1559 } 1560 return false; 1561 } 1562 1563 @Override isRemoved()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 */ isRemovedImpl()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 isHiddenOrRemoved()1595 public boolean isHiddenOrRemoved() { 1596 return isHidden() || isRemoved(); 1597 } 1598 hasShowAnnotation()1599 public boolean hasShowAnnotation() { 1600 return mShowAnnotations != null && mShowAnnotations.size() > 0; 1601 } 1602 showAnnotations()1603 public ArrayList<AnnotationInstanceInfo> showAnnotations() { 1604 return mShowAnnotations; 1605 } 1606 getShowAnnotationsIncludeOuters()1607 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 matchMethod(ArrayList<MethodInfo> methods, String name, String[] params, String[] dimensions, boolean varargs)1631 private MethodInfo matchMethod(ArrayList<MethodInfo> methods, String name, String[] params, 1632 String[] dimensions, boolean varargs) { 1633 for (MethodInfo method : methods) { 1634 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 findMethod(String name, String[] params, String[] dimensions, boolean varargs)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 } 1672 supportsMethod(MethodInfo method)1673 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 searchInnerClasses(String[] nameParts, int index)1682 private ClassInfo searchInnerClasses(String[] nameParts, int index) { 1683 String part = nameParts[index]; 1684 1685 ArrayList<ClassInfo> inners = mInnerClasses; 1686 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 extendedFindClass(String className)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 findClass(String className)1706 public ClassInfo findClass(String className) { 1707 return Converter.obtainClass(mClass.findClass(className)); 1708 } 1709 findInnerClass(String className)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; 1717 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 1729 cl = cl.findClass(n); 1730 if (cl == null) { 1731 return null; 1732 } 1733 } 1734 1735 return Converter.obtainClass(cl); 1736 } 1737 findField(String name)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 sortByName(ClassInfo[] classes)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 equals(ClassInfo that)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 setNonWrittenConstructors(ArrayList<MethodInfo> nonWritten)1789 public void setNonWrittenConstructors(ArrayList<MethodInfo> nonWritten) { 1790 mNonWrittenConstructors = nonWritten; 1791 } 1792 getNonWrittenConstructors()1793 public ArrayList<MethodInfo> getNonWrittenConstructors() { 1794 return mNonWrittenConstructors; 1795 } 1796 kind()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 } 1813 scope()1814 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 setHiddenMethods(ArrayList<MethodInfo> mInfo)1828 public void setHiddenMethods(ArrayList<MethodInfo> mInfo) { 1829 mHiddenMethods = mInfo; 1830 } 1831 getHiddenMethods()1832 public ArrayList<MethodInfo> getHiddenMethods() { 1833 return mHiddenMethods; 1834 } 1835 1836 @Override toString()1837 public String toString() { 1838 return this.qualifiedName(); 1839 } 1840 setReasonIncluded(String reason)1841 public void setReasonIncluded(String reason) { 1842 mReasonIncluded = reason; 1843 } 1844 getReasonIncluded()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 1874 private ArrayList<ClassInfo> mRealInterfaces = new ArrayList<ClassInfo>(); 1875 private ArrayList<ClassInfo> mInterfaces; 1876 private ArrayList<TypeInfo> mRealInterfaceTypes; 1877 private ArrayList<ClassInfo> mInnerClasses; 1878 // mAllConstructors will not contain *all* constructors. Only the constructors that pass 1879 // checkLevel. @see {@link Converter#convertMethods(ConstructorDoc[])} 1880 private ArrayList<MethodInfo> mAllConstructors = new ArrayList<MethodInfo>(); 1881 // mAllSelfMethods will not contain *all* self methods. Only the methods that pass 1882 // checkLevel. @see {@link Converter#convertMethods(MethodDoc[])} 1883 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>(); 1887 private PackageInfo mContainingPackage; 1888 private ClassInfo mContainingClass; 1889 private ClassInfo mRealSuperclass; 1890 private TypeInfo mRealSuperclassType; 1891 private ClassInfo mSuperclass; 1892 private ArrayList<AnnotationInstanceInfo> mAnnotations; 1893 private ArrayList<AnnotationInstanceInfo> mShowAnnotations; 1894 private boolean mSuperclassInit; 1895 private boolean mDeprecatedKnown; 1896 1897 // lazy 1898 private ArrayList<ClassTypePair> mSuperclassesWithTypes; 1899 private ArrayList<ClassTypePair> mInterfacesWithTypes; 1900 private ArrayList<ClassTypePair> mAllInterfacesWithTypes; 1901 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; 1910 private Boolean mHidden = null; 1911 private Boolean mRemoved = null; 1912 private Boolean mCheckLevel = null; 1913 private String mReasonIncluded; 1914 private ArrayList<MethodInfo> mNonWrittenConstructors; 1915 private boolean mIsDeprecated; 1916 1917 // TODO: Temporary members from apicheck migration. 1918 private HashMap<String, MethodInfo> mApiCheckConstructors = new HashMap<String, MethodInfo>(); 1919 private HashMap<String, MethodInfo> mApiCheckMethods = new HashMap<String, MethodInfo>(); 1920 private HashMap<String, FieldInfo> mApiCheckFields = new HashMap<String, FieldInfo>(); 1921 private HashMap<String, FieldInfo> mApiCheckEnumConstants = new HashMap<String, FieldInfo>(); 1922 1923 // Resolutions 1924 private ArrayList<Resolution> mResolutions; 1925 1926 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 1933 /** 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 */ implementsInterface(String iface)1937 public boolean implementsInterface(String iface) { 1938 if (qualifiedName().equals(iface)) { 1939 return true; 1940 } 1941 for (ClassInfo clImplements : realInterfaces()) { 1942 if (clImplements.implementsInterface(iface)) { 1943 return true; 1944 } 1945 } 1946 if (mSuperclass != null && mSuperclass.implementsInterface(iface)) { 1947 return true; 1948 } 1949 return false; 1950 } 1951 1952 /** 1953 * Returns true if {@code this} extends the class {@code ext}. 1954 */ extendsClass(String cl)1955 public boolean extendsClass(String cl) { 1956 if (qualifiedName().equals(cl)) { 1957 return true; 1958 } 1959 if (mSuperclass != null && mSuperclass.extendsClass(cl)) { 1960 return true; 1961 } 1962 return false; 1963 } 1964 1965 /** 1966 * Returns true if {@code this} is assignable to cl 1967 */ isAssignableTo(String cl)1968 public boolean isAssignableTo(String cl) { 1969 return implementsInterface(cl) || extendsClass(cl); 1970 } 1971 addInterface(ClassInfo iface)1972 public void addInterface(ClassInfo iface) { 1973 mRealInterfaces.add(iface); 1974 } 1975 addConstructor(MethodInfo ctor)1976 public void addConstructor(MethodInfo ctor) { 1977 mApiCheckConstructors.put(ctor.getHashableName(), ctor); 1978 1979 mAllConstructors.add(ctor); 1980 mConstructors = null; // flush this, hopefully it hasn't been used yet. 1981 } 1982 addField(FieldInfo field)1983 public void addField(FieldInfo field) { 1984 mApiCheckFields.put(field.name(), field); 1985 1986 mAllSelfFields.add(field); 1987 1988 mSelfFields = null; // flush this, hopefully it hasn't been used yet. 1989 } 1990 addEnumConstant(FieldInfo field)1991 public void addEnumConstant(FieldInfo field) { 1992 mApiCheckEnumConstants.put(field.name(), field); 1993 1994 mEnumConstants.add(field); 1995 } 1996 setSuperClass(ClassInfo superclass)1997 public void setSuperClass(ClassInfo superclass) { 1998 mRealSuperclass = superclass; 1999 mSuperclass = superclass; 2000 } 2001 allConstructorsMap()2002 public Map<String, MethodInfo> allConstructorsMap() { 2003 return mApiCheckConstructors; 2004 } 2005 allFields()2006 public Map<String, FieldInfo> allFields() { 2007 return mApiCheckFields; 2008 } 2009 allEnums()2010 public Map<String, FieldInfo> allEnums() { 2011 return mApiCheckEnumConstants; 2012 } 2013 2014 /** 2015 * Returns all methods defined directly in this class. For a list of all 2016 * methods supported by this class, see {@link #methods()}. 2017 */ allMethods()2018 public Map<String, MethodInfo> allMethods() { 2019 return mApiCheckMethods; 2020 } 2021 2022 /** 2023 * Returns the class hierarchy for this class, starting with this class. 2024 */ hierarchy()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 } 2032 superclassName()2033 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 } 2042 setAnnotations(ArrayList<AnnotationInstanceInfo> annotations)2043 public void setAnnotations(ArrayList<AnnotationInstanceInfo> annotations) { 2044 mAnnotations = annotations; 2045 } 2046 isConsistent(ClassInfo cl)2047 public boolean isConsistent(ClassInfo cl) { 2048 return isConsistent(cl, null, null); 2049 } 2050 isConsistent(ClassInfo cl, List<MethodInfo> newCtors, List<MethodInfo> newMethods)2051 public boolean isConsistent(ClassInfo cl, List<MethodInfo> newCtors, List<MethodInfo> newMethods) { 2052 boolean consistent = true; 2053 boolean diffMode = (newCtors != null) && (newMethods != null); 2054 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) { 2061 if (!cl.implementsInterface(iface.mQualifiedName)) { 2062 Errors.error(Errors.REMOVED_INTERFACE, cl.position(), "Class " + qualifiedName() 2063 + " no longer implements " + iface); 2064 } 2065 } 2066 for (ClassInfo iface : cl.mRealInterfaces) { 2067 if (!implementsInterface(iface.mQualifiedName)) { 2068 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 " 2090 + mInfo.prettyQualifiedSignature()); 2091 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. 2100 * 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(). 2102 */ 2103 MethodInfo mi = ClassInfo.overriddenMethod(mInfo, this); 2104 if (mi == null || 2105 mi.isAbstract() != mInfo.isAbstract()) { 2106 Errors.error(Errors.ADDED_METHOD, mInfo.position(), "Added public method " 2107 + mInfo.prettyQualifiedSignature()); 2108 if (diffMode) { 2109 newMethods.add(mInfo); 2110 } 2111 consistent = false; 2112 } 2113 } 2114 } 2115 if (diffMode) { 2116 Collections.sort(newMethods, MethodInfo.comparator); 2117 } 2118 2119 for (MethodInfo mInfo : mApiCheckConstructors.values()) { 2120 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 " 2126 + mInfo.prettyQualifiedSignature()); 2127 consistent = false; 2128 } 2129 } 2130 for (MethodInfo mInfo : cl.mApiCheckConstructors.values()) { 2131 if (!mApiCheckConstructors.containsKey(mInfo.getHashableName())) { 2132 Errors.error(Errors.ADDED_METHOD, mInfo.position(), "Added public constructor " 2133 + mInfo.prettyQualifiedSignature()); 2134 if (diffMode) { 2135 newCtors.add(mInfo); 2136 } 2137 consistent = false; 2138 } 2139 } 2140 if (diffMode) { 2141 Collections.sort(newCtors, MethodInfo.comparator); 2142 } 2143 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 2163 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 2182 if (mIsAbstract != cl.mIsAbstract) { 2183 consistent = false; 2184 Errors.error(Errors.CHANGED_ABSTRACT, cl.position(), "Class " + cl.qualifiedName() 2185 + " changed abstract qualifier"); 2186 } 2187 2188 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) { 2204 consistent = false; 2205 Errors.error(Errors.REMOVED_FINAL, cl.position(), "Class " + cl.qualifiedName() 2206 + " removed final qualifier"); 2207 } 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() 2224 + " has changed deprecation state " + isDeprecated() + " --> " + cl.isDeprecated()); 2225 } 2226 2227 if (superclassName() != null) { // java.lang.Object can't have a superclass. 2228 if (!cl.extendsClass(superclassName())) { 2229 consistent = false; 2230 Errors.error(Errors.CHANGED_SUPERCLASS, cl.position(), "Class " + qualifiedName() 2231 + " superclass changed from " + superclassName() + " to " + cl.superclassName()); 2232 } 2233 } 2234 2235 return consistent; 2236 } 2237 2238 // Find a superclass implementation of the given method based on the methods in mApiCheckMethods. overriddenMethod(MethodInfo candidate, ClassInfo newClassObj)2239 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. interfaceMethod(MethodInfo candidate, ClassInfo newClassObj)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 } 2268 hasConstructor(MethodInfo constructor)2269 public boolean hasConstructor(MethodInfo constructor) { 2270 String name = constructor.getHashableName(); 2271 for (MethodInfo ctor : mApiCheckConstructors.values()) { 2272 if (name.equals(ctor.getHashableName())) { 2273 return true; 2274 } 2275 } 2276 return false; 2277 } 2278 setTypeInfo(TypeInfo typeInfo)2279 public void setTypeInfo(TypeInfo typeInfo) { 2280 mTypeInfo = typeInfo; 2281 } 2282 type()2283 public TypeInfo type() { 2284 return mTypeInfo; 2285 } 2286 addInnerClass(ClassInfo innerClass)2287 public void addInnerClass(ClassInfo innerClass) { 2288 if (mInnerClasses == null) { 2289 mInnerClasses = new ArrayList<ClassInfo>(); 2290 } 2291 2292 mInnerClasses.add(innerClass); 2293 } 2294 setContainingClass(ClassInfo containingClass)2295 public void setContainingClass(ClassInfo containingClass) { 2296 mContainingClass = containingClass; 2297 } 2298 setSuperclassType(TypeInfo superclassType)2299 public void setSuperclassType(TypeInfo superclassType) { 2300 mRealSuperclassType = superclassType; 2301 } 2302 printResolutions()2303 public void printResolutions() { 2304 if (mResolutions == null || mResolutions.isEmpty()) { 2305 return; 2306 } 2307 2308 System.out.println("Resolutions for Class " + mName + ":"); 2309 2310 for (Resolution r : mResolutions) { 2311 System.out.println(r); 2312 } 2313 } 2314 addResolution(Resolution resolution)2315 public void addResolution(Resolution resolution) { 2316 if (mResolutions == null) { 2317 mResolutions = new ArrayList<Resolution>(); 2318 } 2319 2320 mResolutions.add(resolution); 2321 } 2322 resolveResolutions()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; 2345 } 2346 } 2347