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