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 17package com.google.doclava; 18 19import com.google.clearsilver.jsilver.data.Data; 20import com.sun.javadoc.ClassDoc; 21 22import java.util.ArrayDeque; 23import java.util.ArrayList; 24import java.util.Arrays; 25import java.util.Collections; 26import java.util.Comparator; 27import java.util.HashMap; 28import java.util.HashSet; 29import java.util.Iterator; 30import java.util.List; 31import java.util.Map; 32import java.util.Queue; 33import java.util.Set; 34import java.util.TreeMap; 35 36public 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 48 public ClassTypePair(ClassInfo cl, TypeInfo t) { 49 mClassInfo = cl; 50 mTypeInfo = t; 51 } 52 53 public ClassInfo classInfo() { 54 return mClassInfo; 55 } 56 57 public TypeInfo typeInfo() { 58 return mTypeInfo; 59 } 60 61 public Map<String, TypeInfo> getTypeArgumentMapping() { 62 return TypeInfo.getTypeArgumentMapping(classInfo(), typeInfo()); 63 } 64 } 65 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 */ 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 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 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 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 189 public void init2() { 190 // calling this here forces the AttrTagInfo objects to be linked to the AttribtueInfo 191 // objects 192 selfAttributes(); 193 } 194 195 public void init3(ArrayList<TypeInfo> types, ArrayList<ClassInfo> realInnerClasses) { 196 mTypeParameters = types; 197 mRealInnerClasses = realInnerClasses; 198 } 199 200 public ArrayList<ClassInfo> getRealInnerClasses() { 201 return mRealInnerClasses; 202 } 203 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 */ 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 221 public int compareTo(Object that) { 222 if (that instanceof ClassInfo) { 223 return mQualifiedName.compareTo(((ClassInfo) that).mQualifiedName); 224 } else { 225 return this.hashCode() - that.hashCode(); 226 } 227 } 228 229 @Override 230 public ContainerInfo parent() { 231 return this; 232 } 233 234 public boolean isPublic() { 235 return mIsPublic; 236 } 237 238 public boolean isProtected() { 239 return mIsProtected; 240 } 241 242 public boolean isPackagePrivate() { 243 return mIsPackagePrivate; 244 } 245 246 public boolean isPrivate() { 247 return mIsPrivate; 248 } 249 250 public boolean isStatic() { 251 return mIsStatic; 252 } 253 254 public boolean isInterface() { 255 return mIsInterface; 256 } 257 258 public boolean isAbstract() { 259 return mIsAbstract; 260 } 261 262 public PackageInfo containingPackage() { 263 return mContainingPackage; 264 } 265 266 public ClassInfo containingClass() { 267 return mContainingClass; 268 } 269 270 public boolean isOrdinaryClass() { 271 return mIsOrdinaryClass; 272 } 273 274 public boolean isException() { 275 return mIsException; 276 } 277 278 public boolean isError() { 279 return mIsError; 280 } 281 282 public boolean isEnum() { 283 return mIsEnum; 284 } 285 286 public boolean isAnnotation() { 287 return mIsAnnotation; 288 } 289 290 public boolean isFinal() { 291 return mIsFinal; 292 } 293 294 public boolean isEffectivelyFinal() { 295 return mIsFinal || mApiCheckConstructors.isEmpty(); 296 } 297 298 public boolean isIncluded() { 299 return mIsIncluded; 300 } 301 302 public HashSet<String> typeVariables() { 303 HashSet<String> result = TypeInfo.typeVariables(mTypeInfo.typeArguments()); 304 ClassInfo cl = containingClass(); 305 while (cl != null) { 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 */ 320 private List<ClassTypePair> justMyInterfacesWithTypes() { 321 return justMyInterfacesWithTypes(Collections.<String, TypeInfo>emptyMap()); 322 } 323 324 /** 325 * List of only direct interface's classes and their parameterized types. 326 * This can't be lazy loaded, because of the passed in typeArgumentsMap. 327 */ 328 private List<ClassTypePair> justMyInterfacesWithTypes(Map<String, TypeInfo> typeArgumentsMap) { 329 if (mRealInterfaces == null || mRealInterfaceTypes == null) { 330 return Collections.<ClassTypePair>emptyList(); 331 } 332 333 List<ClassTypePair> list = new ArrayList<ClassTypePair>(); 334 for (int i = 0; i < mRealInterfaces.size(); i++) { 335 ClassInfo iface = mRealInterfaces.get(i); 336 TypeInfo type = mRealInterfaceTypes.get(i); 337 if (iface != null && type != null) { 338 type = type.getTypeWithArguments(typeArgumentsMap); 339 if (iface.checkLevel()) { 340 list.add(new ClassTypePair(iface, type)); 341 } else { 342 // add the interface's interfaces 343 Map<String, TypeInfo> map = TypeInfo.getTypeArgumentMapping(iface.asTypeInfo(), type); 344 list.addAll(iface.justMyInterfacesWithTypes(map)); 345 } 346 } 347 } 348 return list; 349 } 350 351 /** 352 * List of only direct interface's classes, and any hidden superclass's direct interfaces 353 * between this class and the first visible superclass and those interface class's parameterized types. 354 */ 355 private ArrayList<ClassTypePair> interfacesWithTypes() { 356 if (mInterfacesWithTypes == null) { 357 mInterfacesWithTypes = new ArrayList<ClassTypePair>(); 358 359 Iterator<ClassTypePair> itr = superClassesWithTypes().iterator(); 360 // skip the first one, which is this class 361 itr.next(); 362 while (itr.hasNext()) { 363 ClassTypePair ctp = itr.next(); 364 if (ctp.classInfo().checkLevel()) { 365 break; 366 } else { 367 // fill mInterfacesWithTypes from the hidden superclass 368 mInterfacesWithTypes.addAll( 369 ctp.classInfo().justMyInterfacesWithTypes(ctp.getTypeArgumentMapping())); 370 } 371 } 372 mInterfacesWithTypes.addAll( 373 justMyInterfacesWithTypes()); 374 } 375 return mInterfacesWithTypes; 376 } 377 378 /** 379 * List of all interface's classes reachable in this class's inheritance hierarchy 380 * and those interface class's parameterized types. 381 */ 382 private ArrayList<ClassTypePair> allInterfacesWithTypes() { 383 if (mAllInterfacesWithTypes == null) { 384 mAllInterfacesWithTypes = new ArrayList<ClassTypePair>(); 385 Queue<ClassTypePair> toParse = new ArrayDeque<ClassTypePair>(); 386 Set<String> visited = new HashSet<String>(); 387 388 Iterator<ClassTypePair> itr = superClassesWithTypes().iterator(); 389 // skip the first one, which is this class 390 itr.next(); 391 while (itr.hasNext()) { 392 ClassTypePair ctp = itr.next(); 393 toParse.addAll( 394 ctp.classInfo().justMyInterfacesWithTypes(ctp.getTypeArgumentMapping())); 395 } 396 toParse.addAll(justMyInterfacesWithTypes()); 397 while (!toParse.isEmpty()) { 398 ClassTypePair ctp = toParse.remove(); 399 if (!visited.contains(ctp.typeInfo().fullName())) { 400 mAllInterfacesWithTypes.add(ctp); 401 visited.add(ctp.typeInfo().fullName()); 402 toParse.addAll(ctp.classInfo().justMyInterfacesWithTypes(ctp.getTypeArgumentMapping())); 403 } 404 } 405 } 406 return mAllInterfacesWithTypes; 407 } 408 409 /** 410 * A list of ClassTypePairs that contain all superclasses 411 * and their corresponding types. The types will have type parameters 412 * cascaded upwards so they match, if any classes along the way set them. 413 * The list includes the current class, and is an ascending order up the 414 * heirarchy tree. 415 * */ 416 private ArrayList<ClassTypePair> superClassesWithTypes() { 417 if (mSuperclassesWithTypes == null) { 418 mSuperclassesWithTypes = new ArrayList<ClassTypePair>(); 419 420 ClassTypePair lastCtp = new ClassTypePair(this, this.asTypeInfo()); 421 mSuperclassesWithTypes.add(lastCtp); 422 423 Map<String, TypeInfo> typeArgumentsMap; 424 ClassInfo superclass = mRealSuperclass; 425 TypeInfo supertype = mRealSuperclassType; 426 TypeInfo nextType; 427 while (superclass != null && supertype != null) { 428 typeArgumentsMap = lastCtp.getTypeArgumentMapping(); 429 lastCtp = new ClassTypePair(superclass, supertype.getTypeWithArguments(typeArgumentsMap)); 430 mSuperclassesWithTypes.add(lastCtp); 431 432 supertype = superclass.mRealSuperclassType; 433 superclass = superclass.mRealSuperclass; 434 } 435 } 436 return mSuperclassesWithTypes; 437 } 438 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 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 469 public ArrayList<ClassInfo> realInterfaces() { 470 return mRealInterfaces; 471 } 472 473 ArrayList<TypeInfo> realInterfaceTypes() { 474 return mRealInterfaceTypes; 475 } 476 477 public void addInterfaceType(TypeInfo type) { 478 if (mRealInterfaceTypes == null) { 479 mRealInterfaceTypes = new ArrayList<TypeInfo>(); 480 } 481 482 mRealInterfaceTypes.add(type); 483 } 484 485 public String name() { 486 return mName; 487 } 488 489 public String[] nameParts() { 490 return mNameParts; 491 } 492 493 public String leafName() { 494 return mNameParts[mNameParts.length - 1]; 495 } 496 497 public String qualifiedName() { 498 return mQualifiedName; 499 } 500 501 public String qualifiedTypeName() { 502 return mQualifiedTypeName; 503 } 504 505 public boolean isPrimitive() { 506 return mIsPrimitive; 507 } 508 509 public ArrayList<MethodInfo> allConstructors() { 510 return mAllConstructors; 511 } 512 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 531 public ArrayList<ClassInfo> innerClasses() { 532 return mInnerClasses; 533 } 534 535 public TagInfo[] inlineTags() { 536 return comment().tags(); 537 } 538 539 public TagInfo[] firstSentenceTags() { 540 return comment().briefTags(); 541 } 542 543 public void setDeprecated(boolean deprecated) { 544 mDeprecatedKnown = true; 545 mIsDeprecated = deprecated; 546 } 547 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 570 public TagInfo[] deprecatedTags() { 571 // Should we also do the interfaces? 572 return comment().deprecatedTags(); 573 } 574 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 605 public ArrayList<MethodInfo> annotationElements() { 606 return mAnnotationElements; 607 } 608 609 public ArrayList<AnnotationInstanceInfo> annotations() { 610 return mAnnotations; 611 } 612 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 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 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 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 682 public ArrayList<FieldInfo> allSelfFields() { 683 return mAllSelfFields; 684 } 685 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 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 728 public ArrayList<MethodInfo> allSelfMethods() { 729 return mAllSelfMethods; 730 } 731 732 /** 733 * @param removedMethods the removed methods regardless of access levels. 734 */ 735 public void setRemovedMethods(List<MethodInfo> removedMethods) { 736 Collections.sort(removedMethods, MethodInfo.comparator); 737 mRemovedMethods = Collections.unmodifiableList(removedMethods); 738 } 739 740 /** 741 * @param allMethods all methods regardless of access levels. Selects the 742 * removed, public/protected ones and store them. If a class is removed, all its members 743 * are removed, even if the member may not have a @removed tag. 744 */ 745 public void setRemovedSelfMethods(List<MethodInfo> allMethods) { 746 List<MethodInfo> removedSelfMethods = new ArrayList<MethodInfo>(); 747 for (MethodInfo method : allMethods) { 748 if ((this.isRemoved() || method.isRemoved()) && (method.isPublic() || method.isProtected()) && 749 (this.isPublic() || this.isProtected()) && 750 (method.findOverriddenMethod(method.name(), method.signature()) == null)) { 751 removedSelfMethods.add(method); 752 } 753 } 754 755 Collections.sort(removedSelfMethods, MethodInfo.comparator); 756 mRemovedSelfMethods = Collections.unmodifiableList(removedSelfMethods); 757 } 758 759 /** 760 * @param allCtors all constructors regardless of access levels. 761 * But only the public/protected removed constructors will be stored by the method. 762 * Removed constructors should never be deleted from source code because 763 * they were once public API. 764 */ 765 public void setRemovedConstructors(List<MethodInfo> allCtors) { 766 List<MethodInfo> ctors = new ArrayList<MethodInfo>(); 767 for (MethodInfo ctor : allCtors) { 768 if ((this.isRemoved() || ctor.isRemoved()) && (ctor.isPublic() || ctor.isProtected()) && 769 (this.isPublic() || this.isProtected())) { 770 ctors.add(ctor); 771 } 772 } 773 774 Collections.sort(ctors, MethodInfo.comparator); 775 mRemovedConstructors = Collections.unmodifiableList(ctors); 776 } 777 778 /** 779 * @param allFields all fields regardless of access levels. Selects the 780 * removed, public/protected ones and store them. If a class is removed, all its members 781 * are removed, even if the member may not have a @removed tag. 782 */ 783 public void setRemovedSelfFields(List<FieldInfo> allFields) { 784 List<FieldInfo> fields = new ArrayList<FieldInfo>(); 785 for (FieldInfo field : allFields) { 786 if ((this.isRemoved() || field.isRemoved()) && (field.isPublic() || field.isProtected()) && 787 (this.isPublic() || this.isProtected())) { 788 fields.add(field); 789 } 790 } 791 792 Collections.sort(fields, FieldInfo.comparator); 793 mRemovedSelfFields = Collections.unmodifiableList(fields); 794 } 795 796 /** 797 * @param allEnumConstants all enum constants regardless of access levels. Selects the 798 * removed, public/protected ones and store them. If a class is removed, all its members 799 * are removed, even if the member may not have a @removed tag. 800 */ 801 public void setRemovedEnumConstants(List<FieldInfo> allEnumConstants) { 802 List<FieldInfo> enums = new ArrayList<FieldInfo>(); 803 for (FieldInfo field : allEnumConstants) { 804 if ((this.isRemoved() || field.isRemoved()) && (field.isPublic() || field.isProtected()) && 805 (this.isPublic() || this.isProtected())) { 806 enums.add(field); 807 } 808 } 809 810 Collections.sort(enums, FieldInfo.comparator); 811 mRemovedEnumConstants = Collections.unmodifiableList(enums); 812 } 813 814 /** 815 * @return all methods that are marked as removed, regardless of access levels. 816 * The returned list is sorted and unmodifiable. 817 */ 818 public List<MethodInfo> getRemovedMethods() { 819 return mRemovedMethods; 820 } 821 822 /** 823 * @return all public/protected methods that are removed. @removed methods should never be 824 * deleted from source code because they were once public API. Methods that override 825 * a parent method will not be included, because deleting them does not break the API. 826 */ 827 public List<MethodInfo> getRemovedSelfMethods() { 828 return mRemovedSelfMethods; 829 } 830 831 /** 832 * @return all public constructors that are removed. 833 * removed constructors should never be deleted from source code because they 834 * were once public API. 835 * The returned list is sorted and unmodifiable. 836 */ 837 public List<MethodInfo> getRemovedConstructors() { 838 return mRemovedConstructors; 839 } 840 841 /** 842 * @return all public/protected fields that are removed. 843 * removed members should never be deleted from source code because they were once public API. 844 * The returned list is sorted and unmodifiable. 845 */ 846 public List<FieldInfo> getRemovedSelfFields() { 847 return mRemovedSelfFields; 848 } 849 850 /** 851 * @return all public/protected enumConstants that are removed. 852 * removed members should never be deleted from source code 853 * because they were once public API. 854 * The returned list is sorted and unmodifiable. 855 */ 856 public List<FieldInfo> getRemovedSelfEnumConstants() { 857 return mRemovedEnumConstants; 858 } 859 860 /** 861 * @return true if this class contains any self members that are removed 862 */ 863 public boolean hasRemovedSelfMembers() { 864 List<FieldInfo> removedSelfFields = getRemovedSelfFields(); 865 List<FieldInfo> removedSelfEnumConstants = getRemovedSelfEnumConstants(); 866 List<MethodInfo> removedSelfMethods = getRemovedSelfMethods(); 867 List<MethodInfo> removedConstructors = getRemovedConstructors(); 868 if (removedSelfFields.size() + removedSelfEnumConstants.size() 869 + removedSelfMethods.size() + removedConstructors.size() == 0) { 870 return false; 871 } else { 872 return true; 873 } 874 } 875 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 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. 891 void setPackage(PackageInfo pkg) { 892 mContainingPackage = pkg; 893 } 894 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 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 964 public ArrayList<FieldInfo> enumConstants() { 965 return mEnumConstants; 966 } 967 968 public ClassInfo superclass() { 969 if (!mSuperclassInit) { 970 if (this.checkLevel()) { 971 // rearrange our little inheritance hierarchy, because we need to hide classes that 972 // don't pass checkLevel 973 ClassInfo superclass = mRealSuperclass; 974 while (superclass != null && !superclass.checkLevel()) { 975 superclass = superclass.mRealSuperclass; 976 } 977 mSuperclass = superclass; 978 } else { 979 mSuperclass = mRealSuperclass; 980 } 981 } 982 return mSuperclass; 983 } 984 985 public ClassInfo realSuperclass() { 986 return mRealSuperclass; 987 } 988 989 /** 990 * always the real superclass, not the collapsed one we get through superclass(), also has the 991 * type parameter info if it's generic. 992 */ 993 public TypeInfo superclassType() { 994 return mRealSuperclassType; 995 } 996 997 public TypeInfo asTypeInfo() { 998 return mTypeInfo; 999 } 1000 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 1009 public String htmlPage() { 1010 String s = containingPackage().name(); 1011 s = s.replace('.', '/'); 1012 s += '/'; 1013 s += name(); 1014 s += ".html"; 1015 s = Doclava.javadocDir + s; 1016 return s; 1017 } 1018 1019 /** Even indirectly */ 1020 public boolean isDerivedFrom(ClassInfo cl) { 1021 return isDerivedFrom(cl.qualifiedName()); 1022 } 1023 1024 /** Even indirectly */ 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 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 1164 public void makeLink(Data data, String base) { 1165 data.setValue(base + ".label", this.name()); 1166 if (!this.isPrimitive() && this.isIncluded() && this.checkLevel()) { 1167 data.setValue(base + ".link", this.htmlPage()); 1168 } 1169 } 1170 1171 public static void makeLinkListHDF(Data data, String base, ClassInfo[] classes) { 1172 final int N = classes.length; 1173 for (int i = 0; i < N; i++) { 1174 ClassInfo cl = classes[i]; 1175 if (cl.checkLevel()) { 1176 cl.asTypeInfo().makeHDF(data, base + "." + i); 1177 } 1178 } 1179 } 1180 1181 /** 1182 * Used in lists of this class (packages, nested classes, known subclasses) 1183 */ 1184 public void makeShortDescrHDF(Data data, String base) { 1185 mTypeInfo.makeHDF(data, base + ".type"); 1186 data.setValue(base + ".kind", this.kind()); 1187 TagInfo.makeHDF(data, base + ".shortDescr", this.firstSentenceTags()); 1188 TagInfo.makeHDF(data, base + ".deprecated", deprecatedTags()); 1189 data.setValue(base + ".since", getSince()); 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 */ 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 ArrayList<AnnotationInstanceInfo> showAnnos = getShowAnnotationsIncludeOuters(); 1238 AnnotationInstanceInfo.makeLinkListHDF( 1239 data, 1240 "class.showAnnotations", 1241 showAnnos.toArray(new AnnotationInstanceInfo[showAnnos.size()])); 1242 1243 // class info 1244 String kind = kind(); 1245 if (kind != null) { 1246 data.setValue("class.kind", kind); 1247 } 1248 data.setValue("class.since", getSince()); 1249 if (isDeprecated()) { 1250 data.setValue("class.deprecatedsince", getDeprecatedSince()); 1251 } 1252 setFederatedReferences(data, "class"); 1253 1254 // the containing package -- note that this can be passed to type_link, 1255 // but it also contains the list of all of the packages 1256 containingPackage().makeClassLinkListHDF(data, "class.package"); 1257 1258 // inheritance hierarchy 1259 List<ClassTypePair> ctplist = superClassesWithTypes(); 1260 n = ctplist.size(); 1261 for (i = 0; i < ctplist.size(); i++) { 1262 // go in reverse order 1263 ClassTypePair ctp = ctplist.get(n - i - 1); 1264 if (ctp.classInfo().checkLevel()) { 1265 ctp.typeInfo().makeQualifiedHDF(data, "class.inheritance." + i + ".class"); 1266 ctp.typeInfo().makeHDF(data, "class.inheritance." + i + ".short_class"); 1267 j = 0; 1268 for (ClassTypePair t : ctp.classInfo().interfacesWithTypes()) { 1269 t.typeInfo().makeHDF(data, "class.inheritance." + i + ".interfaces." + j); 1270 j++; 1271 } 1272 } 1273 } 1274 1275 // class description 1276 TagInfo.makeHDF(data, "class.descr", inlineTags()); 1277 TagInfo.makeHDF(data, "class.seeAlso", comment().seeTags()); 1278 TagInfo.makeHDF(data, "class.deprecated", deprecatedTags()); 1279 1280 // known subclasses 1281 TreeMap<String, ClassInfo> direct = new TreeMap<String, ClassInfo>(); 1282 TreeMap<String, ClassInfo> indirect = new TreeMap<String, ClassInfo>(); 1283 ClassInfo[] all = Converter.rootClasses(); 1284 for (ClassInfo cl : all) { 1285 if (cl.superclass() != null && cl.superclass().equals(this)) { 1286 direct.put(cl.name(), cl); 1287 } else if (cl.isDerivedFrom(this)) { 1288 indirect.put(cl.name(), cl); 1289 } 1290 } 1291 // direct 1292 i = 0; 1293 for (ClassInfo cl : direct.values()) { 1294 if (cl.checkLevel()) { 1295 cl.makeShortDescrHDF(data, "class.subclasses.direct." + i); 1296 } 1297 i++; 1298 } 1299 // indirect 1300 i = 0; 1301 for (ClassInfo cl : indirect.values()) { 1302 if (cl.checkLevel()) { 1303 cl.makeShortDescrHDF(data, "class.subclasses.indirect." + i); 1304 } 1305 i++; 1306 } 1307 1308 // hide special cases 1309 if ("java.lang.Object".equals(qualified) || "java.io.Serializable".equals(qualified)) { 1310 data.setValue("class.subclasses.hidden", "1"); 1311 } else { 1312 data.setValue("class.subclasses.hidden", "0"); 1313 } 1314 1315 // nested classes 1316 i = 0; 1317 for (ClassInfo inner : inners) { 1318 if (inner.checkLevel()) { 1319 inner.makeShortDescrHDF(data, "class.inners." + i); 1320 } 1321 i++; 1322 } 1323 1324 // enum constants 1325 i = 0; 1326 for (FieldInfo field : enumConstants) { 1327 field.makeHDF(data, "class.enumConstants." + i); 1328 i++; 1329 } 1330 1331 // constants 1332 i = 0; 1333 for (FieldInfo field : fields) { 1334 if (field.isConstant()) { 1335 field.makeHDF(data, "class.constants." + i); 1336 i++; 1337 } 1338 } 1339 1340 // fields 1341 i = 0; 1342 for (FieldInfo field : fields) { 1343 if (!field.isConstant()) { 1344 field.makeHDF(data, "class.fields." + i); 1345 i++; 1346 } 1347 } 1348 1349 // public constructors 1350 i = 0; 1351 for (MethodInfo ctor : ctors) { 1352 if (ctor.isPublic()) { 1353 ctor.makeHDF(data, "class.ctors.public." + i); 1354 i++; 1355 } 1356 } 1357 1358 // protected constructors 1359 if (Doclava.checkLevel(Doclava.SHOW_PROTECTED)) { 1360 i = 0; 1361 for (MethodInfo ctor : ctors) { 1362 if (ctor.isProtected()) { 1363 ctor.makeHDF(data, "class.ctors.protected." + i); 1364 i++; 1365 } 1366 } 1367 } 1368 1369 // package private constructors 1370 if (Doclava.checkLevel(Doclava.SHOW_PACKAGE)) { 1371 i = 0; 1372 for (MethodInfo ctor : ctors) { 1373 if (ctor.isPackagePrivate()) { 1374 ctor.makeHDF(data, "class.ctors.package." + i); 1375 i++; 1376 } 1377 } 1378 } 1379 1380 // private constructors 1381 if (Doclava.checkLevel(Doclava.SHOW_PRIVATE)) { 1382 i = 0; 1383 for (MethodInfo ctor : ctors) { 1384 if (ctor.isPrivate()) { 1385 ctor.makeHDF(data, "class.ctors.private." + i); 1386 i++; 1387 } 1388 } 1389 } 1390 1391 // public methods 1392 i = 0; 1393 for (MethodInfo method : methods) { 1394 if (method.isPublic()) { 1395 method.makeHDF(data, "class.methods.public." + i); 1396 i++; 1397 } 1398 } 1399 1400 // protected methods 1401 if (Doclava.checkLevel(Doclava.SHOW_PROTECTED)) { 1402 i = 0; 1403 for (MethodInfo method : methods) { 1404 if (method.isProtected()) { 1405 method.makeHDF(data, "class.methods.protected." + i); 1406 i++; 1407 } 1408 } 1409 } 1410 1411 // package private methods 1412 if (Doclava.checkLevel(Doclava.SHOW_PACKAGE)) { 1413 i = 0; 1414 for (MethodInfo method : methods) { 1415 if (method.isPackagePrivate()) { 1416 method.makeHDF(data, "class.methods.package." + i); 1417 i++; 1418 } 1419 } 1420 } 1421 1422 // private methods 1423 if (Doclava.checkLevel(Doclava.SHOW_PRIVATE)) { 1424 i = 0; 1425 for (MethodInfo method : methods) { 1426 if (method.isPrivate()) { 1427 method.makeHDF(data, "class.methods.private." + i); 1428 i++; 1429 } 1430 } 1431 } 1432 1433 // xml attributes 1434 i = 0; 1435 for (AttributeInfo attr : selfAttributes) { 1436 if (attr.checkLevel()) { 1437 attr.makeHDF(data, "class.attrs." + i); 1438 i++; 1439 } 1440 } 1441 1442 // inherited methods 1443 Iterator<ClassTypePair> superclassesItr = superClassesWithTypes().iterator(); 1444 superclassesItr.next(); // skip the first one, which is the current class 1445 ClassTypePair superCtp; 1446 i = 0; 1447 while (superclassesItr.hasNext()) { 1448 superCtp = superclassesItr.next(); 1449 if (superCtp.classInfo().checkLevel()) { 1450 makeInheritedHDF(data, i, superCtp); 1451 i++; 1452 } 1453 } 1454 Iterator<ClassTypePair> interfacesItr = allInterfacesWithTypes().iterator(); 1455 while (interfacesItr.hasNext()) { 1456 superCtp = interfacesItr.next(); 1457 if (superCtp.classInfo().checkLevel()) { 1458 makeInheritedHDF(data, i, superCtp); 1459 i++; 1460 } 1461 } 1462 } 1463 1464 private static void makeInheritedHDF(Data data, int index, ClassTypePair ctp) { 1465 int i; 1466 1467 String base = "class.inherited." + index; 1468 data.setValue(base + ".qualified", ctp.classInfo().qualifiedName()); 1469 if (ctp.classInfo().checkLevel()) { 1470 data.setValue(base + ".link", ctp.classInfo().htmlPage()); 1471 } 1472 String kind = ctp.classInfo().kind(); 1473 if (kind != null) { 1474 data.setValue(base + ".kind", kind); 1475 } 1476 1477 if (ctp.classInfo().mIsIncluded) { 1478 data.setValue(base + ".included", "true"); 1479 } else { 1480 Doclava.federationTagger.tagAll(new ClassInfo[] {ctp.classInfo()}); 1481 if (!ctp.classInfo().getFederatedReferences().isEmpty()) { 1482 FederatedSite site = ctp.classInfo().getFederatedReferences().iterator().next(); 1483 data.setValue(base + ".link", site.linkFor(ctp.classInfo().htmlPage())); 1484 data.setValue(base + ".federated", site.name()); 1485 } 1486 } 1487 1488 // xml attributes 1489 i = 0; 1490 for (AttributeInfo attr : ctp.classInfo().selfAttributes()) { 1491 attr.makeHDF(data, base + ".attrs." + i); 1492 i++; 1493 } 1494 1495 // methods 1496 i = 0; 1497 for (MethodInfo method : ctp.classInfo().selfMethods()) { 1498 method.makeHDF(data, base + ".methods." + i, ctp.getTypeArgumentMapping()); 1499 i++; 1500 } 1501 1502 // fields 1503 i = 0; 1504 for (FieldInfo field : ctp.classInfo().selfFields()) { 1505 if (!field.isConstant()) { 1506 field.makeHDF(data, base + ".fields." + i); 1507 i++; 1508 } 1509 } 1510 1511 // constants 1512 i = 0; 1513 for (FieldInfo field : ctp.classInfo().selfFields()) { 1514 if (field.isConstant()) { 1515 field.makeHDF(data, base + ".constants." + i); 1516 i++; 1517 } 1518 } 1519 } 1520 1521 @Override 1522 public boolean isHidden() { 1523 if (mHidden == null) { 1524 mHidden = isHiddenImpl(); 1525 } 1526 1527 return mHidden; 1528 } 1529 1530 /** 1531 * @return true if the containing package has @hide comment, or an ancestor 1532 * class of this class is hidden, or this class has @hide comment. 1533 */ 1534 public boolean isHiddenImpl() { 1535 ClassInfo cl = this; 1536 while (cl != null) { 1537 if (cl.hasShowAnnotation()) { 1538 return false; 1539 } 1540 PackageInfo pkg = cl.containingPackage(); 1541 if (pkg != null && pkg.hasHideComment()) { 1542 return true; 1543 } 1544 if (cl.comment().isHidden()) { 1545 return true; 1546 } 1547 cl = cl.containingClass(); 1548 } 1549 return false; 1550 } 1551 1552 @Override 1553 public boolean isRemoved() { 1554 if (mRemoved == null) { 1555 mRemoved = isRemovedImpl(); 1556 } 1557 1558 return mRemoved; 1559 } 1560 1561 /** 1562 * @return true if the containing package has @removed comment, or an ancestor 1563 * class of this class is removed, or this class has @removed comment. 1564 */ 1565 public boolean isRemovedImpl() { 1566 ClassInfo cl = this; 1567 while (cl != null) { 1568 if (cl.hasShowAnnotation()) { 1569 return false; 1570 } 1571 PackageInfo pkg = cl.containingPackage(); 1572 if (pkg != null && pkg.hasRemovedComment()) { 1573 return true; 1574 } 1575 if (cl.comment().isRemoved()) { 1576 return true; 1577 } 1578 cl = cl.containingClass(); 1579 } 1580 return false; 1581 } 1582 1583 @Override 1584 public boolean isHiddenOrRemoved() { 1585 return isHidden() || isRemoved(); 1586 } 1587 1588 public boolean hasShowAnnotation() { 1589 return mShowAnnotations.size() > 0; 1590 } 1591 1592 public ArrayList<AnnotationInstanceInfo> showAnnotations() { 1593 return mShowAnnotations; 1594 } 1595 1596 public ArrayList<AnnotationInstanceInfo> getShowAnnotationsIncludeOuters() { 1597 ArrayList<AnnotationInstanceInfo> allAnnotations = new ArrayList<AnnotationInstanceInfo>(); 1598 ClassInfo cl = this; 1599 while (cl != null) { 1600 if (cl.showAnnotations() != null) { 1601 // Don't allow duplicates into the merged list 1602 for (AnnotationInstanceInfo newAii : cl.showAnnotations()) { 1603 boolean addIt = true; 1604 for (AnnotationInstanceInfo existingAii : allAnnotations) { 1605 if (existingAii.type().name() == newAii.type().name()) { 1606 addIt = false; 1607 break; 1608 } 1609 } 1610 if (addIt) { 1611 allAnnotations.add(newAii); 1612 } 1613 } 1614 } 1615 cl = cl.containingClass(); 1616 } 1617 return allAnnotations; 1618 } 1619 1620 private MethodInfo matchMethod(ArrayList<MethodInfo> methods, String name, String[] params, 1621 String[] dimensions, boolean varargs) { 1622 for (MethodInfo method : methods) { 1623 if (method.name().equals(name)) { 1624 if (params == null) { 1625 return method; 1626 } else { 1627 if (method.matchesParams(params, dimensions, varargs)) { 1628 return method; 1629 } 1630 } 1631 } 1632 } 1633 return null; 1634 } 1635 1636 public MethodInfo findMethod(String name, String[] params, String[] dimensions, boolean varargs) { 1637 // first look on our class, and our superclasses 1638 1639 // for methods 1640 MethodInfo rv; 1641 rv = matchMethod(methods(), name, params, dimensions, varargs); 1642 1643 if (rv != null) { 1644 return rv; 1645 } 1646 1647 // for constructors 1648 rv = matchMethod(constructors(), name, params, dimensions, varargs); 1649 if (rv != null) { 1650 return rv; 1651 } 1652 1653 // then recursively look at our containing class 1654 ClassInfo containing = containingClass(); 1655 if (containing != null) { 1656 return containing.findMethod(name, params, dimensions, varargs); 1657 } 1658 1659 return null; 1660 } 1661 1662 public boolean supportsMethod(MethodInfo method) { 1663 for (MethodInfo m : methods()) { 1664 if (m.getHashableName().equals(method.getHashableName())) { 1665 return true; 1666 } 1667 } 1668 return false; 1669 } 1670 1671 private ClassInfo searchInnerClasses(String[] nameParts, int index) { 1672 String part = nameParts[index]; 1673 1674 ArrayList<ClassInfo> inners = mInnerClasses; 1675 for (ClassInfo in : inners) { 1676 String[] innerParts = in.nameParts(); 1677 if (part.equals(innerParts[innerParts.length - 1])) { 1678 if (index == nameParts.length - 1) { 1679 return in; 1680 } else { 1681 return in.searchInnerClasses(nameParts, index + 1); 1682 } 1683 } 1684 } 1685 return null; 1686 } 1687 1688 public ClassInfo extendedFindClass(String className) { 1689 // ClassDoc.findClass has this bug that we're working around here: 1690 // If you have a class PackageManager with an inner class PackageInfo 1691 // and you call it with "PackageInfo" it doesn't find it. 1692 return searchInnerClasses(className.split("\\."), 0); 1693 } 1694 1695 public ClassInfo findClass(String className) { 1696 return Converter.obtainClass(mClass.findClass(className)); 1697 } 1698 1699 public ClassInfo findInnerClass(String className) { 1700 // ClassDoc.findClass won't find inner classes. To deal with that, 1701 // we try what they gave us first, but if that didn't work, then 1702 // we see if there are any periods in className, and start searching 1703 // from there. 1704 String[] nodes = className.split("\\."); 1705 ClassDoc cl = mClass; 1706 1707 int N = nodes.length; 1708 for (int i = 0; i < N; ++i) { 1709 final String n = nodes[i]; 1710 if (n.isEmpty() && i == 0) { 1711 // We skip over an empty classname component if it's at location 0. This is 1712 // to deal with names like ".Inner". java7 will return a bogus ClassInfo when 1713 // we call "findClass("") and the next iteration of the loop will throw a 1714 // runtime exception. 1715 continue; 1716 } 1717 1718 cl = cl.findClass(n); 1719 if (cl == null) { 1720 return null; 1721 } 1722 } 1723 1724 return Converter.obtainClass(cl); 1725 } 1726 1727 public FieldInfo findField(String name) { 1728 // first look on our class, and our superclasses 1729 for (FieldInfo f : fields()) { 1730 if (f.name().equals(name)) { 1731 return f; 1732 } 1733 } 1734 1735 // then look at our enum constants (these are really fields, maybe 1736 // they should be mixed into fields(). not sure) 1737 for (FieldInfo f : enumConstants()) { 1738 if (f.name().equals(name)) { 1739 return f; 1740 } 1741 } 1742 1743 // then recursively look at our containing class 1744 ClassInfo containing = containingClass(); 1745 if (containing != null) { 1746 return containing.findField(name); 1747 } 1748 1749 return null; 1750 } 1751 1752 public static ClassInfo[] sortByName(ClassInfo[] classes) { 1753 int i; 1754 Sorter[] sorted = new Sorter[classes.length]; 1755 for (i = 0; i < sorted.length; i++) { 1756 ClassInfo cl = classes[i]; 1757 sorted[i] = new Sorter(cl.name(), cl); 1758 } 1759 1760 Arrays.sort(sorted); 1761 1762 ClassInfo[] rv = new ClassInfo[classes.length]; 1763 for (i = 0; i < rv.length; i++) { 1764 rv[i] = (ClassInfo) sorted[i].data; 1765 } 1766 1767 return rv; 1768 } 1769 1770 public boolean equals(ClassInfo that) { 1771 if (that != null) { 1772 return this.qualifiedName().equals(that.qualifiedName()); 1773 } else { 1774 return false; 1775 } 1776 } 1777 1778 public void setNonWrittenConstructors(ArrayList<MethodInfo> nonWritten) { 1779 mNonWrittenConstructors = nonWritten; 1780 } 1781 1782 public ArrayList<MethodInfo> getNonWrittenConstructors() { 1783 return mNonWrittenConstructors; 1784 } 1785 1786 public String kind() { 1787 if (isOrdinaryClass()) { 1788 return "class"; 1789 } else if (isInterface()) { 1790 return "interface"; 1791 } else if (isEnum()) { 1792 return "enum"; 1793 } else if (isError()) { 1794 return "class"; 1795 } else if (isException()) { 1796 return "class"; 1797 } else if (isAnnotation()) { 1798 return "@interface"; 1799 } 1800 return null; 1801 } 1802 1803 public String scope() { 1804 if (isPublic()) { 1805 return "public"; 1806 } else if (isProtected()) { 1807 return "protected"; 1808 } else if (isPackagePrivate()) { 1809 return ""; 1810 } else if (isPrivate()) { 1811 return "private"; 1812 } else { 1813 throw new RuntimeException("invalid scope for object " + this); 1814 } 1815 } 1816 1817 public void setHiddenMethods(ArrayList<MethodInfo> mInfo) { 1818 mHiddenMethods = mInfo; 1819 } 1820 1821 public ArrayList<MethodInfo> getHiddenMethods() { 1822 return mHiddenMethods; 1823 } 1824 1825 @Override 1826 public String toString() { 1827 return this.qualifiedName(); 1828 } 1829 1830 public void setReasonIncluded(String reason) { 1831 mReasonIncluded = reason; 1832 } 1833 1834 public String getReasonIncluded() { 1835 return mReasonIncluded; 1836 } 1837 1838 private ClassDoc mClass; 1839 1840 // ctor 1841 private boolean mIsPublic; 1842 private boolean mIsProtected; 1843 private boolean mIsPackagePrivate; 1844 private boolean mIsPrivate; 1845 private boolean mIsStatic; 1846 private boolean mIsInterface; 1847 private boolean mIsAbstract; 1848 private boolean mIsOrdinaryClass; 1849 private boolean mIsException; 1850 private boolean mIsError; 1851 private boolean mIsEnum; 1852 private boolean mIsAnnotation; 1853 private boolean mIsFinal; 1854 private boolean mIsIncluded; 1855 private String mName; 1856 private String mQualifiedName; 1857 private String mQualifiedTypeName; 1858 private boolean mIsPrimitive; 1859 private TypeInfo mTypeInfo; 1860 private String[] mNameParts; 1861 1862 // init 1863 private ArrayList<ClassInfo> mRealInterfaces = new ArrayList<ClassInfo>(); 1864 private ArrayList<ClassInfo> mInterfaces; 1865 private ArrayList<TypeInfo> mRealInterfaceTypes; 1866 private ArrayList<ClassInfo> mInnerClasses; 1867 // mAllConstructors will not contain *all* constructors. Only the constructors that pass 1868 // checkLevel. @see {@link Converter#convertMethods(ConstructorDoc[])} 1869 private ArrayList<MethodInfo> mAllConstructors = new ArrayList<MethodInfo>(); 1870 // mAllSelfMethods will not contain *all* self methods. Only the methods that pass 1871 // checkLevel. @see {@link Converter#convertMethods(MethodDoc[])} 1872 private ArrayList<MethodInfo> mAllSelfMethods = new ArrayList<MethodInfo>(); 1873 private ArrayList<MethodInfo> mAnnotationElements = new ArrayList<MethodInfo>(); // if this class is an annotation 1874 private ArrayList<FieldInfo> mAllSelfFields = new ArrayList<FieldInfo>(); 1875 private ArrayList<FieldInfo> mEnumConstants = new ArrayList<FieldInfo>(); 1876 private PackageInfo mContainingPackage; 1877 private ClassInfo mContainingClass; 1878 private ClassInfo mRealSuperclass; 1879 private TypeInfo mRealSuperclassType; 1880 private ClassInfo mSuperclass; 1881 private ArrayList<AnnotationInstanceInfo> mAnnotations; 1882 private ArrayList<AnnotationInstanceInfo> mShowAnnotations; 1883 private boolean mSuperclassInit; 1884 private boolean mDeprecatedKnown; 1885 1886 // lazy 1887 private ArrayList<ClassTypePair> mSuperclassesWithTypes; 1888 private ArrayList<ClassTypePair> mInterfacesWithTypes; 1889 private ArrayList<ClassTypePair> mAllInterfacesWithTypes; 1890 private ArrayList<MethodInfo> mConstructors; 1891 private ArrayList<ClassInfo> mRealInnerClasses; 1892 private ArrayList<MethodInfo> mSelfMethods; 1893 private ArrayList<FieldInfo> mSelfFields; 1894 private ArrayList<AttributeInfo> mSelfAttributes; 1895 private ArrayList<MethodInfo> mMethods; 1896 private ArrayList<FieldInfo> mFields; 1897 private ArrayList<TypeInfo> mTypeParameters; 1898 private ArrayList<MethodInfo> mHiddenMethods; 1899 private Boolean mHidden = null; 1900 private Boolean mRemoved = null; 1901 private Boolean mCheckLevel = null; 1902 private String mReasonIncluded; 1903 private ArrayList<MethodInfo> mNonWrittenConstructors; 1904 private boolean mIsDeprecated; 1905 1906 // TODO: Temporary members from apicheck migration. 1907 private HashMap<String, MethodInfo> mApiCheckConstructors = new HashMap<String, MethodInfo>(); 1908 private HashMap<String, MethodInfo> mApiCheckMethods = new HashMap<String, MethodInfo>(); 1909 private HashMap<String, FieldInfo> mApiCheckFields = new HashMap<String, FieldInfo>(); 1910 private HashMap<String, FieldInfo> mApiCheckEnumConstants = new HashMap<String, FieldInfo>(); 1911 1912 // Resolutions 1913 private ArrayList<Resolution> mResolutions; 1914 1915 private List<MethodInfo> mRemovedConstructors; // immutable after you set its value. 1916 // @removed self methods that do not override any parent methods 1917 private List<MethodInfo> mRemovedSelfMethods; // immutable after you set its value. 1918 private List<MethodInfo> mRemovedMethods; // immutable after you set its value. 1919 private List<FieldInfo> mRemovedSelfFields; // immutable after you set its value. 1920 private List<FieldInfo> mRemovedEnumConstants; // immutable after you set its value. 1921 1922 /** 1923 * Returns true if {@code cl} implements the interface {@code iface} either by either being that 1924 * interface, implementing that interface or extending a type that implements the interface. 1925 */ 1926 public boolean implementsInterface(String iface) { 1927 if (qualifiedName().equals(iface)) { 1928 return true; 1929 } 1930 for (ClassInfo clImplements : realInterfaces()) { 1931 if (clImplements.implementsInterface(iface)) { 1932 return true; 1933 } 1934 } 1935 if (mSuperclass != null && mSuperclass.implementsInterface(iface)) { 1936 return true; 1937 } 1938 return false; 1939 } 1940 1941 /** 1942 * Returns true if {@code this} extends the class {@code ext}. 1943 */ 1944 public boolean extendsClass(String cl) { 1945 if (qualifiedName().equals(cl)) { 1946 return true; 1947 } 1948 if (mSuperclass != null && mSuperclass.extendsClass(cl)) { 1949 return true; 1950 } 1951 return false; 1952 } 1953 1954 /** 1955 * Returns true if {@code this} is assignable to cl 1956 */ 1957 public boolean isAssignableTo(String cl) { 1958 return implementsInterface(cl) || extendsClass(cl); 1959 } 1960 1961 public void addInterface(ClassInfo iface) { 1962 mRealInterfaces.add(iface); 1963 } 1964 1965 public void addConstructor(MethodInfo ctor) { 1966 mApiCheckConstructors.put(ctor.getHashableName(), ctor); 1967 1968 mAllConstructors.add(ctor); 1969 mConstructors = null; // flush this, hopefully it hasn't been used yet. 1970 } 1971 1972 public void addField(FieldInfo field) { 1973 mApiCheckFields.put(field.name(), field); 1974 1975 mAllSelfFields.add(field); 1976 1977 mSelfFields = null; // flush this, hopefully it hasn't been used yet. 1978 } 1979 1980 public void addEnumConstant(FieldInfo field) { 1981 mApiCheckEnumConstants.put(field.name(), field); 1982 1983 mEnumConstants.add(field); 1984 } 1985 1986 public void setSuperClass(ClassInfo superclass) { 1987 mRealSuperclass = superclass; 1988 mSuperclass = superclass; 1989 } 1990 1991 public Map<String, MethodInfo> allConstructorsMap() { 1992 return mApiCheckConstructors; 1993 } 1994 1995 public Map<String, FieldInfo> allFields() { 1996 return mApiCheckFields; 1997 } 1998 1999 public Map<String, FieldInfo> allEnums() { 2000 return mApiCheckEnumConstants; 2001 } 2002 2003 /** 2004 * Returns all methods defined directly in this class. For a list of all 2005 * methods supported by this class, see {@link #methods()}. 2006 */ 2007 public Map<String, MethodInfo> allMethods() { 2008 return mApiCheckMethods; 2009 } 2010 2011 /** 2012 * Returns the class hierarchy for this class, starting with this class. 2013 */ 2014 public Iterable<ClassInfo> hierarchy() { 2015 List<ClassInfo> result = new ArrayList<ClassInfo>(4); 2016 for (ClassInfo c = this; c != null; c = c.mSuperclass) { 2017 result.add(c); 2018 } 2019 return result; 2020 } 2021 2022 public String superclassName() { 2023 if (mSuperclass == null) { 2024 if (mQualifiedName.equals("java.lang.Object")) { 2025 return null; 2026 } 2027 throw new UnsupportedOperationException("Superclass not set for " + qualifiedName()); 2028 } 2029 return mSuperclass.mQualifiedName; 2030 } 2031 2032 public void setAnnotations(ArrayList<AnnotationInstanceInfo> annotations) { 2033 mAnnotations = annotations; 2034 } 2035 2036 public boolean isConsistent(ClassInfo cl) { 2037 boolean consistent = true; 2038 2039 if (isInterface() != cl.isInterface()) { 2040 Errors.error(Errors.CHANGED_CLASS, cl.position(), "Class " + cl.qualifiedName() 2041 + " changed class/interface declaration"); 2042 consistent = false; 2043 } 2044 for (ClassInfo iface : mRealInterfaces) { 2045 if (!cl.implementsInterface(iface.mQualifiedName)) { 2046 Errors.error(Errors.REMOVED_INTERFACE, cl.position(), "Class " + qualifiedName() 2047 + " no longer implements " + iface); 2048 } 2049 } 2050 for (ClassInfo iface : cl.mRealInterfaces) { 2051 if (!implementsInterface(iface.mQualifiedName)) { 2052 Errors.error(Errors.ADDED_INTERFACE, cl.position(), "Added interface " + iface 2053 + " to class " + qualifiedName()); 2054 consistent = false; 2055 } 2056 } 2057 2058 for (MethodInfo mInfo : mApiCheckMethods.values()) { 2059 if (cl.mApiCheckMethods.containsKey(mInfo.getHashableName())) { 2060 if (!mInfo.isConsistent(cl.mApiCheckMethods.get(mInfo.getHashableName()))) { 2061 consistent = false; 2062 } 2063 } else { 2064 /* 2065 * This class formerly provided this method directly, and now does not. Check our ancestry 2066 * to see if there's an inherited version that still fulfills the API requirement. 2067 */ 2068 MethodInfo mi = ClassInfo.overriddenMethod(mInfo, cl); 2069 if (mi == null) { 2070 mi = ClassInfo.interfaceMethod(mInfo, cl); 2071 } 2072 if (mi == null) { 2073 Errors.error(Errors.REMOVED_METHOD, mInfo.position(), "Removed public method " 2074 + mInfo.qualifiedName()); 2075 consistent = false; 2076 } 2077 } 2078 } 2079 for (MethodInfo mInfo : cl.mApiCheckMethods.values()) { 2080 if (!mApiCheckMethods.containsKey(mInfo.getHashableName())) { 2081 /* 2082 * Similarly to the above, do not fail if this "new" method is really an override of an 2083 * existing superclass method. 2084 */ 2085 MethodInfo mi = ClassInfo.overriddenMethod(mInfo, this); 2086 if (mi == null) { 2087 Errors.error(Errors.ADDED_METHOD, mInfo.position(), "Added public method " 2088 + mInfo.qualifiedName()); 2089 consistent = false; 2090 } 2091 } 2092 } 2093 2094 for (MethodInfo mInfo : mApiCheckConstructors.values()) { 2095 if (cl.mApiCheckConstructors.containsKey(mInfo.getHashableName())) { 2096 if (!mInfo.isConsistent(cl.mApiCheckConstructors.get(mInfo.getHashableName()))) { 2097 consistent = false; 2098 } 2099 } else { 2100 Errors.error(Errors.REMOVED_METHOD, mInfo.position(), "Removed public constructor " 2101 + mInfo.prettySignature()); 2102 consistent = false; 2103 } 2104 } 2105 for (MethodInfo mInfo : cl.mApiCheckConstructors.values()) { 2106 if (!mApiCheckConstructors.containsKey(mInfo.getHashableName())) { 2107 Errors.error(Errors.ADDED_METHOD, mInfo.position(), "Added public constructor " 2108 + mInfo.prettySignature()); 2109 consistent = false; 2110 } 2111 } 2112 2113 for (FieldInfo mInfo : mApiCheckFields.values()) { 2114 if (cl.mApiCheckFields.containsKey(mInfo.name())) { 2115 if (!mInfo.isConsistent(cl.mApiCheckFields.get(mInfo.name()))) { 2116 consistent = false; 2117 } 2118 } else { 2119 Errors.error(Errors.REMOVED_FIELD, mInfo.position(), "Removed field " 2120 + mInfo.qualifiedName()); 2121 consistent = false; 2122 } 2123 } 2124 for (FieldInfo mInfo : cl.mApiCheckFields.values()) { 2125 if (!mApiCheckFields.containsKey(mInfo.name())) { 2126 Errors.error(Errors.ADDED_FIELD, mInfo.position(), "Added public field " 2127 + mInfo.qualifiedName()); 2128 consistent = false; 2129 } 2130 } 2131 2132 for (FieldInfo info : mApiCheckEnumConstants.values()) { 2133 if (cl.mApiCheckEnumConstants.containsKey(info.name())) { 2134 if (!info.isConsistent(cl.mApiCheckEnumConstants.get(info.name()))) { 2135 consistent = false; 2136 } 2137 } else { 2138 Errors.error(Errors.REMOVED_FIELD, info.position(), "Removed enum constant " 2139 + info.qualifiedName()); 2140 consistent = false; 2141 } 2142 } 2143 for (FieldInfo info : cl.mApiCheckEnumConstants.values()) { 2144 if (!mApiCheckEnumConstants.containsKey(info.name())) { 2145 Errors.error(Errors.ADDED_FIELD, info.position(), "Added enum constant " 2146 + info.qualifiedName()); 2147 consistent = false; 2148 } 2149 } 2150 2151 if (mIsAbstract != cl.mIsAbstract) { 2152 consistent = false; 2153 Errors.error(Errors.CHANGED_ABSTRACT, cl.position(), "Class " + cl.qualifiedName() 2154 + " changed abstract qualifier"); 2155 } 2156 2157 if (!mIsFinal && cl.mIsFinal) { 2158 /* 2159 * It is safe to make a class final if it did not previously have any public 2160 * constructors because it was impossible for an application to create a subclass. 2161 */ 2162 if (mApiCheckConstructors.isEmpty()) { 2163 consistent = false; 2164 Errors.error(Errors.ADDED_FINAL_UNINSTANTIABLE, cl.position(), 2165 "Class " + cl.qualifiedName() + " added final qualifier but " 2166 + "was previously uninstantiable and therefore could not be subclassed"); 2167 } else { 2168 consistent = false; 2169 Errors.error(Errors.ADDED_FINAL, cl.position(), "Class " + cl.qualifiedName() 2170 + " added final qualifier"); 2171 } 2172 } else if (mIsFinal && !cl.mIsFinal) { 2173 consistent = false; 2174 Errors.error(Errors.REMOVED_FINAL, cl.position(), "Class " + cl.qualifiedName() 2175 + " removed final qualifier"); 2176 } 2177 2178 if (mIsStatic != cl.mIsStatic) { 2179 consistent = false; 2180 Errors.error(Errors.CHANGED_STATIC, cl.position(), "Class " + cl.qualifiedName() 2181 + " changed static qualifier"); 2182 } 2183 2184 if (!scope().equals(cl.scope())) { 2185 consistent = false; 2186 Errors.error(Errors.CHANGED_SCOPE, cl.position(), "Class " + cl.qualifiedName() 2187 + " scope changed from " + scope() + " to " + cl.scope()); 2188 } 2189 2190 if (!isDeprecated() == cl.isDeprecated()) { 2191 consistent = false; 2192 Errors.error(Errors.CHANGED_DEPRECATED, cl.position(), "Class " + cl.qualifiedName() 2193 + " has changed deprecation state"); 2194 } 2195 2196 if (superclassName() != null) { // java.lang.Object can't have a superclass. 2197 if (!cl.extendsClass(superclassName())) { 2198 consistent = false; 2199 Errors.error(Errors.CHANGED_SUPERCLASS, cl.position(), "Class " + qualifiedName() 2200 + " superclass changed from " + superclassName() + " to " + cl.superclassName()); 2201 } 2202 } 2203 2204 return consistent; 2205 } 2206 2207 // Find a superclass implementation of the given method based on the methods in mApiCheckMethods. 2208 public static MethodInfo overriddenMethod(MethodInfo candidate, ClassInfo newClassObj) { 2209 if (newClassObj == null) { 2210 return null; 2211 } 2212 for (MethodInfo mi : newClassObj.mApiCheckMethods.values()) { 2213 if (mi.matches(candidate)) { 2214 // found it 2215 return mi; 2216 } 2217 } 2218 2219 // not found here. recursively search ancestors 2220 return ClassInfo.overriddenMethod(candidate, newClassObj.mSuperclass); 2221 } 2222 2223 // Find a superinterface declaration of the given method. 2224 public static MethodInfo interfaceMethod(MethodInfo candidate, ClassInfo newClassObj) { 2225 if (newClassObj == null) { 2226 return null; 2227 } 2228 for (ClassInfo interfaceInfo : newClassObj.interfaces()) { 2229 for (MethodInfo mi : interfaceInfo.mApiCheckMethods.values()) { 2230 if (mi.matches(candidate)) { 2231 return mi; 2232 } 2233 } 2234 } 2235 return ClassInfo.interfaceMethod(candidate, newClassObj.mSuperclass); 2236 } 2237 2238 public boolean hasConstructor(MethodInfo constructor) { 2239 String name = constructor.getHashableName(); 2240 for (MethodInfo ctor : mApiCheckConstructors.values()) { 2241 if (name.equals(ctor.getHashableName())) { 2242 return true; 2243 } 2244 } 2245 return false; 2246 } 2247 2248 public void setTypeInfo(TypeInfo typeInfo) { 2249 mTypeInfo = typeInfo; 2250 } 2251 2252 public TypeInfo type() { 2253 return mTypeInfo; 2254 } 2255 2256 public void addInnerClass(ClassInfo innerClass) { 2257 if (mInnerClasses == null) { 2258 mInnerClasses = new ArrayList<ClassInfo>(); 2259 } 2260 2261 mInnerClasses.add(innerClass); 2262 } 2263 2264 public void setContainingClass(ClassInfo containingClass) { 2265 mContainingClass = containingClass; 2266 } 2267 2268 public void setSuperclassType(TypeInfo superclassType) { 2269 mRealSuperclassType = superclassType; 2270 } 2271 2272 public void printResolutions() { 2273 if (mResolutions == null || mResolutions.isEmpty()) { 2274 return; 2275 } 2276 2277 System.out.println("Resolutions for Class " + mName + ":"); 2278 2279 for (Resolution r : mResolutions) { 2280 System.out.println(r); 2281 } 2282 } 2283 2284 public void addResolution(Resolution resolution) { 2285 if (mResolutions == null) { 2286 mResolutions = new ArrayList<Resolution>(); 2287 } 2288 2289 mResolutions.add(resolution); 2290 } 2291 2292 public boolean resolveResolutions() { 2293 ArrayList<Resolution> resolutions = mResolutions; 2294 mResolutions = new ArrayList<Resolution>(); 2295 2296 boolean allResolved = true; 2297 for (Resolution resolution : resolutions) { 2298 StringBuilder qualifiedClassName = new StringBuilder(); 2299 InfoBuilder.resolveQualifiedName(resolution.getValue(), qualifiedClassName, 2300 resolution.getInfoBuilder()); 2301 2302 // if we still couldn't resolve it, save it for the next pass 2303 if ("".equals(qualifiedClassName.toString())) { 2304 mResolutions.add(resolution); 2305 allResolved = false; 2306 } else if ("superclassQualifiedName".equals(resolution.getVariable())) { 2307 setSuperClass(InfoBuilder.Caches.obtainClass(qualifiedClassName.toString())); 2308 } else if ("interfaceQualifiedName".equals(resolution.getVariable())) { 2309 addInterface(InfoBuilder.Caches.obtainClass(qualifiedClassName.toString())); 2310 } 2311 } 2312 2313 return allResolved; 2314 } 2315} 2316