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.ArrayList; 23 import java.util.Arrays; 24 import java.util.Collections; 25 import java.util.Comparator; 26 import java.util.HashMap; 27 import java.util.HashSet; 28 import java.util.List; 29 import java.util.Map; 30 import java.util.Set; 31 import java.util.TreeMap; 32 import java.util.TreeSet; 33 import java.util.Vector; 34 35 public class ClassInfo extends DocInfo implements ContainerInfo, Comparable, Scoped, Resolvable { 36 public static final Comparator<ClassInfo> comparator = new Comparator<ClassInfo>() { 37 public int compare(ClassInfo a, ClassInfo b) { 38 return a.name().compareTo(b.name()); 39 } 40 }; 41 42 public static final Comparator<ClassInfo> qualifiedComparator = new Comparator<ClassInfo>() { 43 public int compare(ClassInfo a, ClassInfo b) { 44 return a.qualifiedName().compareTo(b.qualifiedName()); 45 } 46 }; 47 48 /** 49 * Constructs a stub representation of a class. 50 */ 51 public ClassInfo(String qualifiedName) { 52 super("", SourcePositionInfo.UNKNOWN); 53 54 mQualifiedName = qualifiedName; 55 if (qualifiedName.lastIndexOf('.') != -1) { 56 mName = qualifiedName.substring(qualifiedName.lastIndexOf('.') + 1); 57 } else { 58 mName = qualifiedName; 59 } 60 } 61 62 public ClassInfo(ClassDoc cl, String rawCommentText, SourcePositionInfo position, 63 boolean isPublic, boolean isProtected, boolean isPackagePrivate, boolean isPrivate, 64 boolean isStatic, boolean isInterface, boolean isAbstract, boolean isOrdinaryClass, 65 boolean isException, boolean isError, boolean isEnum, boolean isAnnotation, boolean isFinal, 66 boolean isIncluded, String name, String qualifiedName, String qualifiedTypeName, 67 boolean isPrimitive) { 68 super(rawCommentText, position); 69 70 initialize(rawCommentText, position, 71 isPublic, isProtected, isPackagePrivate, isPrivate, 72 isStatic, isInterface, isAbstract, isOrdinaryClass, 73 isException, isError, isEnum, isAnnotation, isFinal, 74 isIncluded, qualifiedTypeName, isPrimitive, null); 75 76 mName = name; 77 mQualifiedName = qualifiedName; 78 mNameParts = name.split("\\."); 79 mClass = cl; 80 } 81 82 public void initialize(String rawCommentText, SourcePositionInfo position, 83 boolean isPublic, boolean isProtected, boolean isPackagePrivate, boolean isPrivate, 84 boolean isStatic, boolean isInterface, boolean isAbstract, boolean isOrdinaryClass, 85 boolean isException, boolean isError, boolean isEnum, boolean isAnnotation, boolean isFinal, 86 boolean isIncluded, String qualifiedTypeName, boolean isPrimitive, ArrayList<AnnotationInstanceInfo> annotations) { 87 88 // calls 89 setPosition(position); 90 setRawCommentText(rawCommentText); 91 mIsPublic = isPublic; 92 mIsProtected = isProtected; 93 mIsPackagePrivate = isPackagePrivate; 94 mIsPrivate = isPrivate; 95 mIsStatic = isStatic; 96 mIsInterface = isInterface; 97 mIsAbstract = isAbstract; 98 mIsOrdinaryClass = isOrdinaryClass; 99 mIsException = isException; 100 mIsError = isError; 101 mIsEnum = isEnum; 102 mIsAnnotation = isAnnotation; 103 mIsFinal = isFinal; 104 mIsIncluded = isIncluded; 105 mQualifiedTypeName = qualifiedTypeName; 106 mIsPrimitive = isPrimitive; 107 mAnnotations = annotations; 108 } 109 110 public void init(TypeInfo typeInfo, ArrayList<ClassInfo> interfaces, 111 ArrayList<TypeInfo> interfaceTypes, ArrayList<ClassInfo> innerClasses, 112 ArrayList<MethodInfo> constructors, ArrayList<MethodInfo> methods, 113 ArrayList<MethodInfo> annotationElements, ArrayList<FieldInfo> fields, 114 ArrayList<FieldInfo> enumConstants, PackageInfo containingPackage, 115 ClassInfo containingClass, ClassInfo superclass, 116 TypeInfo superclassType, ArrayList<AnnotationInstanceInfo> annotations) { 117 mTypeInfo = typeInfo; 118 mRealInterfaces = new ArrayList<ClassInfo>(interfaces); 119 mRealInterfaceTypes = interfaceTypes; 120 mInnerClasses = innerClasses; 121 mAllConstructors = constructors; 122 mAllSelfMethods = methods; 123 mAnnotationElements = annotationElements; 124 mAllSelfFields = fields; 125 mEnumConstants = enumConstants; 126 mContainingPackage = containingPackage; 127 mContainingClass = containingClass; 128 mRealSuperclass = superclass; 129 mRealSuperclassType = superclassType; 130 mAnnotations = annotations; 131 132 // after providing new methods and new superclass info,clear any cached 133 // lists of self + superclass methods, ctors, etc. 134 mSuperclassInit = false; 135 mConstructors = null; 136 mMethods = null; 137 mSelfMethods = null; 138 mFields = null; 139 mSelfFields = null; 140 mSelfAttributes = null; 141 mDeprecatedKnown = false; 142 143 Collections.sort(mEnumConstants, FieldInfo.comparator); 144 Collections.sort(mInnerClasses, ClassInfo.comparator); 145 } 146 147 public void init2() { 148 // calling this here forces the AttrTagInfo objects to be linked to the AttribtueInfo 149 // objects 150 selfAttributes(); 151 } 152 153 public void init3(ArrayList<TypeInfo> types, ArrayList<ClassInfo> realInnerClasses) { 154 mTypeParameters = types; 155 mRealInnerClasses = realInnerClasses; 156 } 157 158 public ArrayList<ClassInfo> getRealInnerClasses() { 159 return mRealInnerClasses; 160 } 161 162 public ArrayList<TypeInfo> getTypeParameters() { 163 return mTypeParameters; 164 } 165 166 public boolean checkLevel() { 167 int val = mCheckLevel; 168 if (val >= 0) { 169 return val != 0; 170 } else { 171 boolean v = 172 Doclava.checkLevel(mIsPublic, mIsProtected, mIsPackagePrivate, mIsPrivate, isHidden()); 173 mCheckLevel = v ? 1 : 0; 174 return v; 175 } 176 } 177 178 public int compareTo(Object that) { 179 if (that instanceof ClassInfo) { 180 return mQualifiedName.compareTo(((ClassInfo) that).mQualifiedName); 181 } else { 182 return this.hashCode() - that.hashCode(); 183 } 184 } 185 186 @Override 187 public ContainerInfo parent() { 188 return this; 189 } 190 191 public boolean isPublic() { 192 return mIsPublic; 193 } 194 195 public boolean isProtected() { 196 return mIsProtected; 197 } 198 199 public boolean isPackagePrivate() { 200 return mIsPackagePrivate; 201 } 202 203 public boolean isPrivate() { 204 return mIsPrivate; 205 } 206 207 public boolean isStatic() { 208 return mIsStatic; 209 } 210 211 public boolean isInterface() { 212 return mIsInterface; 213 } 214 215 public boolean isAbstract() { 216 return mIsAbstract; 217 } 218 219 public PackageInfo containingPackage() { 220 return mContainingPackage; 221 } 222 223 public ClassInfo containingClass() { 224 return mContainingClass; 225 } 226 227 public boolean isOrdinaryClass() { 228 return mIsOrdinaryClass; 229 } 230 231 public boolean isException() { 232 return mIsException; 233 } 234 235 public boolean isError() { 236 return mIsError; 237 } 238 239 public boolean isEnum() { 240 return mIsEnum; 241 } 242 243 public boolean isAnnotation() { 244 return mIsAnnotation; 245 } 246 247 public boolean isFinal() { 248 return mIsFinal; 249 } 250 251 public boolean isIncluded() { 252 return mIsIncluded; 253 } 254 255 public HashSet<String> typeVariables() { 256 HashSet<String> result = TypeInfo.typeVariables(mTypeInfo.typeArguments()); 257 ClassInfo cl = containingClass(); 258 while (cl != null) { 259 ArrayList<TypeInfo> types = cl.asTypeInfo().typeArguments(); 260 if (types != null) { 261 TypeInfo.typeVariables(types, result); 262 } 263 cl = cl.containingClass(); 264 } 265 return result; 266 } 267 268 private static void gatherHiddenInterfaces(ClassInfo cl, HashSet<ClassInfo> interfaces) { 269 for (ClassInfo iface : cl.mRealInterfaces) { 270 if (iface.checkLevel()) { 271 interfaces.add(iface); 272 } else { 273 gatherHiddenInterfaces(iface, interfaces); 274 } 275 } 276 } 277 278 public ArrayList<ClassInfo> interfaces() { 279 if (mInterfaces == null) { 280 if (checkLevel()) { 281 HashSet<ClassInfo> interfaces = new HashSet<ClassInfo>(); 282 ClassInfo superclass = mRealSuperclass; 283 while (superclass != null && !superclass.checkLevel()) { 284 gatherHiddenInterfaces(superclass, interfaces); 285 superclass = superclass.mRealSuperclass; 286 } 287 gatherHiddenInterfaces(this, interfaces); 288 mInterfaces = new ArrayList<ClassInfo>(interfaces); 289 } else { 290 // put something here in case someone uses it 291 mInterfaces = new ArrayList<ClassInfo>(mRealInterfaces); 292 } 293 Collections.sort(mInterfaces, ClassInfo.qualifiedComparator); 294 } 295 return mInterfaces; 296 } 297 298 public ArrayList<ClassInfo> realInterfaces() { 299 return mRealInterfaces; 300 } 301 302 ArrayList<TypeInfo> realInterfaceTypes() { 303 return mRealInterfaceTypes; 304 } 305 306 public void addInterfaceType(TypeInfo type) { 307 if (mRealInterfaceTypes == null) { 308 mRealInterfaceTypes = new ArrayList<TypeInfo>(); 309 } 310 311 mRealInterfaceTypes.add(type); 312 } 313 314 public String name() { 315 return mName; 316 } 317 318 public String[] nameParts() { 319 return mNameParts; 320 } 321 322 public String leafName() { 323 return mNameParts[mNameParts.length - 1]; 324 } 325 326 public String qualifiedName() { 327 return mQualifiedName; 328 } 329 330 public String qualifiedTypeName() { 331 return mQualifiedTypeName; 332 } 333 334 public boolean isPrimitive() { 335 return mIsPrimitive; 336 } 337 338 public ArrayList<MethodInfo> allConstructors() { 339 return mAllConstructors; 340 } 341 342 public ArrayList<MethodInfo> constructors() { 343 if (mConstructors == null) { 344 if (mAllConstructors == null) { 345 return new ArrayList<MethodInfo>(); 346 } 347 348 mConstructors = new ArrayList<MethodInfo>(); 349 for (MethodInfo m : mAllConstructors) { 350 if (!m.isHidden()) { 351 mConstructors.add(m); 352 } 353 } 354 355 Collections.sort(mConstructors, MethodInfo.comparator); 356 } 357 return mConstructors; 358 } 359 360 public ArrayList<ClassInfo> innerClasses() { 361 return mInnerClasses; 362 } 363 364 public TagInfo[] inlineTags() { 365 return comment().tags(); 366 } 367 368 public TagInfo[] firstSentenceTags() { 369 return comment().briefTags(); 370 } 371 372 public void setDeprecated(boolean deprecated) { 373 mDeprecatedKnown = true; 374 mIsDeprecated = deprecated; 375 } 376 377 public boolean isDeprecated() { 378 if (!mDeprecatedKnown) { 379 boolean commentDeprecated = comment().isDeprecated(); 380 boolean annotationDeprecated = false; 381 for (AnnotationInstanceInfo annotation : annotations()) { 382 if (annotation.type().qualifiedName().equals("java.lang.Deprecated")) { 383 annotationDeprecated = true; 384 break; 385 } 386 } 387 388 if (commentDeprecated != annotationDeprecated) { 389 Errors.error(Errors.DEPRECATION_MISMATCH, position(), "Class " + qualifiedName() 390 + ": @Deprecated annotation and @deprecated comment do not match"); 391 } 392 393 mIsDeprecated = commentDeprecated | annotationDeprecated; 394 mDeprecatedKnown = true; 395 } 396 return mIsDeprecated; 397 } 398 399 public TagInfo[] deprecatedTags() { 400 // Should we also do the interfaces? 401 return comment().deprecatedTags(); 402 } 403 404 public ArrayList<MethodInfo> methods() { 405 if (mMethods == null) { 406 TreeMap<String, MethodInfo> all = new TreeMap<String, MethodInfo>(); 407 408 ArrayList<ClassInfo> interfaces = interfaces(); 409 for (ClassInfo iface : interfaces) { 410 if (iface != null) { 411 for (MethodInfo method : iface.methods()) { 412 all.put(method.getHashableName(), method); 413 } 414 } 415 } 416 417 ClassInfo superclass = superclass(); 418 if (superclass != null) { 419 for (MethodInfo method : superclass.methods()) { 420 all.put(method.getHashableName(), method); 421 } 422 } 423 424 for (MethodInfo method : selfMethods()) { 425 all.put(method.getHashableName(), method); 426 } 427 428 mMethods = new ArrayList<MethodInfo>(all.values()); 429 Collections.sort(mMethods, MethodInfo.comparator); 430 } 431 return mMethods; 432 } 433 434 public ArrayList<MethodInfo> annotationElements() { 435 return mAnnotationElements; 436 } 437 438 public ArrayList<AnnotationInstanceInfo> annotations() { 439 return mAnnotations; 440 } 441 442 private static void addFields(ClassInfo cl, TreeMap<String, FieldInfo> all) { 443 for (FieldInfo field : cl.fields()) { 444 all.put(field.name(), field); 445 } 446 } 447 448 public ArrayList<FieldInfo> fields() { 449 if (mFields == null) { 450 TreeMap<String, FieldInfo> all = new TreeMap<String, FieldInfo>(); 451 452 for (ClassInfo iface : interfaces()) { 453 addFields(iface, all); 454 } 455 456 ClassInfo superclass = superclass(); 457 if (superclass != null) { 458 addFields(superclass, all); 459 } 460 461 for (FieldInfo field : selfFields()) { 462 if (!field.isHidden()) { 463 all.put(field.name(), field); 464 } 465 } 466 467 mFields = new ArrayList<FieldInfo>(all.values()); 468 } 469 return mFields; 470 } 471 472 public void gatherFields(ClassInfo owner, ClassInfo cl, HashMap<String, FieldInfo> fields) { 473 for (FieldInfo f : cl.selfFields()) { 474 if (f.checkLevel()) { 475 fields.put(f.name(), f.cloneForClass(owner)); 476 } 477 } 478 } 479 480 public ArrayList<FieldInfo> selfFields() { 481 if (mSelfFields == null) { 482 HashMap<String, FieldInfo> fields = new HashMap<String, FieldInfo>(); 483 // our hidden parents 484 if (mRealSuperclass != null && !mRealSuperclass.checkLevel()) { 485 gatherFields(this, mRealSuperclass, fields); 486 } 487 for (ClassInfo iface : mRealInterfaces) { 488 if (!iface.checkLevel()) { 489 gatherFields(this, iface, fields); 490 } 491 } 492 493 for (FieldInfo f : mAllSelfFields) { 494 if (!f.isHidden()) { 495 fields.put(f.name(), f); 496 } 497 } 498 499 mSelfFields = new ArrayList<FieldInfo>(fields.values()); 500 Collections.sort(mSelfFields, FieldInfo.comparator); 501 } 502 return mSelfFields; 503 } 504 505 public ArrayList<FieldInfo> allSelfFields() { 506 return mAllSelfFields; 507 } 508 509 private void gatherMethods(ClassInfo owner, ClassInfo cl, HashMap<String, MethodInfo> methods) { 510 for (MethodInfo m : cl.selfMethods()) { 511 if (m.checkLevel()) { 512 methods.put(m.name() + m.signature(), m.cloneForClass(owner)); 513 } 514 } 515 } 516 517 public ArrayList<MethodInfo> selfMethods() { 518 if (mSelfMethods == null) { 519 HashMap<String, MethodInfo> methods = new HashMap<String, MethodInfo>(); 520 // our hidden parents 521 if (mRealSuperclass != null && !mRealSuperclass.checkLevel()) { 522 gatherMethods(this, mRealSuperclass, methods); 523 } 524 for (ClassInfo iface : mRealInterfaces) { 525 if (!iface.checkLevel()) { 526 gatherMethods(this, iface, methods); 527 } 528 } 529 // mine 530 if (mAllSelfMethods != null) { 531 for (MethodInfo m : mAllSelfMethods) { 532 if (m.checkLevel()) { 533 methods.put(m.name() + m.signature(), m); 534 } 535 } 536 } 537 538 // sort it 539 mSelfMethods = new ArrayList<MethodInfo>(methods.values()); 540 Collections.sort(mSelfMethods, MethodInfo.comparator); 541 } 542 return mSelfMethods; 543 } 544 545 public ArrayList<MethodInfo> allSelfMethods() { 546 return mAllSelfMethods; 547 } 548 549 public void addMethod(MethodInfo method) { 550 mApiCheckMethods.put(method.getHashableName(), method); 551 552 mAllSelfMethods.add(method); 553 mSelfMethods = null; // flush this, hopefully it hasn't been used yet. 554 } 555 556 public void addAnnotationElement(MethodInfo method) { 557 mAnnotationElements.add(method); 558 } 559 560 public void setContainingPackage(PackageInfo pkg) { 561 mContainingPackage = pkg; 562 563 if (mContainingPackage != null) { 564 if (mIsEnum) { 565 mContainingPackage.addEnum(this); 566 } else if (mIsInterface) { 567 mContainingPackage.addInterface(this); 568 } else { 569 mContainingPackage.addOrdinaryClass(this); 570 } 571 } 572 } 573 574 public ArrayList<AttributeInfo> selfAttributes() { 575 if (mSelfAttributes == null) { 576 TreeMap<FieldInfo, AttributeInfo> attrs = new TreeMap<FieldInfo, AttributeInfo>(); 577 578 // the ones in the class comment won't have any methods 579 for (AttrTagInfo tag : comment().attrTags()) { 580 FieldInfo field = tag.reference(); 581 if (field != null) { 582 AttributeInfo attr = attrs.get(field); 583 if (attr == null) { 584 attr = new AttributeInfo(this, field); 585 attrs.put(field, attr); 586 } 587 tag.setAttribute(attr); 588 } 589 } 590 591 // in the methods 592 for (MethodInfo m : selfMethods()) { 593 for (AttrTagInfo tag : m.comment().attrTags()) { 594 FieldInfo field = tag.reference(); 595 if (field != null) { 596 AttributeInfo attr = attrs.get(field); 597 if (attr == null) { 598 attr = new AttributeInfo(this, field); 599 attrs.put(field, attr); 600 } 601 tag.setAttribute(attr); 602 attr.methods.add(m); 603 } 604 } 605 } 606 607 // constructors too 608 for (MethodInfo m : constructors()) { 609 for (AttrTagInfo tag : m.comment().attrTags()) { 610 FieldInfo field = tag.reference(); 611 if (field != null) { 612 AttributeInfo attr = attrs.get(field); 613 if (attr == null) { 614 attr = new AttributeInfo(this, field); 615 attrs.put(field, attr); 616 } 617 tag.setAttribute(attr); 618 attr.methods.add(m); 619 } 620 } 621 } 622 623 mSelfAttributes = new ArrayList<AttributeInfo>(attrs.values()); 624 Collections.sort(mSelfAttributes, AttributeInfo.comparator); 625 } 626 return mSelfAttributes; 627 } 628 629 public ArrayList<FieldInfo> enumConstants() { 630 return mEnumConstants; 631 } 632 633 public ClassInfo superclass() { 634 if (!mSuperclassInit) { 635 if (this.checkLevel()) { 636 // rearrange our little inheritance hierarchy, because we need to hide classes that 637 // don't pass checkLevel 638 ClassInfo superclass = mRealSuperclass; 639 while (superclass != null && !superclass.checkLevel()) { 640 superclass = superclass.mRealSuperclass; 641 } 642 mSuperclass = superclass; 643 } else { 644 mSuperclass = mRealSuperclass; 645 } 646 } 647 return mSuperclass; 648 } 649 650 public ClassInfo realSuperclass() { 651 return mRealSuperclass; 652 } 653 654 /** 655 * always the real superclass, not the collapsed one we get through superclass(), also has the 656 * type parameter info if it's generic. 657 */ 658 public TypeInfo superclassType() { 659 return mRealSuperclassType; 660 } 661 662 public TypeInfo asTypeInfo() { 663 return mTypeInfo; 664 } 665 666 ArrayList<TypeInfo> interfaceTypes() { 667 ArrayList<TypeInfo> types = new ArrayList<TypeInfo>(); 668 for (ClassInfo iface : interfaces()) { 669 types.add(iface.asTypeInfo()); 670 } 671 return types; 672 } 673 674 public String htmlPage() { 675 String s = containingPackage().name(); 676 s = s.replace('.', '/'); 677 s += '/'; 678 s += name(); 679 s += ".html"; 680 s = Doclava.javadocDir + s; 681 return s; 682 } 683 684 /** Even indirectly */ 685 public boolean isDerivedFrom(ClassInfo cl) { 686 return isDerivedFrom(cl.qualifiedName()); 687 } 688 689 /** Even indirectly */ 690 public boolean isDerivedFrom(String qualifiedName) { 691 ClassInfo dad = this.superclass(); 692 if (dad != null) { 693 if (dad.mQualifiedName.equals(qualifiedName)) { 694 return true; 695 } else { 696 if (dad.isDerivedFrom(qualifiedName)) { 697 return true; 698 } 699 } 700 } 701 for (ClassInfo iface : interfaces()) { 702 if (iface.mQualifiedName.equals(qualifiedName)) { 703 return true; 704 } else { 705 if (iface.isDerivedFrom(qualifiedName)) { 706 return true; 707 } 708 } 709 } 710 return false; 711 } 712 713 public void makeKeywordEntries(List<KeywordEntry> keywords) { 714 if (!checkLevel()) { 715 return; 716 } 717 718 String htmlPage = htmlPage(); 719 String qualifiedName = qualifiedName(); 720 721 keywords.add(new KeywordEntry(name(), htmlPage, "class in " + containingPackage().name())); 722 723 ArrayList<FieldInfo> fields = selfFields(); 724 //ArrayList<FieldInfo> enumConstants = enumConstants(); 725 ArrayList<MethodInfo> ctors = constructors(); 726 ArrayList<MethodInfo> methods = selfMethods(); 727 728 // enum constants 729 for (FieldInfo field : enumConstants()) { 730 if (field.checkLevel()) { 731 keywords.add(new KeywordEntry(field.name(), htmlPage + "#" + field.anchor(), 732 "enum constant in " + qualifiedName)); 733 } 734 } 735 736 // constants 737 for (FieldInfo field : fields) { 738 if (field.isConstant() && field.checkLevel()) { 739 keywords.add(new KeywordEntry(field.name(), htmlPage + "#" + field.anchor(), "constant in " 740 + qualifiedName)); 741 } 742 } 743 744 // fields 745 for (FieldInfo field : fields) { 746 if (!field.isConstant() && field.checkLevel()) { 747 keywords.add(new KeywordEntry(field.name(), htmlPage + "#" + field.anchor(), "field in " 748 + qualifiedName)); 749 } 750 } 751 752 // public constructors 753 for (MethodInfo m : ctors) { 754 if (m.isPublic() && m.checkLevel()) { 755 keywords.add(new KeywordEntry(m.prettySignature(), htmlPage + "#" + m.anchor(), 756 "constructor in " + qualifiedName)); 757 } 758 } 759 760 // protected constructors 761 if (Doclava.checkLevel(Doclava.SHOW_PROTECTED)) { 762 for (MethodInfo m : ctors) { 763 if (m.isProtected() && m.checkLevel()) { 764 keywords.add(new KeywordEntry(m.prettySignature(), 765 htmlPage + "#" + m.anchor(), "constructor in " + qualifiedName)); 766 } 767 } 768 } 769 770 // package private constructors 771 if (Doclava.checkLevel(Doclava.SHOW_PACKAGE)) { 772 for (MethodInfo m : ctors) { 773 if (m.isPackagePrivate() && m.checkLevel()) { 774 keywords.add(new KeywordEntry(m.prettySignature(), 775 htmlPage + "#" + m.anchor(), "constructor in " + qualifiedName)); 776 } 777 } 778 } 779 780 // private constructors 781 if (Doclava.checkLevel(Doclava.SHOW_PRIVATE)) { 782 for (MethodInfo m : ctors) { 783 if (m.isPrivate() && m.checkLevel()) { 784 keywords.add(new KeywordEntry(m.name() + m.prettySignature(), 785 htmlPage + "#" + m.anchor(), "constructor in " + qualifiedName)); 786 } 787 } 788 } 789 790 // public methods 791 for (MethodInfo m : methods) { 792 if (m.isPublic() && m.checkLevel()) { 793 keywords.add(new KeywordEntry(m.name() + m.prettySignature(), htmlPage + "#" + m.anchor(), 794 "method in " + qualifiedName)); 795 } 796 } 797 798 // protected methods 799 if (Doclava.checkLevel(Doclava.SHOW_PROTECTED)) { 800 for (MethodInfo m : methods) { 801 if (m.isProtected() && m.checkLevel()) { 802 keywords.add(new KeywordEntry(m.name() + m.prettySignature(), 803 htmlPage + "#" + m.anchor(), "method in " + qualifiedName)); 804 } 805 } 806 } 807 808 // package private methods 809 if (Doclava.checkLevel(Doclava.SHOW_PACKAGE)) { 810 for (MethodInfo m : methods) { 811 if (m.isPackagePrivate() && m.checkLevel()) { 812 keywords.add(new KeywordEntry(m.name() + m.prettySignature(), 813 htmlPage + "#" + m.anchor(), "method in " + qualifiedName)); 814 } 815 } 816 } 817 818 // private methods 819 if (Doclava.checkLevel(Doclava.SHOW_PRIVATE)) { 820 for (MethodInfo m : methods) { 821 if (m.isPrivate() && m.checkLevel()) { 822 keywords.add(new KeywordEntry(m.name() + m.prettySignature(), 823 htmlPage + "#" + m.anchor(), "method in " + qualifiedName)); 824 } 825 } 826 } 827 } 828 829 public void makeLink(Data data, String base) { 830 data.setValue(base + ".label", this.name()); 831 if (!this.isPrimitive() && this.isIncluded() && this.checkLevel()) { 832 data.setValue(base + ".link", this.htmlPage()); 833 } 834 } 835 836 public static void makeLinkListHDF(Data data, String base, ClassInfo[] classes) { 837 final int N = classes.length; 838 for (int i = 0; i < N; i++) { 839 ClassInfo cl = classes[i]; 840 if (cl.checkLevel()) { 841 cl.asTypeInfo().makeHDF(data, base + "." + i); 842 } 843 } 844 } 845 846 /** 847 * Used in lists of this class (packages, nested classes, known subclasses) 848 */ 849 public void makeShortDescrHDF(Data data, String base) { 850 mTypeInfo.makeHDF(data, base + ".type"); 851 data.setValue(base + ".kind", this.kind()); 852 TagInfo.makeHDF(data, base + ".shortDescr", this.firstSentenceTags()); 853 TagInfo.makeHDF(data, base + ".deprecated", deprecatedTags()); 854 data.setValue(base + ".since", getSince()); 855 setFederatedReferences(data, base); 856 } 857 858 /** 859 * Turns into the main class page 860 */ 861 public void makeHDF(Data data) { 862 int i, j, n; 863 String name = name(); 864 String qualified = qualifiedName(); 865 ArrayList<AttributeInfo> selfAttributes = selfAttributes(); 866 ArrayList<MethodInfo> methods = selfMethods(); 867 ArrayList<FieldInfo> fields = selfFields(); 868 ArrayList<FieldInfo> enumConstants = enumConstants(); 869 ArrayList<MethodInfo> ctors = constructors(); 870 ArrayList<ClassInfo> inners = innerClasses(); 871 872 // class name 873 mTypeInfo.makeHDF(data, "class.type"); 874 mTypeInfo.makeQualifiedHDF(data, "class.qualifiedType"); 875 data.setValue("class.name", name); 876 data.setValue("class.qualified", qualified); 877 if (isProtected()) { 878 data.setValue("class.scope", "protected"); 879 } else if (isPublic()) { 880 data.setValue("class.scope", "public"); 881 } 882 if (isStatic()) { 883 data.setValue("class.static", "static"); 884 } 885 if (isFinal()) { 886 data.setValue("class.final", "final"); 887 } 888 if (isAbstract() && !isInterface()) { 889 data.setValue("class.abstract", "abstract"); 890 } 891 892 // class info 893 String kind = kind(); 894 if (kind != null) { 895 data.setValue("class.kind", kind); 896 } 897 data.setValue("class.since", getSince()); 898 setFederatedReferences(data, "class"); 899 900 // the containing package -- note that this can be passed to type_link, 901 // but it also contains the list of all of the packages 902 containingPackage().makeClassLinkListHDF(data, "class.package"); 903 904 // inheritance hierarchy 905 Vector<ClassInfo> superClasses = new Vector<ClassInfo>(); 906 superClasses.add(this); 907 ClassInfo supr = superclass(); 908 while (supr != null) { 909 superClasses.add(supr); 910 supr = supr.superclass(); 911 } 912 n = superClasses.size(); 913 for (i = 0; i < n; i++) { 914 supr = superClasses.elementAt(n - i - 1); 915 916 supr.asTypeInfo().makeQualifiedHDF(data, "class.inheritance." + i + ".class"); 917 supr.asTypeInfo().makeHDF(data, "class.inheritance." + i + ".short_class"); 918 j = 0; 919 for (TypeInfo t : supr.interfaceTypes()) { 920 t.makeHDF(data, "class.inheritance." + i + ".interfaces." + j); 921 j++; 922 } 923 } 924 925 // class description 926 TagInfo.makeHDF(data, "class.descr", inlineTags()); 927 TagInfo.makeHDF(data, "class.seeAlso", comment().seeTags()); 928 TagInfo.makeHDF(data, "class.deprecated", deprecatedTags()); 929 930 // known subclasses 931 TreeMap<String, ClassInfo> direct = new TreeMap<String, ClassInfo>(); 932 TreeMap<String, ClassInfo> indirect = new TreeMap<String, ClassInfo>(); 933 ClassInfo[] all = Converter.rootClasses(); 934 for (ClassInfo cl : all) { 935 if (cl.superclass() != null && cl.superclass().equals(this)) { 936 direct.put(cl.name(), cl); 937 } else if (cl.isDerivedFrom(this)) { 938 indirect.put(cl.name(), cl); 939 } 940 } 941 // direct 942 i = 0; 943 for (ClassInfo cl : direct.values()) { 944 if (cl.checkLevel()) { 945 cl.makeShortDescrHDF(data, "class.subclasses.direct." + i); 946 } 947 i++; 948 } 949 // indirect 950 i = 0; 951 for (ClassInfo cl : indirect.values()) { 952 if (cl.checkLevel()) { 953 cl.makeShortDescrHDF(data, "class.subclasses.indirect." + i); 954 } 955 i++; 956 } 957 958 // hide special cases 959 if ("java.lang.Object".equals(qualified) || "java.io.Serializable".equals(qualified)) { 960 data.setValue("class.subclasses.hidden", "1"); 961 } else { 962 data.setValue("class.subclasses.hidden", "0"); 963 } 964 965 // nested classes 966 i = 0; 967 for (ClassInfo inner : inners) { 968 if (inner.checkLevel()) { 969 inner.makeShortDescrHDF(data, "class.inners." + i); 970 } 971 i++; 972 } 973 974 // enum constants 975 i = 0; 976 for (FieldInfo field : enumConstants) { 977 field.makeHDF(data, "class.enumConstants." + i); 978 i++; 979 } 980 981 // constants 982 i = 0; 983 for (FieldInfo field : fields) { 984 if (field.isConstant()) { 985 field.makeHDF(data, "class.constants." + i); 986 i++; 987 } 988 } 989 990 // fields 991 i = 0; 992 for (FieldInfo field : fields) { 993 if (!field.isConstant()) { 994 field.makeHDF(data, "class.fields." + i); 995 i++; 996 } 997 } 998 999 // public constructors 1000 i = 0; 1001 for (MethodInfo ctor : ctors) { 1002 if (ctor.isPublic()) { 1003 ctor.makeHDF(data, "class.ctors.public." + i); 1004 i++; 1005 } 1006 } 1007 1008 // protected constructors 1009 if (Doclava.checkLevel(Doclava.SHOW_PROTECTED)) { 1010 i = 0; 1011 for (MethodInfo ctor : ctors) { 1012 if (ctor.isProtected()) { 1013 ctor.makeHDF(data, "class.ctors.protected." + i); 1014 i++; 1015 } 1016 } 1017 } 1018 1019 // package private constructors 1020 if (Doclava.checkLevel(Doclava.SHOW_PACKAGE)) { 1021 i = 0; 1022 for (MethodInfo ctor : ctors) { 1023 if (ctor.isPackagePrivate()) { 1024 ctor.makeHDF(data, "class.ctors.package." + i); 1025 i++; 1026 } 1027 } 1028 } 1029 1030 // private constructors 1031 if (Doclava.checkLevel(Doclava.SHOW_PRIVATE)) { 1032 i = 0; 1033 for (MethodInfo ctor : ctors) { 1034 if (ctor.isPrivate()) { 1035 ctor.makeHDF(data, "class.ctors.private." + i); 1036 i++; 1037 } 1038 } 1039 } 1040 1041 // public methods 1042 i = 0; 1043 for (MethodInfo method : methods) { 1044 if (method.isPublic()) { 1045 method.makeHDF(data, "class.methods.public." + i); 1046 i++; 1047 } 1048 } 1049 1050 // protected methods 1051 if (Doclava.checkLevel(Doclava.SHOW_PROTECTED)) { 1052 i = 0; 1053 for (MethodInfo method : methods) { 1054 if (method.isProtected()) { 1055 method.makeHDF(data, "class.methods.protected." + i); 1056 i++; 1057 } 1058 } 1059 } 1060 1061 // package private methods 1062 if (Doclava.checkLevel(Doclava.SHOW_PACKAGE)) { 1063 i = 0; 1064 for (MethodInfo method : methods) { 1065 if (method.isPackagePrivate()) { 1066 method.makeHDF(data, "class.methods.package." + i); 1067 i++; 1068 } 1069 } 1070 } 1071 1072 // private methods 1073 if (Doclava.checkLevel(Doclava.SHOW_PRIVATE)) { 1074 i = 0; 1075 for (MethodInfo method : methods) { 1076 if (method.isPrivate()) { 1077 method.makeHDF(data, "class.methods.private." + i); 1078 i++; 1079 } 1080 } 1081 } 1082 1083 // xml attributes 1084 i = 0; 1085 for (AttributeInfo attr : selfAttributes) { 1086 if (attr.checkLevel()) { 1087 attr.makeHDF(data, "class.attrs." + i); 1088 i++; 1089 } 1090 } 1091 1092 // inherited methods 1093 Set<ClassInfo> interfaces = new TreeSet<ClassInfo>(); 1094 addInterfaces(interfaces(), interfaces); 1095 ClassInfo cl = superclass(); 1096 i = 0; 1097 while (cl != null) { 1098 addInterfaces(cl.interfaces(), interfaces); 1099 makeInheritedHDF(data, i, cl); 1100 cl = cl.superclass(); 1101 i++; 1102 } 1103 for (ClassInfo iface : interfaces) { 1104 makeInheritedHDF(data, i, iface); 1105 i++; 1106 } 1107 } 1108 1109 private static void addInterfaces(ArrayList<ClassInfo> ifaces, Set<ClassInfo> out) { 1110 for (ClassInfo cl : ifaces) { 1111 out.add(cl); 1112 addInterfaces(cl.interfaces(), out); 1113 } 1114 } 1115 1116 private static void makeInheritedHDF(Data data, int index, ClassInfo cl) { 1117 int i; 1118 1119 String base = "class.inherited." + index; 1120 data.setValue(base + ".qualified", cl.qualifiedName()); 1121 if (cl.checkLevel()) { 1122 data.setValue(base + ".link", cl.htmlPage()); 1123 } 1124 String kind = cl.kind(); 1125 if (kind != null) { 1126 data.setValue(base + ".kind", kind); 1127 } 1128 1129 if (cl.mIsIncluded) { 1130 data.setValue(base + ".included", "true"); 1131 } else { 1132 Doclava.federationTagger.tagAll(new ClassInfo[] {cl}); 1133 if (!cl.getFederatedReferences().isEmpty()) { 1134 FederatedSite site = cl.getFederatedReferences().iterator().next(); 1135 data.setValue(base + ".link", site.linkFor(cl.htmlPage())); 1136 data.setValue(base + ".federated", site.name()); 1137 } 1138 } 1139 1140 // xml attributes 1141 i = 0; 1142 for (AttributeInfo attr : cl.selfAttributes()) { 1143 attr.makeHDF(data, base + ".attrs." + i); 1144 i++; 1145 } 1146 1147 // methods 1148 i = 0; 1149 for (MethodInfo method : cl.selfMethods()) { 1150 method.makeHDF(data, base + ".methods." + i); 1151 i++; 1152 } 1153 1154 // fields 1155 i = 0; 1156 for (FieldInfo field : cl.selfFields()) { 1157 if (!field.isConstant()) { 1158 field.makeHDF(data, base + ".fields." + i); 1159 i++; 1160 } 1161 } 1162 1163 // constants 1164 i = 0; 1165 for (FieldInfo field : cl.selfFields()) { 1166 if (field.isConstant()) { 1167 field.makeHDF(data, base + ".constants." + i); 1168 i++; 1169 } 1170 } 1171 } 1172 1173 @Override 1174 public boolean isHidden() { 1175 int val = mHidden; 1176 if (val >= 0) { 1177 return val != 0; 1178 } else { 1179 boolean v = isHiddenImpl(); 1180 mHidden = v ? 1 : 0; 1181 return v; 1182 } 1183 } 1184 1185 public boolean isHiddenImpl() { 1186 ClassInfo cl = this; 1187 while (cl != null) { 1188 PackageInfo pkg = cl.containingPackage(); 1189 if (pkg != null && pkg.isHidden()) { 1190 return true; 1191 } 1192 if (cl.comment().isHidden()) { 1193 return true; 1194 } 1195 cl = cl.containingClass(); 1196 } 1197 return false; 1198 } 1199 1200 private MethodInfo matchMethod(ArrayList<MethodInfo> methods, String name, String[] params, 1201 String[] dimensions, boolean varargs) { 1202 for (MethodInfo method : methods) { 1203 if (method.name().equals(name)) { 1204 if (params == null) { 1205 return method; 1206 } else { 1207 if (method.matchesParams(params, dimensions, varargs)) { 1208 return method; 1209 } 1210 } 1211 } 1212 } 1213 return null; 1214 } 1215 1216 public MethodInfo findMethod(String name, String[] params, String[] dimensions, boolean varargs) { 1217 // first look on our class, and our superclasses 1218 1219 // for methods 1220 MethodInfo rv; 1221 rv = matchMethod(methods(), name, params, dimensions, varargs); 1222 1223 if (rv != null) { 1224 return rv; 1225 } 1226 1227 // for constructors 1228 rv = matchMethod(constructors(), name, params, dimensions, varargs); 1229 if (rv != null) { 1230 return rv; 1231 } 1232 1233 // then recursively look at our containing class 1234 ClassInfo containing = containingClass(); 1235 if (containing != null) { 1236 return containing.findMethod(name, params, dimensions, varargs); 1237 } 1238 1239 return null; 1240 } 1241 1242 public boolean supportsMethod(MethodInfo method) { 1243 for (MethodInfo m : methods()) { 1244 if (m.getHashableName().equals(method.getHashableName())) { 1245 return true; 1246 } 1247 } 1248 return false; 1249 } 1250 1251 private ClassInfo searchInnerClasses(String[] nameParts, int index) { 1252 String part = nameParts[index]; 1253 1254 ArrayList<ClassInfo> inners = mInnerClasses; 1255 for (ClassInfo in : inners) { 1256 String[] innerParts = in.nameParts(); 1257 if (part.equals(innerParts[innerParts.length - 1])) { 1258 if (index == nameParts.length - 1) { 1259 return in; 1260 } else { 1261 return in.searchInnerClasses(nameParts, index + 1); 1262 } 1263 } 1264 } 1265 return null; 1266 } 1267 1268 public ClassInfo extendedFindClass(String className) { 1269 // ClassDoc.findClass has this bug that we're working around here: 1270 // If you have a class PackageManager with an inner class PackageInfo 1271 // and you call it with "PackageInfo" it doesn't find it. 1272 return searchInnerClasses(className.split("\\."), 0); 1273 } 1274 1275 public ClassInfo findClass(String className) { 1276 return Converter.obtainClass(mClass.findClass(className)); 1277 } 1278 1279 public ClassInfo findInnerClass(String className) { 1280 // ClassDoc.findClass won't find inner classes. To deal with that, 1281 // we try what they gave us first, but if that didn't work, then 1282 // we see if there are any periods in className, and start searching 1283 // from there. 1284 String[] nodes = className.split("\\."); 1285 ClassDoc cl = mClass; 1286 for (String n : nodes) { 1287 cl = cl.findClass(n); 1288 if (cl == null) { 1289 return null; 1290 } 1291 } 1292 return Converter.obtainClass(cl); 1293 } 1294 1295 public FieldInfo findField(String name) { 1296 // first look on our class, and our superclasses 1297 for (FieldInfo f : fields()) { 1298 if (f.name().equals(name)) { 1299 return f; 1300 } 1301 } 1302 1303 // then look at our enum constants (these are really fields, maybe 1304 // they should be mixed into fields(). not sure) 1305 for (FieldInfo f : enumConstants()) { 1306 if (f.name().equals(name)) { 1307 return f; 1308 } 1309 } 1310 1311 // then recursively look at our containing class 1312 ClassInfo containing = containingClass(); 1313 if (containing != null) { 1314 return containing.findField(name); 1315 } 1316 1317 return null; 1318 } 1319 1320 public static ClassInfo[] sortByName(ClassInfo[] classes) { 1321 int i; 1322 Sorter[] sorted = new Sorter[classes.length]; 1323 for (i = 0; i < sorted.length; i++) { 1324 ClassInfo cl = classes[i]; 1325 sorted[i] = new Sorter(cl.name(), cl); 1326 } 1327 1328 Arrays.sort(sorted); 1329 1330 ClassInfo[] rv = new ClassInfo[classes.length]; 1331 for (i = 0; i < rv.length; i++) { 1332 rv[i] = (ClassInfo) sorted[i].data; 1333 } 1334 1335 return rv; 1336 } 1337 1338 public boolean equals(ClassInfo that) { 1339 if (that != null) { 1340 return this.qualifiedName().equals(that.qualifiedName()); 1341 } else { 1342 return false; 1343 } 1344 } 1345 1346 public void setNonWrittenConstructors(ArrayList<MethodInfo> nonWritten) { 1347 mNonWrittenConstructors = nonWritten; 1348 } 1349 1350 public ArrayList<MethodInfo> getNonWrittenConstructors() { 1351 return mNonWrittenConstructors; 1352 } 1353 1354 public String kind() { 1355 if (isOrdinaryClass()) { 1356 return "class"; 1357 } else if (isInterface()) { 1358 return "interface"; 1359 } else if (isEnum()) { 1360 return "enum"; 1361 } else if (isError()) { 1362 return "class"; 1363 } else if (isException()) { 1364 return "class"; 1365 } else if (isAnnotation()) { 1366 return "@interface"; 1367 } 1368 return null; 1369 } 1370 1371 public String scope() { 1372 if (isPublic()) { 1373 return "public"; 1374 } else if (isProtected()) { 1375 return "protected"; 1376 } else if (isPackagePrivate()) { 1377 return ""; 1378 } else if (isPrivate()) { 1379 return "private"; 1380 } else { 1381 throw new RuntimeException("invalid scope for object " + this); 1382 } 1383 } 1384 1385 public void setHiddenMethods(ArrayList<MethodInfo> mInfo) { 1386 mHiddenMethods = mInfo; 1387 } 1388 1389 public ArrayList<MethodInfo> getHiddenMethods() { 1390 return mHiddenMethods; 1391 } 1392 1393 @Override 1394 public String toString() { 1395 return this.qualifiedName(); 1396 } 1397 1398 public void setReasonIncluded(String reason) { 1399 mReasonIncluded = reason; 1400 } 1401 1402 public String getReasonIncluded() { 1403 return mReasonIncluded; 1404 } 1405 1406 private ClassDoc mClass; 1407 1408 // ctor 1409 private boolean mIsPublic; 1410 private boolean mIsProtected; 1411 private boolean mIsPackagePrivate; 1412 private boolean mIsPrivate; 1413 private boolean mIsStatic; 1414 private boolean mIsInterface; 1415 private boolean mIsAbstract; 1416 private boolean mIsOrdinaryClass; 1417 private boolean mIsException; 1418 private boolean mIsError; 1419 private boolean mIsEnum; 1420 private boolean mIsAnnotation; 1421 private boolean mIsFinal; 1422 private boolean mIsIncluded; 1423 private String mName; 1424 private String mQualifiedName; 1425 private String mQualifiedTypeName; 1426 private boolean mIsPrimitive; 1427 private TypeInfo mTypeInfo; 1428 private String[] mNameParts; 1429 1430 // init 1431 private ArrayList<ClassInfo> mRealInterfaces = new ArrayList<ClassInfo>(); 1432 private ArrayList<ClassInfo> mInterfaces; 1433 private ArrayList<TypeInfo> mRealInterfaceTypes; 1434 private ArrayList<ClassInfo> mInnerClasses; 1435 private ArrayList<MethodInfo> mAllConstructors = new ArrayList<MethodInfo>(); 1436 private ArrayList<MethodInfo> mAllSelfMethods = new ArrayList<MethodInfo>(); 1437 private ArrayList<MethodInfo> mAnnotationElements = new ArrayList<MethodInfo>(); // if this class is an annotation 1438 private ArrayList<FieldInfo> mAllSelfFields = new ArrayList<FieldInfo>(); 1439 private ArrayList<FieldInfo> mEnumConstants = new ArrayList<FieldInfo>(); 1440 private PackageInfo mContainingPackage; 1441 private ClassInfo mContainingClass; 1442 private ClassInfo mRealSuperclass; 1443 private TypeInfo mRealSuperclassType; 1444 private ClassInfo mSuperclass; 1445 private ArrayList<AnnotationInstanceInfo> mAnnotations; 1446 private boolean mSuperclassInit; 1447 private boolean mDeprecatedKnown; 1448 1449 // lazy 1450 private ArrayList<MethodInfo> mConstructors; 1451 private ArrayList<ClassInfo> mRealInnerClasses; 1452 private ArrayList<MethodInfo> mSelfMethods; 1453 private ArrayList<FieldInfo> mSelfFields; 1454 private ArrayList<AttributeInfo> mSelfAttributes; 1455 private ArrayList<MethodInfo> mMethods; 1456 private ArrayList<FieldInfo> mFields; 1457 private ArrayList<TypeInfo> mTypeParameters; 1458 private ArrayList<MethodInfo> mHiddenMethods; 1459 private int mHidden = -1; 1460 private int mCheckLevel = -1; 1461 private String mReasonIncluded; 1462 private ArrayList<MethodInfo> mNonWrittenConstructors; 1463 private boolean mIsDeprecated; 1464 1465 // TODO: Temporary members from apicheck migration. 1466 private HashMap<String, MethodInfo> mApiCheckConstructors = new HashMap<String, MethodInfo>(); 1467 private HashMap<String, MethodInfo> mApiCheckMethods = new HashMap<String, MethodInfo>(); 1468 private HashMap<String, FieldInfo> mApiCheckFields = new HashMap<String, FieldInfo>(); 1469 private HashMap<String, FieldInfo> mApiCheckEnumConstants = new HashMap<String, FieldInfo>(); 1470 1471 // Resolutions 1472 private ArrayList<Resolution> mResolutions; 1473 1474 /** 1475 * Returns true if {@code cl} implements the interface {@code iface} either by either being that 1476 * interface, implementing that interface or extending a type that implements the interface. 1477 */ 1478 private boolean implementsInterface(ClassInfo cl, String iface) { 1479 if (cl.qualifiedName().equals(iface)) { 1480 return true; 1481 } 1482 for (ClassInfo clImplements : cl.interfaces()) { 1483 if (implementsInterface(clImplements, iface)) { 1484 return true; 1485 } 1486 } 1487 if (cl.mSuperclass != null && implementsInterface(cl.mSuperclass, iface)) { 1488 return true; 1489 } 1490 return false; 1491 } 1492 1493 public void addInterface(ClassInfo iface) { 1494 mRealInterfaces.add(iface); 1495 } 1496 1497 public void addConstructor(MethodInfo ctor) { 1498 mApiCheckConstructors.put(ctor.getHashableName(), ctor); 1499 1500 mAllConstructors.add(ctor); 1501 mConstructors = null; // flush this, hopefully it hasn't been used yet. 1502 } 1503 1504 public void addField(FieldInfo field) { 1505 mApiCheckFields.put(field.name(), field); 1506 1507 mAllSelfFields.add(field); 1508 1509 mSelfFields = null; // flush this, hopefully it hasn't been used yet. 1510 } 1511 1512 public void addEnumConstant(FieldInfo field) { 1513 mApiCheckEnumConstants.put(field.name(), field); 1514 1515 mEnumConstants.add(field); 1516 } 1517 1518 public void setSuperClass(ClassInfo superclass) { 1519 mRealSuperclass = superclass; 1520 mSuperclass = superclass; 1521 } 1522 1523 public Map<String, MethodInfo> allConstructorsMap() { 1524 return mApiCheckConstructors; 1525 } 1526 1527 public Map<String, FieldInfo> allFields() { 1528 return mApiCheckFields; 1529 } 1530 1531 /** 1532 * Returns all methods defined directly in this class. For a list of all 1533 * methods supported by this class, see {@link #methods()}. 1534 */ 1535 1536 public Map<String, MethodInfo> allMethods() { 1537 return mApiCheckMethods; 1538 } 1539 1540 /** 1541 * Returns the class hierarchy for this class, starting with this class. 1542 */ 1543 public Iterable<ClassInfo> hierarchy() { 1544 List<ClassInfo> result = new ArrayList<ClassInfo>(4); 1545 for (ClassInfo c = this; c != null; c = c.mSuperclass) { 1546 result.add(c); 1547 } 1548 return result; 1549 } 1550 1551 public String superclassName() { 1552 if (mSuperclass == null) { 1553 if (mQualifiedName.equals("java.lang.Object")) { 1554 return null; 1555 } 1556 throw new UnsupportedOperationException("Superclass not set for " + qualifiedName()); 1557 } 1558 return mSuperclass.mQualifiedName; 1559 } 1560 1561 public void setAnnotations(ArrayList<AnnotationInstanceInfo> annotations) { 1562 mAnnotations = annotations; 1563 } 1564 1565 public boolean isConsistent(ClassInfo cl) { 1566 boolean consistent = true; 1567 1568 if (isInterface() != cl.isInterface()) { 1569 Errors.error(Errors.CHANGED_CLASS, cl.position(), "Class " + cl.qualifiedName() 1570 + " changed class/interface declaration"); 1571 consistent = false; 1572 } 1573 for (ClassInfo iface : mRealInterfaces) { 1574 if (!implementsInterface(cl, iface.mQualifiedName)) { 1575 Errors.error(Errors.REMOVED_INTERFACE, cl.position(), "Class " + qualifiedName() 1576 + " no longer implements " + iface); 1577 } 1578 } 1579 for (ClassInfo iface : cl.mRealInterfaces) { 1580 if (!implementsInterface(this, iface.mQualifiedName)) { 1581 Errors.error(Errors.ADDED_INTERFACE, cl.position(), "Added interface " + iface 1582 + " to class " + qualifiedName()); 1583 consistent = false; 1584 } 1585 } 1586 1587 for (MethodInfo mInfo : mApiCheckMethods.values()) { 1588 if (cl.mApiCheckMethods.containsKey(mInfo.getHashableName())) { 1589 if (!mInfo.isConsistent(cl.mApiCheckMethods.get(mInfo.getHashableName()))) { 1590 consistent = false; 1591 } 1592 } else { 1593 /* 1594 * This class formerly provided this method directly, and now does not. Check our ancestry 1595 * to see if there's an inherited version that still fulfills the API requirement. 1596 */ 1597 MethodInfo mi = ClassInfo.overriddenMethod(mInfo, cl); 1598 if (mi == null) { 1599 mi = ClassInfo.interfaceMethod(mInfo, cl); 1600 } 1601 if (mi == null) { 1602 Errors.error(Errors.REMOVED_METHOD, mInfo.position(), "Removed public method " 1603 + mInfo.qualifiedName()); 1604 consistent = false; 1605 } 1606 } 1607 } 1608 for (MethodInfo mInfo : cl.mApiCheckMethods.values()) { 1609 if (!mApiCheckMethods.containsKey(mInfo.getHashableName())) { 1610 /* 1611 * Similarly to the above, do not fail if this "new" method is really an override of an 1612 * existing superclass method. 1613 */ 1614 MethodInfo mi = ClassInfo.overriddenMethod(mInfo, this); 1615 if (mi == null) { 1616 Errors.error(Errors.ADDED_METHOD, mInfo.position(), "Added public method " 1617 + mInfo.qualifiedName()); 1618 consistent = false; 1619 } 1620 } 1621 } 1622 1623 for (MethodInfo mInfo : mApiCheckConstructors.values()) { 1624 if (cl.mApiCheckConstructors.containsKey(mInfo.getHashableName())) { 1625 if (!mInfo.isConsistent(cl.mApiCheckConstructors.get(mInfo.getHashableName()))) { 1626 consistent = false; 1627 } 1628 } else { 1629 Errors.error(Errors.REMOVED_METHOD, mInfo.position(), "Removed public constructor " 1630 + mInfo.prettySignature()); 1631 consistent = false; 1632 } 1633 } 1634 for (MethodInfo mInfo : cl.mApiCheckConstructors.values()) { 1635 if (!mApiCheckConstructors.containsKey(mInfo.getHashableName())) { 1636 Errors.error(Errors.ADDED_METHOD, mInfo.position(), "Added public constructor " 1637 + mInfo.prettySignature()); 1638 consistent = false; 1639 } 1640 } 1641 1642 for (FieldInfo mInfo : mApiCheckFields.values()) { 1643 if (cl.mApiCheckFields.containsKey(mInfo.name())) { 1644 if (!mInfo.isConsistent(cl.mApiCheckFields.get(mInfo.name()))) { 1645 consistent = false; 1646 } 1647 } else { 1648 Errors.error(Errors.REMOVED_FIELD, mInfo.position(), "Removed field " 1649 + mInfo.qualifiedName()); 1650 consistent = false; 1651 } 1652 } 1653 for (FieldInfo mInfo : cl.mApiCheckFields.values()) { 1654 if (!mApiCheckFields.containsKey(mInfo.name())) { 1655 Errors.error(Errors.ADDED_FIELD, mInfo.position(), "Added public field " 1656 + mInfo.qualifiedName()); 1657 consistent = false; 1658 } 1659 } 1660 1661 for (FieldInfo info : mApiCheckEnumConstants.values()) { 1662 if (cl.mApiCheckEnumConstants.containsKey(info.name())) { 1663 if (!info.isConsistent(cl.mApiCheckEnumConstants.get(info.name()))) { 1664 consistent = false; 1665 } 1666 } else { 1667 Errors.error(Errors.REMOVED_FIELD, info.position(), "Removed enum constant " 1668 + info.qualifiedName()); 1669 consistent = false; 1670 } 1671 } 1672 for (FieldInfo info : cl.mApiCheckEnumConstants.values()) { 1673 if (!mApiCheckEnumConstants.containsKey(info.name())) { 1674 Errors.error(Errors.ADDED_FIELD, info.position(), "Added enum constant " 1675 + info.qualifiedName()); 1676 consistent = false; 1677 } 1678 } 1679 1680 if (mIsAbstract != cl.mIsAbstract) { 1681 consistent = false; 1682 Errors.error(Errors.CHANGED_ABSTRACT, cl.position(), "Class " + cl.qualifiedName() 1683 + " changed abstract qualifier"); 1684 } 1685 1686 if (mIsFinal != cl.mIsFinal) { 1687 consistent = false; 1688 Errors.error(Errors.CHANGED_FINAL, cl.position(), "Class " + cl.qualifiedName() 1689 + " changed final qualifier"); 1690 } 1691 1692 if (mIsStatic != cl.mIsStatic) { 1693 consistent = false; 1694 Errors.error(Errors.CHANGED_STATIC, cl.position(), "Class " + cl.qualifiedName() 1695 + " changed static qualifier"); 1696 } 1697 1698 if (!scope().equals(cl.scope())) { 1699 consistent = false; 1700 Errors.error(Errors.CHANGED_SCOPE, cl.position(), "Class " + cl.qualifiedName() 1701 + " scope changed from " + scope() + " to " + cl.scope()); 1702 } 1703 1704 if (!isDeprecated() == cl.isDeprecated()) { 1705 consistent = false; 1706 Errors.error(Errors.CHANGED_DEPRECATED, cl.position(), "Class " + cl.qualifiedName() 1707 + " has changed deprecation state"); 1708 } 1709 1710 if (superclassName() != null) { 1711 if (cl.superclassName() == null || !superclassName().equals(cl.superclassName())) { 1712 consistent = false; 1713 Errors.error(Errors.CHANGED_SUPERCLASS, cl.position(), "Class " + qualifiedName() 1714 + " superclass changed from " + superclassName() + " to " + cl.superclassName()); 1715 } 1716 } else if (cl.superclassName() != null) { 1717 consistent = false; 1718 Errors.error(Errors.CHANGED_SUPERCLASS, cl.position(), "Class " + qualifiedName() 1719 + " superclass changed from " + "null to " + cl.superclassName()); 1720 } 1721 1722 return consistent; 1723 } 1724 1725 // Find a superclass implementation of the given method. 1726 public static MethodInfo overriddenMethod(MethodInfo candidate, ClassInfo newClassObj) { 1727 if (newClassObj == null) { 1728 return null; 1729 } 1730 for (MethodInfo mi : newClassObj.mApiCheckMethods.values()) { 1731 if (mi.matches(candidate)) { 1732 // found it 1733 return mi; 1734 } 1735 } 1736 1737 // not found here. recursively search ancestors 1738 return ClassInfo.overriddenMethod(candidate, newClassObj.mSuperclass); 1739 } 1740 1741 // Find a superinterface declaration of the given method. 1742 public static MethodInfo interfaceMethod(MethodInfo candidate, ClassInfo newClassObj) { 1743 if (newClassObj == null) { 1744 return null; 1745 } 1746 for (ClassInfo interfaceInfo : newClassObj.interfaces()) { 1747 for (MethodInfo mi : interfaceInfo.mApiCheckMethods.values()) { 1748 if (mi.matches(candidate)) { 1749 return mi; 1750 } 1751 } 1752 } 1753 return ClassInfo.interfaceMethod(candidate, newClassObj.mSuperclass); 1754 } 1755 1756 public boolean hasConstructor(MethodInfo constructor) { 1757 String name = constructor.getHashableName(); 1758 for (MethodInfo ctor : mApiCheckConstructors.values()) { 1759 if (name.equals(ctor.getHashableName())) { 1760 return true; 1761 } 1762 } 1763 return false; 1764 } 1765 1766 public void setTypeInfo(TypeInfo typeInfo) { 1767 mTypeInfo = typeInfo; 1768 } 1769 1770 public TypeInfo type() { 1771 return mTypeInfo; 1772 } 1773 1774 public void addInnerClass(ClassInfo innerClass) { 1775 if (mInnerClasses == null) { 1776 mInnerClasses = new ArrayList<ClassInfo>(); 1777 } 1778 1779 mInnerClasses.add(innerClass); 1780 } 1781 1782 public void setContainingClass(ClassInfo containingClass) { 1783 mContainingClass = containingClass; 1784 } 1785 1786 public void setSuperclassType(TypeInfo superclassType) { 1787 mRealSuperclassType = superclassType; 1788 } 1789 1790 public void printResolutions() { 1791 if (mResolutions == null || mResolutions.isEmpty()) { 1792 return; 1793 } 1794 1795 System.out.println("Resolutions for Class " + mName + ":"); 1796 1797 for (Resolution r : mResolutions) { 1798 System.out.println(r); 1799 } 1800 } 1801 1802 public void addResolution(Resolution resolution) { 1803 if (mResolutions == null) { 1804 mResolutions = new ArrayList<Resolution>(); 1805 } 1806 1807 mResolutions.add(resolution); 1808 } 1809 1810 public boolean resolveResolutions() { 1811 ArrayList<Resolution> resolutions = mResolutions; 1812 mResolutions = new ArrayList<Resolution>(); 1813 1814 boolean allResolved = true; 1815 for (Resolution resolution : resolutions) { 1816 StringBuilder qualifiedClassName = new StringBuilder(); 1817 InfoBuilder.resolveQualifiedName(resolution.getValue(), qualifiedClassName, 1818 resolution.getInfoBuilder()); 1819 1820 // if we still couldn't resolve it, save it for the next pass 1821 if ("".equals(qualifiedClassName.toString())) { 1822 mResolutions.add(resolution); 1823 allResolved = false; 1824 } else if ("superclassQualifiedName".equals(resolution.getVariable())) { 1825 setSuperClass(InfoBuilder.Caches.obtainClass(qualifiedClassName.toString())); 1826 } else if ("interfaceQualifiedName".equals(resolution.getVariable())) { 1827 addInterface(InfoBuilder.Caches.obtainClass(qualifiedClassName.toString())); 1828 } 1829 } 1830 1831 return allResolved; 1832 } 1833 } 1834