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