1 /* 2 * Copyright (C) 2008 The Android Open Source Project 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 import com.sun.javadoc.*; 18 import com.sun.tools.doclets.*; 19 import org.clearsilver.HDF; 20 import org.clearsilver.CS; 21 import java.util.*; 22 import java.io.*; 23 24 public class ClassInfo extends DocInfo implements ContainerInfo, Comparable, Scoped 25 { 26 public static final Comparator<ClassInfo> comparator = new Comparator<ClassInfo>() { 27 public int compare(ClassInfo a, ClassInfo b) { 28 return a.name().compareTo(b.name()); 29 } 30 }; 31 32 public static final Comparator<ClassInfo> qualifiedComparator = new Comparator<ClassInfo>() { 33 public int compare(ClassInfo a, ClassInfo b) { 34 return a.qualifiedName().compareTo(b.qualifiedName()); 35 } 36 }; 37 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)38 public ClassInfo( 39 ClassDoc cl, 40 String rawCommentText, SourcePositionInfo position, 41 boolean isPublic, boolean isProtected, boolean isPackagePrivate, 42 boolean isPrivate, boolean isStatic, 43 boolean isInterface, boolean isAbstract, boolean isOrdinaryClass, 44 boolean isException, boolean isError, boolean isEnum, boolean isAnnotation, 45 boolean isFinal, boolean isIncluded, String name, 46 String qualifiedName, String qualifiedTypeName, boolean isPrimitive) 47 { 48 super(rawCommentText, position); 49 50 mClass = cl; 51 mIsPublic = isPublic; 52 mIsProtected = isProtected; 53 mIsPackagePrivate = isPackagePrivate; 54 mIsPrivate = isPrivate; 55 mIsStatic = isStatic; 56 mIsInterface = isInterface; 57 mIsAbstract = isAbstract; 58 mIsOrdinaryClass = isOrdinaryClass; 59 mIsException = isException; 60 mIsError = isError; 61 mIsEnum = isEnum; 62 mIsAnnotation = isAnnotation; 63 mIsFinal = isFinal; 64 mIsIncluded = isIncluded; 65 mName = name; 66 mQualifiedName = qualifiedName; 67 mQualifiedTypeName = qualifiedTypeName; 68 mIsPrimitive = isPrimitive; 69 mNameParts = name.split("\\."); 70 } 71 init(TypeInfo typeInfo, ClassInfo[] interfaces, TypeInfo[] interfaceTypes, ClassInfo[] innerClasses, MethodInfo[] constructors, MethodInfo[] methods, MethodInfo[] annotationElements, FieldInfo[] fields, FieldInfo[] enumConstants, PackageInfo containingPackage, ClassInfo containingClass, ClassInfo superclass, TypeInfo superclassType, AnnotationInstanceInfo[] annotations)72 public void init(TypeInfo typeInfo, ClassInfo[] interfaces, TypeInfo[] interfaceTypes, 73 ClassInfo[] innerClasses, 74 MethodInfo[] constructors, MethodInfo[] methods, MethodInfo[] annotationElements, 75 FieldInfo[] fields, FieldInfo[] enumConstants, 76 PackageInfo containingPackage, ClassInfo containingClass, 77 ClassInfo superclass, TypeInfo superclassType, AnnotationInstanceInfo[] annotations) 78 { 79 mTypeInfo = typeInfo; 80 mRealInterfaces = interfaces; 81 mRealInterfaceTypes = interfaceTypes; 82 mInnerClasses = innerClasses; 83 mAllConstructors = constructors; 84 mAllSelfMethods = methods; 85 mAnnotationElements = annotationElements; 86 mAllSelfFields = fields; 87 mEnumConstants = enumConstants; 88 mContainingPackage = containingPackage; 89 mContainingClass = containingClass; 90 mRealSuperclass = superclass; 91 mRealSuperclassType = superclassType; 92 mAnnotations = annotations; 93 94 // after providing new methods and new superclass info,clear any cached 95 // lists of self + superclass methods, ctors, etc. 96 mSuperclassInit = false; 97 mConstructors = null; 98 mMethods = null; 99 mSelfMethods = null; 100 mFields = null; 101 mSelfFields = null; 102 mSelfAttributes = null; 103 mDeprecatedKnown = false; 104 105 Arrays.sort(mEnumConstants, FieldInfo.comparator); 106 Arrays.sort(mInnerClasses, ClassInfo.comparator); 107 } 108 init2()109 public void init2() { 110 // calling this here forces the AttrTagInfo objects to be linked to the AttribtueInfo 111 // objects 112 selfAttributes(); 113 } 114 init3(TypeInfo[] types, ClassInfo[] realInnerClasses)115 public void init3(TypeInfo[] types, ClassInfo[] realInnerClasses){ 116 mTypeParameters = types; 117 mRealInnerClasses = realInnerClasses; 118 } 119 getRealInnerClasses()120 public ClassInfo[] getRealInnerClasses(){ 121 return mRealInnerClasses; 122 } 123 getTypeParameters()124 public TypeInfo[] getTypeParameters(){ 125 return mTypeParameters; 126 } 127 checkLevel()128 public boolean checkLevel() 129 { 130 int val = mCheckLevel; 131 if (val >= 0) { 132 return val != 0; 133 } else { 134 boolean v = DroidDoc.checkLevel(mIsPublic, mIsProtected, 135 mIsPackagePrivate, mIsPrivate, isHidden()); 136 mCheckLevel = v ? 1 : 0; 137 return v; 138 } 139 } 140 compareTo(Object that)141 public int compareTo(Object that) { 142 if (that instanceof ClassInfo) { 143 return mQualifiedName.compareTo(((ClassInfo)that).mQualifiedName); 144 } else { 145 return this.hashCode() - that.hashCode(); 146 } 147 } 148 149 @Override parent()150 public ContainerInfo parent() 151 { 152 return this; 153 } 154 isPublic()155 public boolean isPublic() 156 { 157 return mIsPublic; 158 } 159 isProtected()160 public boolean isProtected() 161 { 162 return mIsProtected; 163 } 164 isPackagePrivate()165 public boolean isPackagePrivate() 166 { 167 return mIsPackagePrivate; 168 } 169 isPrivate()170 public boolean isPrivate() 171 { 172 return mIsPrivate; 173 } 174 isStatic()175 public boolean isStatic() 176 { 177 return mIsStatic; 178 } 179 isInterface()180 public boolean isInterface() 181 { 182 return mIsInterface; 183 } 184 isAbstract()185 public boolean isAbstract() 186 { 187 return mIsAbstract; 188 } 189 containingPackage()190 public PackageInfo containingPackage() 191 { 192 return mContainingPackage; 193 } 194 containingClass()195 public ClassInfo containingClass() 196 { 197 return mContainingClass; 198 } 199 isOrdinaryClass()200 public boolean isOrdinaryClass() 201 { 202 return mIsOrdinaryClass; 203 } 204 isException()205 public boolean isException() 206 { 207 return mIsException; 208 } 209 isError()210 public boolean isError() 211 { 212 return mIsError; 213 } 214 isEnum()215 public boolean isEnum() 216 { 217 return mIsEnum; 218 } 219 isAnnotation()220 public boolean isAnnotation() 221 { 222 return mIsAnnotation; 223 } 224 isFinal()225 public boolean isFinal() 226 { 227 return mIsFinal; 228 } 229 isIncluded()230 public boolean isIncluded() 231 { 232 return mIsIncluded; 233 } 234 typeVariables()235 public HashSet<String> typeVariables() 236 { 237 HashSet<String> result = TypeInfo.typeVariables(mTypeInfo.typeArguments()); 238 ClassInfo cl = containingClass(); 239 while (cl != null) { 240 TypeInfo[] types = cl.asTypeInfo().typeArguments(); 241 if (types != null) { 242 TypeInfo.typeVariables(types, result); 243 } 244 cl = cl.containingClass(); 245 } 246 return result; 247 } 248 gatherHiddenInterfaces(ClassInfo cl, HashSet<ClassInfo> interfaces)249 private static void gatherHiddenInterfaces(ClassInfo cl, HashSet<ClassInfo> interfaces) { 250 for (ClassInfo iface: cl.mRealInterfaces) { 251 if (iface.checkLevel()) { 252 interfaces.add(iface); 253 } else { 254 gatherHiddenInterfaces(iface, interfaces); 255 } 256 } 257 } 258 interfaces()259 public ClassInfo[] interfaces() 260 { 261 if (mInterfaces == null) { 262 if (checkLevel()) { 263 HashSet<ClassInfo> interfaces = new HashSet<ClassInfo>(); 264 ClassInfo superclass = mRealSuperclass; 265 while (superclass != null && !superclass.checkLevel()) { 266 gatherHiddenInterfaces(superclass, interfaces); 267 superclass = superclass.mRealSuperclass; 268 } 269 gatherHiddenInterfaces(this, interfaces); 270 mInterfaces = interfaces.toArray(new ClassInfo[interfaces.size()]); 271 } else { 272 // put something here in case someone uses it 273 mInterfaces = mRealInterfaces; 274 } 275 Arrays.sort(mInterfaces, ClassInfo.qualifiedComparator); 276 } 277 return mInterfaces; 278 } 279 realInterfaces()280 public ClassInfo[] realInterfaces() 281 { 282 return mRealInterfaces; 283 } 284 realInterfaceTypes()285 TypeInfo[] realInterfaceTypes() 286 { 287 return mRealInterfaceTypes; 288 } 289 name()290 public String name() 291 { 292 return mName; 293 } 294 nameParts()295 public String[] nameParts() 296 { 297 return mNameParts; 298 } 299 leafName()300 public String leafName() 301 { 302 return mNameParts[mNameParts.length-1]; 303 } 304 qualifiedName()305 public String qualifiedName() 306 { 307 return mQualifiedName; 308 } 309 qualifiedTypeName()310 public String qualifiedTypeName() 311 { 312 return mQualifiedTypeName; 313 } 314 isPrimitive()315 public boolean isPrimitive() 316 { 317 return mIsPrimitive; 318 } 319 allConstructors()320 public MethodInfo[] allConstructors() { 321 return mAllConstructors; 322 } 323 constructors()324 public MethodInfo[] constructors() 325 { 326 if (mConstructors == null) { 327 MethodInfo[] methods = mAllConstructors; 328 ArrayList<MethodInfo> ctors = new ArrayList<MethodInfo>(); 329 for (int i=0; i<methods.length; i++) { 330 MethodInfo m = methods[i]; 331 if (!m.isHidden()) { 332 ctors.add(m); 333 } 334 } 335 mConstructors = ctors.toArray(new MethodInfo[ctors.size()]); 336 Arrays.sort(mConstructors, MethodInfo.comparator); 337 } 338 return mConstructors; 339 } 340 innerClasses()341 public ClassInfo[] innerClasses() 342 { 343 return mInnerClasses; 344 } 345 inlineTags()346 public TagInfo[] inlineTags() 347 { 348 return comment().tags(); 349 } 350 firstSentenceTags()351 public TagInfo[] firstSentenceTags() 352 { 353 return comment().briefTags(); 354 } 355 isDeprecated()356 public boolean isDeprecated() { 357 boolean deprecated = false; 358 if (!mDeprecatedKnown) { 359 boolean commentDeprecated = (comment().deprecatedTags().length > 0); 360 boolean annotationDeprecated = false; 361 for (AnnotationInstanceInfo annotation : annotations()) { 362 if (annotation.type().qualifiedName().equals("java.lang.Deprecated")) { 363 annotationDeprecated = true; 364 break; 365 } 366 } 367 368 if (commentDeprecated != annotationDeprecated) { 369 Errors.error(Errors.DEPRECATION_MISMATCH, position(), 370 "Class " + qualifiedName() 371 + ": @Deprecated annotation and @deprecated comment do not match"); 372 } 373 374 mIsDeprecated = commentDeprecated | annotationDeprecated; 375 mDeprecatedKnown = true; 376 } 377 return mIsDeprecated; 378 } 379 deprecatedTags()380 public TagInfo[] deprecatedTags() 381 { 382 // Should we also do the interfaces? 383 return comment().deprecatedTags(); 384 } 385 methods()386 public MethodInfo[] methods() 387 { 388 if (mMethods == null) { 389 TreeMap<String,MethodInfo> all = new TreeMap<String,MethodInfo>(); 390 391 ClassInfo[] ifaces = interfaces(); 392 for (ClassInfo iface: ifaces) { 393 if (iface != null) { 394 MethodInfo[] inhereted = iface.methods(); 395 for (MethodInfo method: inhereted) { 396 String key = method.name() + method.signature(); 397 all.put(key, method); 398 } 399 } 400 } 401 402 ClassInfo superclass = superclass(); 403 if (superclass != null) { 404 MethodInfo[] inhereted = superclass.methods(); 405 for (MethodInfo method: inhereted) { 406 String key = method.name() + method.signature(); 407 all.put(key, method); 408 } 409 } 410 411 MethodInfo[] methods = selfMethods(); 412 for (MethodInfo method: methods) { 413 String key = method.name() + method.signature(); 414 MethodInfo old = all.put(key, method); 415 } 416 417 mMethods = all.values().toArray(new MethodInfo[all.size()]); 418 } 419 return mMethods; 420 } 421 annotationElements()422 public MethodInfo[] annotationElements() 423 { 424 return mAnnotationElements; 425 } 426 annotations()427 public AnnotationInstanceInfo[] annotations() 428 { 429 return mAnnotations; 430 } 431 addFields(ClassInfo cl, TreeMap<String,FieldInfo> all)432 private static void addFields(ClassInfo cl, TreeMap<String,FieldInfo> all) 433 { 434 FieldInfo[] fields = cl.fields(); 435 int N = fields.length; 436 for (int i=0; i<N; i++) { 437 FieldInfo f = fields[i]; 438 all.put(f.name(), f); 439 } 440 } 441 fields()442 public FieldInfo[] fields() 443 { 444 if (mFields == null) { 445 int N; 446 TreeMap<String,FieldInfo> all = new TreeMap<String,FieldInfo>(); 447 448 ClassInfo[] interfaces = interfaces(); 449 N = interfaces.length; 450 for (int i=0; i<N; i++) { 451 addFields(interfaces[i], all); 452 } 453 454 ClassInfo superclass = superclass(); 455 if (superclass != null) { 456 addFields(superclass, all); 457 } 458 459 FieldInfo[] fields = selfFields(); 460 N = fields.length; 461 for (int i=0; i<N; i++) { 462 FieldInfo f = fields[i]; 463 if (!f.isHidden()) { 464 String key = f.name(); 465 all.put(key, f); 466 } 467 } 468 469 mFields = all.values().toArray(new FieldInfo[0]); 470 } 471 return mFields; 472 } 473 gatherFields(ClassInfo owner, ClassInfo cl, HashMap<String,FieldInfo> fields)474 public void gatherFields(ClassInfo owner, ClassInfo cl, HashMap<String,FieldInfo> fields) { 475 FieldInfo[] flds = cl.selfFields(); 476 for (FieldInfo f: flds) { 477 if (f.checkLevel()) { 478 fields.put(f.name(), f.cloneForClass(owner)); 479 } 480 } 481 } 482 selfFields()483 public FieldInfo[] selfFields() 484 { 485 if (mSelfFields == null) { 486 HashMap<String,FieldInfo> fields = new HashMap<String,FieldInfo>(); 487 // our hidden parents 488 if (mRealSuperclass != null && !mRealSuperclass.checkLevel()) { 489 gatherFields(this, mRealSuperclass, fields); 490 } 491 for (ClassInfo iface: mRealInterfaces) { 492 if (!iface.checkLevel()) { 493 gatherFields(this, iface, fields); 494 } 495 } 496 // mine 497 FieldInfo[] selfFields = mAllSelfFields; 498 for (int i=0; i<selfFields.length; i++) { 499 FieldInfo f = selfFields[i]; 500 if (!f.isHidden()) { 501 fields.put(f.name(), f); 502 } 503 } 504 // combine and return in 505 mSelfFields = fields.values().toArray(new FieldInfo[fields.size()]); 506 Arrays.sort(mSelfFields, FieldInfo.comparator); 507 } 508 return mSelfFields; 509 } 510 allSelfFields()511 public FieldInfo[] allSelfFields() { 512 return mAllSelfFields; 513 } 514 gatherMethods(ClassInfo owner, ClassInfo cl, HashMap<String,MethodInfo> methods)515 public void gatherMethods(ClassInfo owner, ClassInfo cl, HashMap<String,MethodInfo> methods) { 516 MethodInfo[] meth = cl.selfMethods(); 517 for (MethodInfo m: meth) { 518 if (m.checkLevel()) { 519 methods.put(m.name()+m.signature(), m.cloneForClass(owner)); 520 } 521 } 522 } 523 selfMethods()524 public MethodInfo[] selfMethods() 525 { 526 if (mSelfMethods == null) { 527 HashMap<String,MethodInfo> methods = new HashMap<String,MethodInfo>(); 528 // our hidden parents 529 if (mRealSuperclass != null && !mRealSuperclass.checkLevel()) { 530 gatherMethods(this, mRealSuperclass, methods); 531 } 532 for (ClassInfo iface: mRealInterfaces) { 533 if (!iface.checkLevel()) { 534 gatherMethods(this, iface, methods); 535 } 536 } 537 // mine 538 MethodInfo[] selfMethods = mAllSelfMethods; 539 for (int i=0; i<selfMethods.length; i++) { 540 MethodInfo m = selfMethods[i]; 541 if (m.checkLevel()) { 542 methods.put(m.name()+m.signature(), m); 543 } 544 } 545 // combine and return it 546 mSelfMethods = methods.values().toArray(new MethodInfo[methods.size()]); 547 Arrays.sort(mSelfMethods, MethodInfo.comparator); 548 } 549 return mSelfMethods; 550 } 551 allSelfMethods()552 public MethodInfo[] allSelfMethods() { 553 return mAllSelfMethods; 554 } 555 addMethod(MethodInfo method)556 public void addMethod(MethodInfo method) { 557 MethodInfo[] methods = new MethodInfo[mAllSelfMethods.length + 1]; 558 int i = 0; 559 for (MethodInfo m : mAllSelfMethods) { 560 methods[i] = m; 561 i++; 562 } 563 methods[i] = method; 564 mAllSelfMethods = methods; 565 } 566 selfAttributes()567 public AttributeInfo[] selfAttributes() 568 { 569 if (mSelfAttributes == null) { 570 TreeMap<FieldInfo,AttributeInfo> attrs = new TreeMap<FieldInfo,AttributeInfo>(); 571 572 // the ones in the class comment won't have any methods 573 for (AttrTagInfo tag: comment().attrTags()) { 574 FieldInfo field = tag.reference(); 575 if (field != null) { 576 AttributeInfo attr = attrs.get(field); 577 if (attr == null) { 578 attr = new AttributeInfo(this, field); 579 attrs.put(field, attr); 580 } 581 tag.setAttribute(attr); 582 } 583 } 584 585 // in the methods 586 for (MethodInfo m: selfMethods()) { 587 for (AttrTagInfo tag: m.comment().attrTags()) { 588 FieldInfo field = tag.reference(); 589 if (field != null) { 590 AttributeInfo attr = attrs.get(field); 591 if (attr == null) { 592 attr = new AttributeInfo(this, field); 593 attrs.put(field, attr); 594 } 595 tag.setAttribute(attr); 596 attr.methods.add(m); 597 } 598 } 599 } 600 601 //constructors too 602 for (MethodInfo m: constructors()) { 603 for (AttrTagInfo tag: m.comment().attrTags()) { 604 FieldInfo field = tag.reference(); 605 if (field != null) { 606 AttributeInfo attr = attrs.get(field); 607 if (attr == null) { 608 attr = new AttributeInfo(this, field); 609 attrs.put(field, attr); 610 } 611 tag.setAttribute(attr); 612 attr.methods.add(m); 613 } 614 } 615 } 616 617 mSelfAttributes = attrs.values().toArray(new AttributeInfo[attrs.size()]); 618 Arrays.sort(mSelfAttributes, AttributeInfo.comparator); 619 } 620 return mSelfAttributes; 621 } 622 enumConstants()623 public FieldInfo[] enumConstants() 624 { 625 return mEnumConstants; 626 } 627 superclass()628 public ClassInfo superclass() 629 { 630 if (!mSuperclassInit) { 631 if (this.checkLevel()) { 632 // rearrange our little inheritance hierarchy, because we need to hide classes that 633 // don't pass checkLevel 634 ClassInfo superclass = mRealSuperclass; 635 while (superclass != null && !superclass.checkLevel()) { 636 superclass = superclass.mRealSuperclass; 637 } 638 mSuperclass = superclass; 639 } else { 640 mSuperclass = mRealSuperclass; 641 } 642 } 643 return mSuperclass; 644 } 645 realSuperclass()646 public ClassInfo realSuperclass() 647 { 648 return mRealSuperclass; 649 } 650 651 /** always the real superclass, not the collapsed one we get through superclass(), 652 * also has the type parameter info if it's generic. 653 */ superclassType()654 public TypeInfo superclassType() 655 { 656 return mRealSuperclassType; 657 } 658 asTypeInfo()659 public TypeInfo asTypeInfo() 660 { 661 return mTypeInfo; 662 } 663 interfaceTypes()664 TypeInfo[] interfaceTypes() 665 { 666 ClassInfo[] infos = interfaces(); 667 int len = infos.length; 668 TypeInfo[] types = new TypeInfo[len]; 669 for (int i=0; i<len; i++) { 670 types[i] = infos[i].asTypeInfo(); 671 } 672 return types; 673 } 674 htmlPage()675 public String htmlPage() 676 { 677 String s = containingPackage().name(); 678 s = s.replace('.', '/'); 679 s += '/'; 680 s += name(); 681 s += ".html"; 682 s = DroidDoc.javadocDir + s; 683 return s; 684 } 685 686 /** Even indirectly */ isDerivedFrom(ClassInfo cl)687 public boolean isDerivedFrom(ClassInfo cl) 688 { 689 ClassInfo dad = this.superclass(); 690 if (dad != null) { 691 if (dad.equals(cl)) { 692 return true; 693 } else { 694 if (dad.isDerivedFrom(cl)) { 695 return true; 696 } 697 } 698 } 699 for (ClassInfo iface: interfaces()) { 700 if (iface.equals(cl)) { 701 return true; 702 } else { 703 if (iface.isDerivedFrom(cl)) { 704 return true; 705 } 706 } 707 } 708 return false; 709 } 710 makeKeywordEntries(List<KeywordEntry> keywords)711 public void makeKeywordEntries(List<KeywordEntry> keywords) 712 { 713 if (!checkLevel()) { 714 return; 715 } 716 717 String htmlPage = htmlPage(); 718 String qualifiedName = qualifiedName(); 719 720 keywords.add(new KeywordEntry(name(), htmlPage, 721 "class in " + containingPackage().name())); 722 723 FieldInfo[] fields = selfFields(); 724 FieldInfo[] enumConstants = enumConstants(); 725 MethodInfo[] ctors = constructors(); 726 MethodInfo[] methods = selfMethods(); 727 728 // enum constants 729 for (FieldInfo field: enumConstants()) { 730 if (field.checkLevel()) { 731 keywords.add(new KeywordEntry(field.name(), 732 htmlPage + "#" + field.anchor(), 733 "enum constant in " + qualifiedName)); 734 } 735 } 736 737 // constants 738 for (FieldInfo field: fields) { 739 if (field.isConstant() && field.checkLevel()) { 740 keywords.add(new KeywordEntry(field.name(), 741 htmlPage + "#" + field.anchor(), 742 "constant in " + qualifiedName)); 743 } 744 } 745 746 // fields 747 for (FieldInfo field: fields) { 748 if (!field.isConstant() && field.checkLevel()) { 749 keywords.add(new KeywordEntry(field.name(), 750 htmlPage + "#" + field.anchor(), 751 "field in " + qualifiedName)); 752 } 753 } 754 755 // public constructors 756 for (MethodInfo m: ctors) { 757 if (m.isPublic() && m.checkLevel()) { 758 keywords.add(new KeywordEntry(m.name() + m.prettySignature(), 759 htmlPage + "#" + m.anchor(), 760 "constructor in " + qualifiedName)); 761 } 762 } 763 764 // protected constructors 765 if (DroidDoc.checkLevel(DroidDoc.SHOW_PROTECTED)) { 766 for (MethodInfo m: ctors) { 767 if (m.isProtected() && m.checkLevel()) { 768 keywords.add(new KeywordEntry(m.name() + m.prettySignature(), 769 htmlPage + "#" + m.anchor(), 770 "constructor in " + qualifiedName)); 771 } 772 } 773 } 774 775 // package private constructors 776 if (DroidDoc.checkLevel(DroidDoc.SHOW_PACKAGE)) { 777 for (MethodInfo m: ctors) { 778 if (m.isPackagePrivate() && m.checkLevel()) { 779 keywords.add(new KeywordEntry(m.name() + m.prettySignature(), 780 htmlPage + "#" + m.anchor(), 781 "constructor in " + qualifiedName)); 782 } 783 } 784 } 785 786 // private constructors 787 if (DroidDoc.checkLevel(DroidDoc.SHOW_PRIVATE)) { 788 for (MethodInfo m: ctors) { 789 if (m.isPrivate() && m.checkLevel()) { 790 keywords.add(new KeywordEntry(m.name() + m.prettySignature(), 791 htmlPage + "#" + m.anchor(), 792 "constructor in " + qualifiedName)); 793 } 794 } 795 } 796 797 // public methods 798 for (MethodInfo m: methods) { 799 if (m.isPublic() && m.checkLevel()) { 800 keywords.add(new KeywordEntry(m.name() + m.prettySignature(), 801 htmlPage + "#" + m.anchor(), 802 "method in " + qualifiedName)); 803 } 804 } 805 806 // protected methods 807 if (DroidDoc.checkLevel(DroidDoc.SHOW_PROTECTED)) { 808 for (MethodInfo m: methods) { 809 if (m.isProtected() && m.checkLevel()) { 810 keywords.add(new KeywordEntry(m.name() + m.prettySignature(), 811 htmlPage + "#" + m.anchor(), 812 "method in " + qualifiedName)); 813 } 814 } 815 } 816 817 // package private methods 818 if (DroidDoc.checkLevel(DroidDoc.SHOW_PACKAGE)) { 819 for (MethodInfo m: methods) { 820 if (m.isPackagePrivate() && m.checkLevel()) { 821 keywords.add(new KeywordEntry(m.name() + m.prettySignature(), 822 htmlPage + "#" + m.anchor(), 823 "method in " + qualifiedName)); 824 } 825 } 826 } 827 828 // private methods 829 if (DroidDoc.checkLevel(DroidDoc.SHOW_PRIVATE)) { 830 for (MethodInfo m: methods) { 831 if (m.isPrivate() && m.checkLevel()) { 832 keywords.add(new KeywordEntry(m.name() + m.prettySignature(), 833 htmlPage + "#" + m.anchor(), 834 "method in " + qualifiedName)); 835 } 836 } 837 } 838 } 839 makeLink(HDF data, String base)840 public void makeLink(HDF data, String base) 841 { 842 data.setValue(base + ".label", this.name()); 843 if (!this.isPrimitive() && this.isIncluded() && this.checkLevel()) { 844 data.setValue(base + ".link", this.htmlPage()); 845 } 846 } 847 makeLinkListHDF(HDF data, String base, ClassInfo[] classes)848 public static void makeLinkListHDF(HDF data, String base, ClassInfo[] classes) { 849 final int N = classes.length; 850 for (int i=0; i<N; i++) { 851 ClassInfo cl = classes[i]; 852 if (cl.checkLevel()) { 853 cl.asTypeInfo().makeHDF(data, base + "." + i); 854 } 855 } 856 } 857 858 /** 859 * Used in lists of this class (packages, nested classes, known subclasses) 860 */ makeShortDescrHDF(HDF data, String base)861 public void makeShortDescrHDF(HDF data, String base) 862 { 863 mTypeInfo.makeHDF(data, base + ".type"); 864 data.setValue(base + ".kind", this.kind()); 865 TagInfo.makeHDF(data, base + ".shortDescr", this.firstSentenceTags()); 866 TagInfo.makeHDF(data, base + ".deprecated", deprecatedTags()); 867 data.setValue(base + ".since", getSince()); 868 } 869 870 /** 871 * Turns into the main class page 872 */ makeHDF(HDF data)873 public void makeHDF(HDF data) 874 { 875 int i, j, n; 876 String name = name(); 877 String qualified = qualifiedName(); 878 AttributeInfo[] selfAttributes = selfAttributes(); 879 MethodInfo[] methods = selfMethods(); 880 FieldInfo[] fields = selfFields(); 881 FieldInfo[] enumConstants = enumConstants(); 882 MethodInfo[] ctors = constructors(); 883 ClassInfo[] inners = innerClasses(); 884 885 // class name 886 mTypeInfo.makeHDF(data, "class.type"); 887 mTypeInfo.makeQualifiedHDF(data, "class.qualifiedType"); 888 data.setValue("class.name", name); 889 data.setValue("class.qualified", qualified); 890 String scope = ""; 891 if (isProtected()) { 892 data.setValue("class.scope", "protected"); 893 } 894 else if (isPublic()) { 895 data.setValue("class.scope", "public"); 896 } 897 if (isStatic()) { 898 data.setValue("class.static", "static"); 899 } 900 if (isFinal()) { 901 data.setValue("class.final", "final"); 902 } 903 if (isAbstract() && !isInterface()) { 904 data.setValue("class.abstract", "abstract"); 905 } 906 907 // class info 908 String kind = kind(); 909 if (kind != null) { 910 data.setValue("class.kind", kind); 911 } 912 data.setValue("class.since", getSince()); 913 914 // the containing package -- note that this can be passed to type_link, 915 // but it also contains the list of all of the packages 916 containingPackage().makeClassLinkListHDF(data, "class.package"); 917 918 // inheritance hierarchy 919 Vector<ClassInfo> superClasses = new Vector<ClassInfo>(); 920 superClasses.add(this); 921 ClassInfo supr = superclass(); 922 while (supr != null) { 923 superClasses.add(supr); 924 supr = supr.superclass(); 925 } 926 n = superClasses.size(); 927 for (i=0; i<n; i++) { 928 supr = superClasses.elementAt(n-i-1); 929 930 supr.asTypeInfo().makeQualifiedHDF(data, "class.inheritance." + i + ".class"); 931 supr.asTypeInfo().makeHDF(data, "class.inheritance." + i + ".short_class"); 932 j = 0; 933 for (TypeInfo t: supr.interfaceTypes()) { 934 t.makeHDF(data, "class.inheritance." + i + ".interfaces." + j); 935 j++; 936 } 937 } 938 939 // class description 940 TagInfo.makeHDF(data, "class.descr", inlineTags()); 941 TagInfo.makeHDF(data, "class.seeAlso", comment().seeTags()); 942 TagInfo.makeHDF(data, "class.deprecated", deprecatedTags()); 943 944 // known subclasses 945 TreeMap<String, ClassInfo> direct = new TreeMap<String, ClassInfo>(); 946 TreeMap<String, ClassInfo> indirect = new TreeMap<String, ClassInfo>(); 947 ClassInfo[] all = Converter.rootClasses(); 948 for (ClassInfo cl: all) { 949 if (cl.superclass() != null && cl.superclass().equals(this)) { 950 direct.put(cl.name(), cl); 951 } 952 else if (cl.isDerivedFrom(this)) { 953 indirect.put(cl.name(), cl); 954 } 955 } 956 // direct 957 i = 0; 958 for (ClassInfo cl: direct.values()) { 959 if (cl.checkLevel()) { 960 cl.makeShortDescrHDF(data, "class.subclasses.direct." + i); 961 } 962 i++; 963 } 964 // indirect 965 i = 0; 966 for (ClassInfo cl: indirect.values()) { 967 if (cl.checkLevel()) { 968 cl.makeShortDescrHDF(data, "class.subclasses.indirect." + i); 969 } 970 i++; 971 } 972 973 // nested classes 974 i=0; 975 for (ClassInfo inner: inners) { 976 if (inner.checkLevel()) { 977 inner.makeShortDescrHDF(data, "class.inners." + i); 978 } 979 i++; 980 } 981 982 // enum constants 983 i=0; 984 for (FieldInfo field: enumConstants) { 985 if (field.isConstant()) { 986 field.makeHDF(data, "class.enumConstants." + i); 987 i++; 988 } 989 } 990 991 // constants 992 i=0; 993 for (FieldInfo field: fields) { 994 if (field.isConstant()) { 995 field.makeHDF(data, "class.constants." + i); 996 i++; 997 } 998 } 999 1000 // fields 1001 i=0; 1002 for (FieldInfo field: fields) { 1003 if (!field.isConstant()) { 1004 field.makeHDF(data, "class.fields." + i); 1005 i++; 1006 } 1007 } 1008 1009 // public constructors 1010 i=0; 1011 for (MethodInfo ctor: ctors) { 1012 if (ctor.isPublic()) { 1013 ctor.makeHDF(data, "class.ctors.public." + i); 1014 i++; 1015 } 1016 } 1017 1018 // protected constructors 1019 if (DroidDoc.checkLevel(DroidDoc.SHOW_PROTECTED)) { 1020 i=0; 1021 for (MethodInfo ctor: ctors) { 1022 if (ctor.isProtected()) { 1023 ctor.makeHDF(data, "class.ctors.protected." + i); 1024 i++; 1025 } 1026 } 1027 } 1028 1029 // package private constructors 1030 if (DroidDoc.checkLevel(DroidDoc.SHOW_PACKAGE)) { 1031 i=0; 1032 for (MethodInfo ctor: ctors) { 1033 if (ctor.isPackagePrivate()) { 1034 ctor.makeHDF(data, "class.ctors.package." + i); 1035 i++; 1036 } 1037 } 1038 } 1039 1040 // private constructors 1041 if (DroidDoc.checkLevel(DroidDoc.SHOW_PRIVATE)) { 1042 i=0; 1043 for (MethodInfo ctor: ctors) { 1044 if (ctor.isPrivate()) { 1045 ctor.makeHDF(data, "class.ctors.private." + i); 1046 i++; 1047 } 1048 } 1049 } 1050 1051 // public methods 1052 i=0; 1053 for (MethodInfo method: methods) { 1054 if (method.isPublic()) { 1055 method.makeHDF(data, "class.methods.public." + i); 1056 i++; 1057 } 1058 } 1059 1060 // protected methods 1061 if (DroidDoc.checkLevel(DroidDoc.SHOW_PROTECTED)) { 1062 i=0; 1063 for (MethodInfo method: methods) { 1064 if (method.isProtected()) { 1065 method.makeHDF(data, "class.methods.protected." + i); 1066 i++; 1067 } 1068 } 1069 } 1070 1071 // package private methods 1072 if (DroidDoc.checkLevel(DroidDoc.SHOW_PACKAGE)) { 1073 i=0; 1074 for (MethodInfo method: methods) { 1075 if (method.isPackagePrivate()) { 1076 method.makeHDF(data, "class.methods.package." + i); 1077 i++; 1078 } 1079 } 1080 } 1081 1082 // private methods 1083 if (DroidDoc.checkLevel(DroidDoc.SHOW_PRIVATE)) { 1084 i=0; 1085 for (MethodInfo method: methods) { 1086 if (method.isPrivate()) { 1087 method.makeHDF(data, "class.methods.private." + i); 1088 i++; 1089 } 1090 } 1091 } 1092 1093 // xml attributes 1094 i=0; 1095 for (AttributeInfo attr: selfAttributes) { 1096 if (attr.checkLevel()) { 1097 attr.makeHDF(data, "class.attrs." + i); 1098 i++; 1099 } 1100 } 1101 1102 // inherited methods 1103 Set<ClassInfo> interfaces = new TreeSet<ClassInfo>(); 1104 addInterfaces(interfaces(), interfaces); 1105 ClassInfo cl = superclass(); 1106 i=0; 1107 while (cl != null) { 1108 addInterfaces(cl.interfaces(), interfaces); 1109 makeInheritedHDF(data, i, cl); 1110 cl = cl.superclass(); 1111 i++; 1112 } 1113 for (ClassInfo iface: interfaces) { 1114 makeInheritedHDF(data, i, iface); 1115 i++; 1116 } 1117 } 1118 addInterfaces(ClassInfo[] ifaces, Set<ClassInfo> out)1119 private static void addInterfaces(ClassInfo[] ifaces, Set<ClassInfo> out) 1120 { 1121 for (ClassInfo cl: ifaces) { 1122 out.add(cl); 1123 addInterfaces(cl.interfaces(), out); 1124 } 1125 } 1126 makeInheritedHDF(HDF data, int index, ClassInfo cl)1127 private static void makeInheritedHDF(HDF data, int index, ClassInfo cl) 1128 { 1129 int i; 1130 1131 String base = "class.inherited." + index; 1132 data.setValue(base + ".qualified", cl.qualifiedName()); 1133 if (cl.checkLevel()) { 1134 data.setValue(base + ".link", cl.htmlPage()); 1135 } 1136 String kind = cl.kind(); 1137 if (kind != null) { 1138 data.setValue(base + ".kind", kind); 1139 } 1140 1141 if (cl.mIsIncluded) { 1142 data.setValue(base + ".included", "true"); 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 { 1181 int val = mHidden; 1182 if (val >= 0) { 1183 return val != 0; 1184 } else { 1185 boolean v = isHiddenImpl(); 1186 mHidden = v ? 1 : 0; 1187 return v; 1188 } 1189 } 1190 isHiddenImpl()1191 public boolean isHiddenImpl() 1192 { 1193 ClassInfo cl = this; 1194 while (cl != null) { 1195 PackageInfo pkg = cl.containingPackage(); 1196 if (pkg != null && pkg.isHidden()) { 1197 return true; 1198 } 1199 if (cl.comment().isHidden()) { 1200 return true; 1201 } 1202 cl = cl.containingClass(); 1203 } 1204 return false; 1205 } 1206 matchMethod(MethodInfo[] methods, String name, String[] params, String[] dimensions)1207 private MethodInfo matchMethod(MethodInfo[] methods, String name, 1208 String[] params, String[] dimensions) 1209 { 1210 int len = methods.length; 1211 for (int i=0; i<len; i++) { 1212 MethodInfo method = methods[i]; 1213 if (method.name().equals(name)) { 1214 if (params == null) { 1215 return method; 1216 } else { 1217 if (method.matchesParams(params, dimensions)) { 1218 return method; 1219 } 1220 } 1221 } 1222 } 1223 return null; 1224 } 1225 findMethod(String name, String[] params, String[] dimensions)1226 public MethodInfo findMethod(String name, 1227 String[] params, String[] dimensions) 1228 { 1229 // first look on our class, and our superclasses 1230 1231 // for methods 1232 MethodInfo rv; 1233 rv = matchMethod(methods(), name, params, dimensions); 1234 1235 if (rv != null) { 1236 return rv; 1237 } 1238 1239 // for constructors 1240 rv = matchMethod(constructors(), name, params, dimensions); 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); 1249 } 1250 1251 return null; 1252 } 1253 searchInnerClasses(String[] nameParts, int index)1254 private ClassInfo searchInnerClasses(String[] nameParts, int index) 1255 { 1256 String part = nameParts[index]; 1257 1258 ClassInfo[] inners = mInnerClasses; 1259 for (ClassInfo in: inners) { 1260 String[] innerParts = in.nameParts(); 1261 if (part.equals(innerParts[innerParts.length-1])) { 1262 if (index == nameParts.length-1) { 1263 return in; 1264 } else { 1265 return in.searchInnerClasses(nameParts, index+1); 1266 } 1267 } 1268 } 1269 return null; 1270 } 1271 extendedFindClass(String className)1272 public ClassInfo extendedFindClass(String className) 1273 { 1274 // ClassDoc.findClass has this bug that we're working around here: 1275 // If you have a class PackageManager with an inner class PackageInfo 1276 // and you call it with "PackageInfo" it doesn't find it. 1277 return searchInnerClasses(className.split("\\."), 0); 1278 } 1279 findClass(String className)1280 public ClassInfo findClass(String className) 1281 { 1282 return Converter.obtainClass(mClass.findClass(className)); 1283 } 1284 findInnerClass(String className)1285 public ClassInfo findInnerClass(String className) 1286 { 1287 // ClassDoc.findClass won't find inner classes. To deal with that, 1288 // we try what they gave us first, but if that didn't work, then 1289 // we see if there are any periods in className, and start searching 1290 // from there. 1291 String[] nodes = className.split("\\."); 1292 ClassDoc cl = mClass; 1293 for (String n: nodes) { 1294 cl = cl.findClass(n); 1295 if (cl == null) { 1296 return null; 1297 } 1298 } 1299 return Converter.obtainClass(cl); 1300 } 1301 findField(String name)1302 public FieldInfo findField(String name) 1303 { 1304 // first look on our class, and our superclasses 1305 for (FieldInfo f: fields()) { 1306 if (f.name().equals(name)) { 1307 return f; 1308 } 1309 } 1310 1311 // then look at our enum constants (these are really fields, maybe 1312 // they should be mixed into fields(). not sure) 1313 for (FieldInfo f: enumConstants()) { 1314 if (f.name().equals(name)) { 1315 return f; 1316 } 1317 } 1318 1319 // then recursively look at our containing class 1320 ClassInfo containing = containingClass(); 1321 if (containing != null) { 1322 return containing.findField(name); 1323 } 1324 1325 return null; 1326 } 1327 sortByName(ClassInfo[] classes)1328 public static ClassInfo[] sortByName(ClassInfo[] classes) 1329 { 1330 int i; 1331 Sorter[] sorted = new Sorter[classes.length]; 1332 for (i=0; i<sorted.length; i++) { 1333 ClassInfo cl = classes[i]; 1334 sorted[i] = new Sorter(cl.name(), cl); 1335 } 1336 1337 Arrays.sort(sorted); 1338 1339 ClassInfo[] rv = new ClassInfo[classes.length]; 1340 for (i=0; i<rv.length; i++) { 1341 rv[i] = (ClassInfo)sorted[i].data; 1342 } 1343 1344 return rv; 1345 } 1346 equals(ClassInfo that)1347 public boolean equals(ClassInfo that) 1348 { 1349 if (that != null) { 1350 return this.qualifiedName().equals(that.qualifiedName()); 1351 } else { 1352 return false; 1353 } 1354 } 1355 setNonWrittenConstructors(MethodInfo[] nonWritten)1356 public void setNonWrittenConstructors(MethodInfo[] nonWritten) { 1357 mNonWrittenConstructors = nonWritten; 1358 } 1359 getNonWrittenConstructors()1360 public MethodInfo[] getNonWrittenConstructors() { 1361 return mNonWrittenConstructors; 1362 } 1363 kind()1364 public String kind() 1365 { 1366 if (isOrdinaryClass()) { 1367 return "class"; 1368 } 1369 else if (isInterface()) { 1370 return "interface"; 1371 } 1372 else if (isEnum()) { 1373 return "enum"; 1374 } 1375 else if (isError()) { 1376 return "class"; 1377 } 1378 else if (isException()) { 1379 return "class"; 1380 } 1381 else if (isAnnotation()) { 1382 return "@interface"; 1383 } 1384 return null; 1385 } 1386 setHiddenMethods(MethodInfo[] mInfo)1387 public void setHiddenMethods(MethodInfo[] mInfo){ 1388 mHiddenMethods = mInfo; 1389 } getHiddenMethods()1390 public MethodInfo[] getHiddenMethods(){ 1391 return mHiddenMethods; 1392 } 1393 @Override toString()1394 public String toString(){ 1395 return this.qualifiedName(); 1396 } 1397 setReasonIncluded(String reason)1398 public void setReasonIncluded(String reason) { 1399 mReasonIncluded = reason; 1400 } 1401 getReasonIncluded()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 ClassInfo[] mRealInterfaces; 1432 private ClassInfo[] mInterfaces; 1433 private TypeInfo[] mRealInterfaceTypes; 1434 private ClassInfo[] mInnerClasses; 1435 private MethodInfo[] mAllConstructors; 1436 private MethodInfo[] mAllSelfMethods; 1437 private MethodInfo[] mAnnotationElements; // if this class is an annotation 1438 private FieldInfo[] mAllSelfFields; 1439 private FieldInfo[] mEnumConstants; 1440 private PackageInfo mContainingPackage; 1441 private ClassInfo mContainingClass; 1442 private ClassInfo mRealSuperclass; 1443 private TypeInfo mRealSuperclassType; 1444 private ClassInfo mSuperclass; 1445 private AnnotationInstanceInfo[] mAnnotations; 1446 private boolean mSuperclassInit; 1447 private boolean mDeprecatedKnown; 1448 1449 // lazy 1450 private MethodInfo[] mConstructors; 1451 private ClassInfo[] mRealInnerClasses; 1452 private MethodInfo[] mSelfMethods; 1453 private FieldInfo[] mSelfFields; 1454 private AttributeInfo[] mSelfAttributes; 1455 private MethodInfo[] mMethods; 1456 private FieldInfo[] mFields; 1457 private TypeInfo[] mTypeParameters; 1458 private MethodInfo[] mHiddenMethods; 1459 private int mHidden = -1; 1460 private int mCheckLevel = -1; 1461 private String mReasonIncluded; 1462 private MethodInfo[] mNonWrittenConstructors; 1463 private boolean mIsDeprecated; 1464 } 1465