1 package jdiff; 2 3 import java.util.*; 4 5 12 public class APIComparator { 13 14 18 public APIDiff apiDiff; 19 20 25 public PackageDiff pkgDiff; 26 27 28 public APIComparator() { 29 apiDiff = new APIDiff(); 30 } 31 32 33 private static API oldAPI_; 34 35 private static API newAPI_; 36 37 40 public void compareAPIs(API oldAPI, API newAPI) { 41 System.out.println("JDiff: comparing the old and new APIs ..."); 42 oldAPI_ = oldAPI; 43 newAPI_ = newAPI; 44 45 double differs = 0.0; 46 47 apiDiff.oldAPIName_ = oldAPI.name_; 48 apiDiff.newAPIName_ = newAPI.name_; 49 50 Collections.sort(oldAPI.packages_); 51 Collections.sort(newAPI.packages_); 52 53 Iterator iter = oldAPI.packages_.iterator(); 55 while (iter.hasNext()) { 56 PackageAPI oldPkg = (PackageAPI)(iter.next()); 57 int idx = Collections.binarySearch(newAPI.packages_, oldPkg); 60 if (idx < 0) { 61 int existsNew = newAPI.packages_.indexOf(oldPkg); 66 if (existsNew != -1) { 67 differs += 2.0 * comparePackages(oldPkg, (PackageAPI)(newAPI.packages_.get(existsNew))); 70 } else { 71 if (trace) 72 System.out.println("Package " + oldPkg.name_ + " was removed"); 73 apiDiff.packagesRemoved.add(oldPkg); 74 differs += 1.0; 75 } 76 } else { 77 differs += 2.0 * comparePackages(oldPkg, (PackageAPI)(newAPI.packages_.get(idx))); 81 } 82 } 84 iter = newAPI.packages_.iterator(); 86 while (iter.hasNext()) { 87 PackageAPI newPkg = (PackageAPI)(iter.next()); 88 int idx = Collections.binarySearch(oldAPI.packages_, newPkg); 89 if (idx < 0) { 90 int existsOld = oldAPI.packages_.indexOf(newPkg); 92 if (existsOld != -1) { 93 } else { 96 if (trace) 97 System.out.println("Package " + newPkg.name_ + " was added"); 98 apiDiff.packagesAdded.add(newPkg); 99 differs += 1.0; 100 } 101 } else { 102 } 104 } 106 MergeChanges.mergeRemoveAdd(apiDiff); 109 110 Long denom = new Long (oldAPI.packages_.size() + newAPI.packages_.size()); 124 if (denom.intValue() == 0) { 126 System.out.println("Error: no packages found in the APIs."); 127 return; 128 } 129 if (trace) 130 System.out.println("Top level changes: " + differs + "/" + denom.intValue()); 131 differs = (100.0 * differs)/denom.doubleValue(); 132 133 apiDiff.pdiff = differs; 137 Double percentage = new Double (differs); 138 int approxPercentage = percentage.intValue(); 139 if (approxPercentage == 0) 140 System.out.println(" Approximately " + percentage + "% difference between the APIs"); 141 else 142 System.out.println(" Approximately " + approxPercentage + "% difference between the APIs"); 143 144 Diff.closeDiffFile(); 145 } 146 147 150 public double comparePackages(PackageAPI oldPkg, PackageAPI newPkg) { 151 if (trace) 152 System.out.println("Comparing old package " + oldPkg.name_ + 153 " and new package " + newPkg.name_); 154 pkgDiff = new PackageDiff(oldPkg.name_); 155 double differs = 0.0; 156 157 Collections.sort(oldPkg.classes_); 158 Collections.sort(newPkg.classes_); 159 160 Iterator iter = oldPkg.classes_.iterator(); 162 while (iter.hasNext()) { 163 ClassAPI oldClass = (ClassAPI)(iter.next()); 164 int idx = Collections.binarySearch(newPkg.classes_, oldClass); 167 if (idx < 0) { 168 int existsNew = newPkg.classes_.indexOf(oldClass); 173 if (existsNew != -1) { 174 differs += 2.0 * compareClasses(oldClass, (ClassAPI)(newPkg.classes_.get(existsNew)), pkgDiff); 177 } else { 178 if (trace) 179 System.out.println(" Class " + oldClass.name_ + " was removed"); 180 pkgDiff.classesRemoved.add(oldClass); 181 differs += 1.0; 182 } 183 } else { 184 differs += 2.0 * compareClasses(oldClass, (ClassAPI)(newPkg.classes_.get(idx)), pkgDiff); 187 } 188 } 190 iter = newPkg.classes_.iterator(); 192 while (iter.hasNext()) { 193 ClassAPI newClass = (ClassAPI)(iter.next()); 194 int idx = Collections.binarySearch(oldPkg.classes_, newClass); 195 if (idx < 0) { 196 int existsOld = oldPkg.classes_.indexOf(newClass); 198 if (existsOld != -1) { 199 } else { 202 if (trace) 203 System.out.println(" Class " + newClass.name_ + " was added"); 204 pkgDiff.classesAdded.add(newClass); 205 differs += 1.0; 206 } 207 } else { 208 } 210 } 212 boolean differsFlag = false; 214 if (docChanged(oldPkg.doc_, newPkg.doc_)) { 215 String link = "<a HREF=\"pkg_" + oldPkg.name_ + HTMLReportGenerator.reportFileExt + "\" class=\"hiddenlink\">"; 216 String id = oldPkg.name_ + "!package"; 217 String title = link + "Package <b>" + oldPkg.name_ + "</b></a>"; 218 pkgDiff.documentationChange_ = Diff.saveDocDiffs(pkgDiff.name_, null, oldPkg.doc_, newPkg.doc_, id, title); 219 differsFlag = true; 220 } 221 222 if (differs != 0.0 || differsFlag) 224 apiDiff.packagesChanged.add(pkgDiff); 225 226 Long denom = new Long (oldPkg.classes_.size() + newPkg.classes_.size()); 227 if (denom.intValue() == 0) { 229 System.out.println("Warning: no classes found in the package " + oldPkg.name_); 230 return 0.0; 231 } 232 if (trace) 233 System.out.println("Package " + pkgDiff.name_ + " had a difference of " + differs + "/" + denom.intValue()); 234 pkgDiff.pdiff = 100.0 * differs/denom.doubleValue(); 235 return differs/denom.doubleValue(); 236 } 238 243 public double compareClasses(ClassAPI oldClass, ClassAPI newClass, PackageDiff pkgDiff) { 244 if (trace) 245 System.out.println(" Comparing old class " + oldClass.name_ + 246 " and new class " + newClass.name_); 247 boolean differsFlag = false; 248 double differs = 0.0; 249 ClassDiff classDiff = new ClassDiff(oldClass.name_); 250 classDiff.isInterface_ = newClass.isInterface_; 252 if (oldClass.isInterface_ != newClass.isInterface_) { 254 classDiff.modifiersChange_ = "Changed from "; 255 if (oldClass.isInterface_) 256 classDiff.modifiersChange_ += "an interface to a class."; 257 else 258 classDiff.modifiersChange_ += "a class to an interface."; 259 differsFlag = true; 260 } 261 String inheritanceChange = ClassDiff.diff(oldClass, newClass); 263 if (inheritanceChange != null) { 264 classDiff.inheritanceChange_ = inheritanceChange; 265 differsFlag = true; 266 } 267 if (oldClass.isAbstract_ != newClass.isAbstract_) { 269 String changeText = ""; 270 if (oldClass.isAbstract_) 271 changeText += "Changed from abstract to non-abstract."; 272 else 273 changeText += "Changed from non-abstract to abstract."; 274 classDiff.addModifiersChange(changeText); 275 differsFlag = true; 276 } 277 if (docChanged(oldClass.doc_, newClass.doc_)) { 279 String fqName = pkgDiff.name_ + "." + classDiff.name_; 280 String link = "<a HREF=\"" + fqName + HTMLReportGenerator.reportFileExt + "\" class=\"hiddenlink\">"; 281 String id = pkgDiff.name_ + "." + classDiff.name_ + "!class"; 282 String title = link + "Class <b>" + classDiff.name_ + "</b></a>"; 283 classDiff.documentationChange_ = Diff.saveDocDiffs(pkgDiff.name_, 284 classDiff.name_, oldClass.doc_, newClass.doc_, id, title); 285 differsFlag = true; 286 } 287 String modifiersChange = oldClass.modifiers_.diff(newClass.modifiers_); 289 if (modifiersChange != null) { 290 differsFlag = true; 291 if (modifiersChange.indexOf("Change from deprecated to undeprecated") != -1) { 292 System.out.println("JDiff: warning: change from deprecated to undeprecated for class " + pkgDiff.name_ + "." + newClass.name_); 293 294 } 295 } 296 classDiff.addModifiersChange(modifiersChange); 297 298 boolean differsCtors = 300 compareAllCtors(oldClass, newClass, classDiff); 301 boolean differsMethods = 302 compareAllMethods(oldClass, newClass, classDiff); 303 boolean differsFields = 304 compareAllFields(oldClass, newClass, classDiff); 305 if (differsCtors || differsMethods || differsFields) 306 differsFlag = true; 307 308 if (trace) { 309 System.out.println(" Ctors differ? " + differsCtors + 310 ", Methods differ? " + differsMethods + 311 ", Fields differ? " + differsFields); 312 } 313 314 if (differsFlag) 316 pkgDiff.classesChanged.add(classDiff); 317 318 differs = 320 classDiff.ctorsRemoved.size() + classDiff.ctorsAdded.size() + 321 classDiff.ctorsChanged.size() + 322 classDiff.methodsRemoved.size() + classDiff.methodsAdded.size() + 323 classDiff.methodsChanged.size() + 324 classDiff.fieldsRemoved.size() + classDiff.fieldsAdded.size() + 325 classDiff.fieldsChanged.size(); 326 Long denom = new Long ( 327 oldClass.ctors_.size() + 328 numLocalMethods(oldClass.methods_) + 329 numLocalFields(oldClass.fields_) + 330 newClass.ctors_.size() + 331 numLocalMethods(newClass.methods_) + 332 numLocalFields(newClass.fields_)); 333 if (denom.intValue() == 0) { 334 if (differsFlag) { 337 classDiff.pdiff = 0.0; return 1.0; 339 } else { 340 return 0.0; 341 } 342 } 343 if (differsFlag && differs == 0.0) { 346 differs = 1.0; 347 } 348 if (trace) 349 System.out.println(" Class " + classDiff.name_ + " had a difference of " + differs + "/" + denom.intValue()); 350 classDiff.pdiff = 100.0 * differs/denom.doubleValue(); 351 return differs/denom.doubleValue(); 352 } 354 359 public boolean compareAllCtors(ClassAPI oldClass, ClassAPI newClass, 360 ClassDiff classDiff) { 361 if (trace) 362 System.out.println(" Comparing constructors: #old " + 363 oldClass.ctors_.size() + ", #new " + newClass.ctors_.size()); 364 boolean differs = false; 365 boolean singleCtor = false; 367 Collections.sort(oldClass.ctors_); 368 Collections.sort(newClass.ctors_); 369 370 Iterator iter = oldClass.ctors_.iterator(); 372 while (iter.hasNext()) { 373 ConstructorAPI oldCtor = (ConstructorAPI)(iter.next()); 374 int idx = Collections.binarySearch(newClass.ctors_, oldCtor); 375 if (idx < 0) { 376 int oldSize = oldClass.ctors_.size(); 377 int newSize = newClass.ctors_.size(); 378 if (oldSize == 1 && oldSize == newSize) { 379 MemberDiff memberDiff = new MemberDiff(oldClass.name_); 382 memberDiff.oldType_ = oldCtor.type_; 383 memberDiff.oldExceptions_ = oldCtor.exceptions_; 384 ConstructorAPI newCtor = (ConstructorAPI)(newClass.ctors_.get(0)); 385 memberDiff.newType_ = newCtor.type_; 386 memberDiff.newExceptions_ = newCtor.exceptions_; 387 if (docChanged(oldCtor.doc_, newCtor.doc_)) { 389 String type = memberDiff.newType_; 390 if (type.compareTo("void") == 0) 391 type = ""; 392 String fqName = pkgDiff.name_ + "." + classDiff.name_; 393 String link1 = "<a HREF=\"" + fqName + HTMLReportGenerator.reportFileExt + "\" class=\"hiddenlink\">"; 394 String link2 = "<a HREF=\"" + fqName + HTMLReportGenerator.reportFileExt + "#" + fqName + ".ctor_changed(" + type + ")\" class=\"hiddenlink\">"; 395 String id = pkgDiff.name_ + "." + classDiff.name_ + ".ctor(" + HTMLReportGenerator.simpleName(type) + ")"; 396 String title = link1 + "Class <b>" + classDiff.name_ + 397 "</b></a>, " + link2 + "constructor <b>" + classDiff.name_ + "(" + HTMLReportGenerator.simpleName(type) + ")</b></a>"; 398 memberDiff.documentationChange_ = Diff.saveDocDiffs( 399 pkgDiff.name_, classDiff.name_, oldCtor.doc_, newCtor.doc_, id, title); 400 } 401 String modifiersChange = oldCtor.modifiers_.diff(newCtor.modifiers_); 402 if (modifiersChange != null && modifiersChange.indexOf("Change from deprecated to undeprecated") != -1) { 403 System.out.println("JDiff: warning: change from deprecated to undeprecated for a constructor in class" + newClass.name_); 404 } 405 memberDiff.addModifiersChange(modifiersChange); 406 if (trace) 407 System.out.println(" The single constructor was changed"); 408 classDiff.ctorsChanged.add(memberDiff); 409 singleCtor = true; 410 } else { 411 if (trace) 412 System.out.println(" Constructor " + oldClass.name_ + " was removed"); 413 classDiff.ctorsRemoved.add(oldCtor); 414 } 415 differs = true; 416 } 417 } 419 iter = newClass.ctors_.iterator(); 421 while (iter.hasNext()) { 422 ConstructorAPI newCtor = (ConstructorAPI)(iter.next()); 423 int idx = Collections.binarySearch(oldClass.ctors_, newCtor); 424 if (idx < 0) { 425 if (!singleCtor) { 426 if (trace) 427 System.out.println(" Constructor " + oldClass.name_ + " was added"); 428 classDiff.ctorsAdded.add(newCtor); 429 differs = true; 430 } 431 } 432 } 434 return differs; 435 } 437 450 public boolean compareAllMethods(ClassAPI oldClass, ClassAPI newClass, ClassDiff classDiff) { 451 if (trace) 452 System.out.println(" Comparing methods: #old " + 453 oldClass.methods_.size() + ", #new " + 454 newClass.methods_.size()); 455 boolean differs = false; 456 457 Collections.sort(oldClass.methods_); 458 Collections.sort(newClass.methods_); 459 460 Iterator iter = oldClass.methods_.iterator(); 462 while (iter.hasNext()) { 463 MethodAPI oldMethod = (MethodAPI)(iter.next()); 464 int idx = -1; 465 MethodAPI[] methodArr = new MethodAPI[newClass.methods_.size()]; 466 methodArr = (MethodAPI[])newClass.methods_.toArray(methodArr); 467 for (int methodIdx = 0; methodIdx < methodArr.length; methodIdx++) { 468 MethodAPI newMethod = methodArr[methodIdx]; 469 if (oldMethod.compareTo(newMethod) == 0) { 470 idx = methodIdx; 471 break; 472 } 473 } 474 if (idx < 0) { 481 int startOld = oldClass.methods_.indexOf(oldMethod); 488 int endOld = oldClass.methods_.lastIndexOf(oldMethod); 489 int startNew = newClass.methods_.indexOf(oldMethod); 490 int endNew = newClass.methods_.lastIndexOf(oldMethod); 491 492 if (startOld != -1 && startOld == endOld && 493 startNew != -1 && startNew == endNew) { 494 MethodAPI newMethod = (MethodAPI)(newClass.methods_.get(startNew)); 495 if (oldMethod.inheritedFrom_ == null || 499 newMethod.inheritedFrom_ == null) { 500 compareMethods(oldMethod, newMethod, classDiff); 503 differs = true; 504 } 505 } else if (oldMethod.inheritedFrom_ == null) { 506 if (trace) 508 System.out.println(" Method " + oldMethod.name_ + 509 "(" + oldMethod.getSignature() + 510 ") was removed"); 511 classDiff.methodsRemoved.add(oldMethod); 512 differs = true; 513 } 514 } 515 } 517 iter = newClass.methods_.iterator(); 519 while (iter.hasNext()) { 520 MethodAPI newMethod = (MethodAPI)(iter.next()); 521 if (newMethod.inheritedFrom_ != null) 523 continue; 524 int idx = -1; 525 MethodAPI[] methodArr = new MethodAPI[oldClass.methods_.size()]; 526 methodArr = (MethodAPI[])oldClass.methods_.toArray(methodArr); 527 for (int methodIdx = 0; methodIdx < methodArr.length; methodIdx++) { 528 MethodAPI oldMethod = methodArr[methodIdx]; 529 if (newMethod.compareTo(oldMethod) == 0) { 530 idx = methodIdx; 531 break; 532 } 533 } 534 if (idx < 0) { 537 int startOld = oldClass.methods_.indexOf(newMethod); 539 int endOld = oldClass.methods_.lastIndexOf(newMethod); 540 int startNew = newClass.methods_.indexOf(newMethod); 541 int endNew = newClass.methods_.lastIndexOf(newMethod); 542 543 if (startOld != -1 && startOld == endOld && 544 startNew != -1 && startNew == endNew) { 545 } else { 548 if (trace) 549 System.out.println(" Method " + newMethod.name_ + 550 "(" + newMethod.getSignature() + ") was added"); 551 classDiff.methodsAdded.add(newMethod); 552 differs = true; 553 } 554 } 555 } 557 return differs; 558 } 560 563 public boolean compareMethods(MethodAPI oldMethod, MethodAPI newMethod, ClassDiff classDiff) { 564 MemberDiff methodDiff = new MemberDiff(oldMethod.name_); 565 boolean differs = false; 566 methodDiff.oldType_ = oldMethod.returnType_; 568 methodDiff.newType_ = newMethod.returnType_; 569 if (oldMethod.returnType_.compareTo(newMethod.returnType_) != 0) { 570 differs = true; 571 } 572 String oldSig = oldMethod.getSignature(); 574 String newSig = newMethod.getSignature(); 575 methodDiff.oldSignature_ = oldSig; 576 methodDiff.newSignature_ = newSig; 577 if (oldSig.compareTo(newSig) != 0) { 578 differs = true; 579 } 580 int inh = changedInheritance(oldMethod.inheritedFrom_, newMethod.inheritedFrom_); 582 if (inh != 0) 583 differs = true; 584 if (inh == 1) { 585 methodDiff.addModifiersChange("Method was locally defined, but is now inherited from " + linkToClass(newMethod, true) + "."); 586 methodDiff.inheritedFrom_ = newMethod.inheritedFrom_; 587 } else if (inh == 2) { 588 methodDiff.addModifiersChange("Method was inherited from " + linkToClass(oldMethod, false) + ", but is now defined locally."); 589 } else if (inh == 3) { 590 methodDiff.addModifiersChange("Method was inherited from " + 591 linkToClass(oldMethod, false) + ", and is now inherited from " + linkToClass(newMethod, true) + "."); 592 methodDiff.inheritedFrom_ = newMethod.inheritedFrom_; 593 } 594 if (oldMethod.isAbstract_ != newMethod.isAbstract_) { 596 String changeText = ""; 597 if (oldMethod.isAbstract_) 598 changeText += "Changed from abstract to non-abstract."; 599 else 600 changeText += "Changed from non-abstract to abstract."; 601 methodDiff.addModifiersChange(changeText); 602 differs = true; 603 } 604 if (Diff.showAllChanges && 606 oldMethod.isNative_ != newMethod.isNative_) { 607 String changeText = ""; 608 if (oldMethod.isNative_) 609 changeText += "Changed from native to non-native."; 610 else 611 changeText += "Changed from non-native to native."; 612 methodDiff.addModifiersChange(changeText); 613 differs = true; 614 } 615 if (Diff.showAllChanges && 617 oldMethod.isSynchronized_ != newMethod.isSynchronized_) { 618 String changeText = ""; 619 if (oldMethod.isSynchronized_) 620 changeText += "Changed from synchronized to non-synchronized."; 621 else 622 changeText += "Changed from non-synchronized to synchronized."; 623 methodDiff.addModifiersChange(changeText); 624 differs = true; 625 } 626 627 methodDiff.oldExceptions_ = oldMethod.exceptions_; 629 methodDiff.newExceptions_ = newMethod.exceptions_; 630 if (oldMethod.exceptions_.compareTo(newMethod.exceptions_) != 0) { 631 differs = true; 632 } 633 634 if (docChanged(oldMethod.doc_, newMethod.doc_)) { 636 String sig = methodDiff.newSignature_; 637 if (sig.compareTo("void") == 0) 638 sig = ""; 639 String fqName = pkgDiff.name_ + "." + classDiff.name_; 640 String link1 = "<a HREF=\"" + fqName + HTMLReportGenerator.reportFileExt + "\" class=\"hiddenlink\">"; 641 String link2 = "<a HREF=\"" + fqName + HTMLReportGenerator.reportFileExt + "#" + fqName + "." + newMethod.name_ + "_changed(" + sig + ")\" class=\"hiddenlink\">"; 642 String id = pkgDiff.name_ + "." + classDiff.name_ + ".dmethod." + newMethod.name_ + "(" + HTMLReportGenerator.simpleName(sig) + ")"; 643 String title = link1 + "Class <b>" + classDiff.name_ + "</b></a>, " + 644 link2 + HTMLReportGenerator.simpleName(methodDiff.newType_) + " <b>" + newMethod.name_ + "(" + HTMLReportGenerator.simpleName(sig) + ")</b></a>"; 645 methodDiff.documentationChange_ = Diff.saveDocDiffs(pkgDiff.name_, classDiff.name_, oldMethod.doc_, newMethod.doc_, id, title); 646 differs = true; 647 } 648 649 String modifiersChange = oldMethod.modifiers_.diff(newMethod.modifiers_); 651 if (modifiersChange != null) { 652 differs = true; 653 if (modifiersChange.indexOf("Change from deprecated to undeprecated") != -1) { 654 System.out.println("JDiff: warning: change from deprecated to undeprecated for method " + classDiff.name_ + "." + newMethod.name_); 655 656 } 657 } 658 methodDiff.addModifiersChange(modifiersChange); 659 660 if (differs) { 662 if (trace) { 663 System.out.println(" Method " + newMethod.name_ + 664 " was changed: old: " + 665 oldMethod.returnType_ + "(" + oldSig + "), new: " + 666 newMethod.returnType_ + "(" + newSig + ")"); 667 if (methodDiff.modifiersChange_ != null) 668 System.out.println(" Modifier change: " + methodDiff.modifiersChange_); 669 } 670 classDiff.methodsChanged.add(methodDiff); 671 } 672 673 return differs; 674 } 676 679 public boolean compareAllFields(ClassAPI oldClass, ClassAPI newClass, 680 ClassDiff classDiff) { 681 if (trace) 682 System.out.println(" Comparing fields: #old " + 683 oldClass.fields_.size() + ", #new " 684 + newClass.fields_.size()); 685 boolean differs = false; 686 687 Collections.sort(oldClass.fields_); 688 Collections.sort(newClass.fields_); 689 690 Iterator iter = oldClass.fields_.iterator(); 692 while (iter.hasNext()) { 693 FieldAPI oldField = (FieldAPI)(iter.next()); 694 int idx = Collections.binarySearch(newClass.fields_, oldField); 695 if (idx < 0) { 696 int existsNew = newClass.fields_.indexOf(oldField); 701 if (existsNew != -1) { 702 FieldAPI newField = (FieldAPI)(newClass.fields_.get(existsNew)); 703 if (oldField.inheritedFrom_ == null || 704 newField.inheritedFrom_ == null) { 705 MemberDiff memberDiff = new MemberDiff(oldField.name_); 707 memberDiff.oldType_ = oldField.type_; 708 memberDiff.newType_ = newField.type_; 709 int inh = changedInheritance(oldField.inheritedFrom_, newField.inheritedFrom_); 711 if (inh != 0) 712 differs = true; 713 if (inh == 1) { 714 memberDiff.addModifiersChange("Field was locally defined, but is now inherited from " + linkToClass(newField, true) + "."); 715 memberDiff.inheritedFrom_ = newField.inheritedFrom_; 716 } else if (inh == 2) { 717 memberDiff.addModifiersChange("Field was inherited from " + linkToClass(oldField, false) + ", but is now defined locally."); 718 } else if (inh == 3) { 719 memberDiff.addModifiersChange("Field was inherited from " + linkToClass(oldField, false) + ", and is now inherited from " + linkToClass(newField, true) + "."); 720 memberDiff.inheritedFrom_ = newField.inheritedFrom_; 721 } 722 if (oldField.isTransient_ != newField.isTransient_) { 724 String changeText = ""; 725 if (oldField.isTransient_) 726 changeText += "Changed from transient to non-transient."; 727 else 728 changeText += "Changed from non-transient to transient."; 729 memberDiff.addModifiersChange(changeText); 730 differs = true; 731 } 732 if (oldField.isVolatile_ != newField.isVolatile_) { 734 String changeText = ""; 735 if (oldField.isVolatile_) 736 changeText += "Changed from volatile to non-volatile."; 737 else 738 changeText += "Changed from non-volatile to volatile."; 739 memberDiff.addModifiersChange(changeText); 740 differs = true; 741 } 742 if (oldField.value_ != null && 744 newField.value_ != null && 745 oldField.value_.compareTo(newField.value_) != 0) { 746 String changeText = "Changed in value from " + oldField.value_ 747 + " to " + newField.value_ +"."; 748 memberDiff.addModifiersChange(changeText); 749 differs = true; 750 } 751 if (docChanged(oldField.doc_, newField.doc_)) { 753 String fqName = pkgDiff.name_ + "." + classDiff.name_; 754 String link1 = "<a HREF=\"" + fqName + HTMLReportGenerator.reportFileExt + "\" class=\"hiddenlink\">"; 755 String link2 = "<a HREF=\"" + fqName + HTMLReportGenerator.reportFileExt + "#" + fqName + "." + newField.name_ + "\" class=\"hiddenlink\">"; 756 String id = pkgDiff.name_ + "." + classDiff.name_ + ".field." + newField.name_; 757 String title = link1 + "Class <b>" + classDiff.name_ + "</b></a>, " + 758 link2 + HTMLReportGenerator.simpleName(memberDiff.newType_) + " <b>" + newField.name_ + "</b></a>"; 759 memberDiff.documentationChange_ = Diff.saveDocDiffs(pkgDiff.name_, classDiff.name_, oldField.doc_, newField.doc_, id, title); 760 differs = true; 761 } 762 763 String modifiersChange = oldField.modifiers_.diff(newField.modifiers_); 765 memberDiff.addModifiersChange(modifiersChange); 766 if (modifiersChange != null && modifiersChange.indexOf("Change from deprecated to undeprecated") != -1) { 767 System.out.println("JDiff: warning: change from deprecated to undeprecated for class " + newClass.name_ + ", field " + newField.name_); 768 } 769 if (trace) 770 System.out.println(" Field " + newField.name_ + " was changed"); 771 classDiff.fieldsChanged.add(memberDiff); 772 differs = true; 773 } 774 } else if (oldField.inheritedFrom_ == null) { 775 if (trace) 776 System.out.println(" Field " + oldField.name_ + " was removed"); 777 classDiff.fieldsRemoved.add(oldField); 778 differs = true; 779 } 780 } 781 } 783 iter = newClass.fields_.iterator(); 785 while (iter.hasNext()) { 786 FieldAPI newField = (FieldAPI)(iter.next()); 787 if (newField.inheritedFrom_ != null) 789 continue; 790 int idx = Collections.binarySearch(oldClass.fields_, newField); 791 if (idx < 0) { 792 int existsOld = oldClass.fields_.indexOf(newField); 794 if (existsOld != -1) { 795 } else { 797 if (trace) 798 System.out.println(" Field " + newField.name_ + " was added"); 799 classDiff.fieldsAdded.add(newField); 800 differs = true; 801 } 802 } 803 } 805 return differs; 806 } 808 814 public static boolean docChanged(String oldDoc, String newDoc) { 815 if (!HTMLReportGenerator.reportDocChanges) 816 return false; if (oldDoc == null && newDoc != null) 818 return true; 819 if (oldDoc != null && newDoc == null) 820 return true; 821 if (oldDoc != null && newDoc != null && oldDoc.compareTo(newDoc) != 0) 822 return true; 823 return false; 824 } 825 826 835 public static int changedInheritance(String oldInherit, String newInherit) { 836 if (oldInherit == null && newInherit == null) 837 return 0; 838 if (oldInherit == null && newInherit != null) 839 return 1; 840 if (oldInherit != null && newInherit == null) 841 return 2; 842 if (oldInherit.compareTo(newInherit) == 0) 843 return 0; 844 else 845 return 3; 846 } 847 848 851 public static String linkToClass(MethodAPI m, boolean useNew) { 852 String sig = m.getSignature(); 853 if (sig.compareTo("void") == 0) 854 sig = ""; 855 return linkToClass(m.inheritedFrom_, m.name_, sig, useNew); 856 } 857 858 861 public static String linkToClass(FieldAPI m, boolean useNew) { 862 return linkToClass(m.inheritedFrom_, m.name_, null, useNew); 863 } 864 865 872 public static String linkToClass(String className, String memberName, 873 String memberType, boolean useNew) { 874 if (!useNew && HTMLReportGenerator.oldDocPrefix == null) { 875 return "<tt>" + className + "</tt>"; } 877 API api = oldAPI_; 878 String prefix = HTMLReportGenerator.oldDocPrefix; 879 if (useNew) { 880 api = newAPI_; 881 prefix = HTMLReportGenerator.newDocPrefix; 882 } 883 ClassAPI cls = (ClassAPI)api.classes_.get(className); 884 if (cls == null) { 885 if (useNew) 886 System.out.println("Warning: class " + className + " not found in the new API when creating Javadoc link"); 887 else 888 System.out.println("Warning: class " + className + " not found in the old API when creating Javadoc link"); 889 return "<tt>" + className + "</tt>"; 890 } 891 int clsIdx = className.indexOf(cls.name_); 892 if (clsIdx != -1) { 893 String pkgRef = className.substring(0, clsIdx); 894 pkgRef = pkgRef.replace('.', '/'); 895 String res = "<a HREF=\"" + prefix + pkgRef + cls.name_ + ".html#" + memberName; 896 if (memberType != null) 897 res += "(" + memberType + ")"; 898 res += "\" target=\"_top\">" + "<tt>" + cls.name_ + "</tt></a>"; 899 return res; 900 } 901 return "<tt>" + className + "</tt>"; 902 } 903 904 907 public int numLocalMethods(List methods) { 908 int res = 0; 909 Iterator iter = methods.iterator(); 910 while (iter.hasNext()) { 911 MethodAPI m = (MethodAPI)(iter.next()); 912 if (m.inheritedFrom_ == null) 913 res++; 914 } 915 return res; 916 } 917 918 921 public int numLocalFields(List fields) { 922 int res = 0; 923 Iterator iter = fields.iterator(); 924 while (iter.hasNext()) { 925 FieldAPI f = (FieldAPI)(iter.next()); 926 if (f.inheritedFrom_ == null) 927 res++; 928 } 929 return res; 930 } 931 932 933 private boolean trace = false; 934 } 935 | Popular Tags |