196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Projectpackage jdiff; 296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project 396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Projectimport java.util.*; 496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project 596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project/** 696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project * Convert some remove and add operations into change operations. 796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project * 896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project * Once the numbers of members removed and added are known 996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project * we can deduce more information about changes. For instance, if there are 1096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project * two methods with the same name, and one or more of them has a 1196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project * parameter type change, then this can only be reported as removing 1296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project * the old version(s) and adding the new version(s), because there are 1396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project * multiple methods with the same name. 1496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project * 1596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project * However, if only <i>one</i> method with a given name is removed, and 1696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project * only <i>one</i> method with the same name is added, we can convert these 1796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project * operations to a change operation. For constructors, this is true if 1896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project * the types are the same. For fields, the field names have to be the same, 1996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project * though this should never occur, since field names are unique. 2096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project * 2196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project * Another merge which can be made is if two or more methods with the same name 2296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project * were marked as removed and added because of changes other than signature. 2396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project * 2496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project * See the file LICENSE.txt for copyright details. 2596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project * @author Matthew Doar, mdoar@pobox.com 2696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project */ 2796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Projectclass MergeChanges { 2896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project 2996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project /** 3096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project * Convert some remove and add operations into change operations. 3196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project * 3296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project * Note that if a single thread modifies a collection directly while it is 3396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project * iterating over the collection with a fail-fast iterator, the iterator 3496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project * will throw java.util.ConcurrentModificationException 3596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project */ 3696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project public static void mergeRemoveAdd(APIDiff apiDiff) { 3796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project // Go through all the ClassDiff objects searching for the above cases. 3896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project Iterator iter = apiDiff.packagesChanged.iterator(); 3996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project while (iter.hasNext()) { 4096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project PackageDiff pkgDiff = (PackageDiff)(iter.next()); 4196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project Iterator iter2 = pkgDiff.classesChanged.iterator(); 4296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project while (iter2.hasNext()) { 4396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project ClassDiff classDiff = (ClassDiff)(iter2.next()); 4496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project // Note: using iterators to step through the members gives a 4596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project // ConcurrentModificationException exception with large files. 4696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project // Constructors 4796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project ConstructorAPI[] ctorArr = new ConstructorAPI[classDiff.ctorsRemoved.size()]; 4896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project ctorArr = (ConstructorAPI[])classDiff.ctorsRemoved.toArray(ctorArr); 4996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project for (int ctorIdx = 0; ctorIdx < ctorArr.length; ctorIdx++) { 5096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project ConstructorAPI removedCtor = ctorArr[ctorIdx]; 5196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project mergeRemoveAddCtor(removedCtor, classDiff, pkgDiff); 5296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project } 5396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project // Methods 5496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project MethodAPI[] methodArr = new MethodAPI[classDiff.methodsRemoved.size()]; 5596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project methodArr = (MethodAPI[])classDiff.methodsRemoved.toArray(methodArr); 5696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project for (int methodIdx = 0; methodIdx < methodArr.length; methodIdx++) { 5796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project MethodAPI removedMethod = methodArr[methodIdx]; 5896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project // Only merge locally defined methods 5996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project if (removedMethod.inheritedFrom_ == null) 6096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project mergeRemoveAddMethod(removedMethod, classDiff, pkgDiff); 6196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project } 6296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project // Fields 6396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project FieldAPI[] fieldArr = new FieldAPI[classDiff.fieldsRemoved.size()]; 6496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project fieldArr = (FieldAPI[])classDiff.fieldsRemoved.toArray(fieldArr); 6596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project for (int fieldIdx = 0; fieldIdx < fieldArr.length; fieldIdx++) { 6696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project FieldAPI removedField = fieldArr[fieldIdx]; 6796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project // Only merge locally defined fields 6896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project if (removedField.inheritedFrom_ == null) 6996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project mergeRemoveAddField(removedField, classDiff, pkgDiff); 7096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project } 7196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project } 7296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project } 7396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project } 7496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project 7596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project /** 7696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project * Convert some removed and added constructors into changed constructors. 7796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project */ 7896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project public static void mergeRemoveAddCtor(ConstructorAPI removedCtor, ClassDiff classDiff, PackageDiff pkgDiff) { 7996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project // Search on the type of the constructor 8096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project int startRemoved = classDiff.ctorsRemoved.indexOf(removedCtor); 8196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project int endRemoved = classDiff.ctorsRemoved.lastIndexOf(removedCtor); 8296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project int startAdded = classDiff.ctorsAdded.indexOf(removedCtor); 8396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project int endAdded = classDiff.ctorsAdded.lastIndexOf(removedCtor); 8496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project if (startRemoved != -1 && startRemoved == endRemoved && 8596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project startAdded != -1 && startAdded == endAdded) { 8696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project // There is only one constructor with the type of the 8796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project // removedCtor in both the removed and added constructors. 8896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project ConstructorAPI addedCtor = (ConstructorAPI)(classDiff.ctorsAdded.get(startAdded)); 8996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project // Create a MemberDiff for this change 9096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project MemberDiff ctorDiff = new MemberDiff(classDiff.name_); 9196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project ctorDiff.oldType_ = removedCtor.type_; 9296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project ctorDiff.newType_ = addedCtor.type_; // Should be the same as removedCtor.type 9396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project ctorDiff.oldExceptions_ = removedCtor.exceptions_; 9496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project ctorDiff.newExceptions_ = addedCtor.exceptions_; 9596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project ctorDiff.addModifiersChange(removedCtor.modifiers_.diff(addedCtor.modifiers_)); 9696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project // Track changes in documentation 9796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project if (APIComparator.docChanged(removedCtor.doc_, addedCtor.doc_)) { 9896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project String type = ctorDiff.newType_; 9996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project if (type.compareTo("void") == 0) 10096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project type = ""; 10196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project String fqName = pkgDiff.name_ + "." + classDiff.name_; 10296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project String link1 = "<a href=\"" + fqName + HTMLReportGenerator.reportFileExt + "\" class=\"hiddenlink\">"; 10396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project String link2 = "<a href=\"" + fqName + HTMLReportGenerator.reportFileExt + "#" + fqName + ".ctor_changed(" + type + ")\" class=\"hiddenlink\">"; 10496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project String id = pkgDiff.name_ + "." + classDiff.name_ + ".ctor(" + HTMLReportGenerator.simpleName(type) + ")"; 10596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project String title = link1 + "Class <b>" + classDiff.name_ + 10696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project "</b></a>, " + link2 + "constructor <b>" + classDiff.name_ + "(" + HTMLReportGenerator.simpleName(type) + ")</b></a>"; 10796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project ctorDiff.documentationChange_ = Diff.saveDocDiffs(pkgDiff.name_, classDiff.name_, removedCtor.doc_, addedCtor.doc_, id, title); 10896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project } 10996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project classDiff.ctorsChanged.add(ctorDiff); 11096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project // Now remove the entries from the remove and add lists 11196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project classDiff.ctorsRemoved.remove(startRemoved); 11296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project classDiff.ctorsAdded.remove(startAdded); 11396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project if (trace && ctorDiff.modifiersChange_ != null) 11496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project System.out.println("Merged the removal and addition of constructor into one change: " + ctorDiff.modifiersChange_); 11596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project } 11696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project } 11796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project 11896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project /** 11996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project * Convert some removed and added methods into changed methods. 12096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project */ 12196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project public static void mergeRemoveAddMethod(MethodAPI removedMethod, 12296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project ClassDiff classDiff, 12396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project PackageDiff pkgDiff) { 12496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project mergeSingleMethods(removedMethod, classDiff, pkgDiff); 12596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project mergeMultipleMethods(removedMethod, classDiff, pkgDiff); 12696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project } 12796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project 12896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project /** 12996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project * Convert single removed and added methods into a changed method. 13096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project */ 13196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project public static void mergeSingleMethods(MethodAPI removedMethod, ClassDiff classDiff, PackageDiff pkgDiff) { 13296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project // Search on the name of the method 13396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project int startRemoved = classDiff.methodsRemoved.indexOf(removedMethod); 13496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project int endRemoved = classDiff.methodsRemoved.lastIndexOf(removedMethod); 13596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project int startAdded = classDiff.methodsAdded.indexOf(removedMethod); 13696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project int endAdded = classDiff.methodsAdded.lastIndexOf(removedMethod); 13796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project if (startRemoved != -1 && startRemoved == endRemoved && 13896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project startAdded != -1 && startAdded == endAdded) { 13996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project // There is only one method with the name of the 14096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project // removedMethod in both the removed and added methods. 14196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project MethodAPI addedMethod = (MethodAPI)(classDiff.methodsAdded.get(startAdded)); 14296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project if (addedMethod.inheritedFrom_ == null) { 14396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project // Create a MemberDiff for this change 14496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project MemberDiff methodDiff = new MemberDiff(removedMethod.name_); 14596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project methodDiff.oldType_ = removedMethod.returnType_; 14696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project methodDiff.newType_ = addedMethod.returnType_; 14796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project methodDiff.oldSignature_ = removedMethod.getSignature(); 14896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project methodDiff.newSignature_ = addedMethod.getSignature(); 14996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project methodDiff.oldExceptions_ = removedMethod.exceptions_; 15096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project methodDiff.newExceptions_ = addedMethod.exceptions_; 15196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project // The addModifiersChange field may not have been 15296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project // initialized yet if there were multiple methods of the same 15396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project // name. 15496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project diffMethods(methodDiff, removedMethod, addedMethod); 15596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project methodDiff.addModifiersChange(removedMethod.modifiers_.diff(addedMethod.modifiers_)); 15696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project // Track changes in documentation 15796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project if (APIComparator.docChanged(removedMethod.doc_, addedMethod.doc_)) { 15896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project String sig = methodDiff.newSignature_; 15996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project if (sig.compareTo("void") == 0) 16096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project sig = ""; 16196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project String fqName = pkgDiff.name_ + "." + classDiff.name_; 16296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project String link1 = "<a href=\"" + fqName + HTMLReportGenerator.reportFileExt + "\" class=\"hiddenlink\">"; 16396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project String link2 = "<a href=\"" + fqName + HTMLReportGenerator.reportFileExt + "#" + fqName + "." + addedMethod.name_ + "_changed(" + sig + ")\" class=\"hiddenlink\">"; 16496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project String id = pkgDiff.name_ + "." + classDiff.name_ + ".dmethod." + addedMethod.name_ + "(" + HTMLReportGenerator.simpleName(sig) + ")"; 16596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project String title = link1 + "Class <b>" + classDiff.name_ + "</b></a>, " + 16696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project link2 + HTMLReportGenerator.simpleName(methodDiff.newType_) + " <b>" + addedMethod.name_ + "(" + HTMLReportGenerator.simpleName(sig) + ")</b></a>"; 16796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project methodDiff.documentationChange_ = Diff.saveDocDiffs(pkgDiff.name_, classDiff.name_, removedMethod.doc_, addedMethod.doc_, id, title); 16896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project } 16996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project classDiff.methodsChanged.add(methodDiff); 17096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project // Now remove the entries from the remove and add lists 17196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project classDiff.methodsRemoved.remove(startRemoved); 17296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project classDiff.methodsAdded.remove(startAdded); 17396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project if (trace) { 17496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project System.out.println("Merged the removal and addition of method " + 17596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project removedMethod.name_ + 17696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project " into one change"); 17796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project } 17896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project } //if (addedMethod.inheritedFrom_ == null) 17996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project } 18096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project } 18196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project 18296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project /** 18396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project * Convert multiple removed and added methods into changed methods. 18496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project * This handles the case where the methods' signatures are unchanged, but 18596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project * something else changed. 18696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project */ 18796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project public static void mergeMultipleMethods(MethodAPI removedMethod, ClassDiff classDiff, PackageDiff pkgDiff) { 18896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project // Search on the name and signature of the method 18996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project int startRemoved = classDiff.methodsRemoved.indexOf(removedMethod); 19096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project int endRemoved = classDiff.methodsRemoved.lastIndexOf(removedMethod); 19196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project int startAdded = classDiff.methodsAdded.indexOf(removedMethod); 19296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project int endAdded = classDiff.methodsAdded.lastIndexOf(removedMethod); 19396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project if (startRemoved != -1 && endRemoved != -1 && 19496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project startAdded != -1 && endAdded != -1) { 19596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project // Find the index of the current removed method 19696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project int removedIdx = -1; 19796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project for (int i = startRemoved; i <= endRemoved; i++) { 19896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project if (removedMethod.equalSignatures(classDiff.methodsRemoved.get(i))) { 19996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project removedIdx = i; 20096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project break; 20196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project } 20296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project } 20396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project if (removedIdx == -1) { 20496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project System.out.println("Error: removed method index not found"); 20596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project System.exit(5); 20696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project } 20796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project // Find the index of the added method with the same signature, if 20896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project // it exists, and make sure it is defined locally. 20996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project int addedIdx = -1; 21096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project for (int i = startAdded; i <= endAdded; i++) { 21196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project MethodAPI addedMethod2 = (MethodAPI)(classDiff.methodsAdded.get(i)); 21296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project if (addedMethod2.inheritedFrom_ == null && 21396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project removedMethod.equalSignatures(addedMethod2)) 21496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project addedIdx = i; 21596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project break; 21696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project } 21796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project if (addedIdx == -1) 21896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project return; 21996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project MethodAPI addedMethod = (MethodAPI)(classDiff.methodsAdded.get(addedIdx)); 22096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project // Create a MemberDiff for this change 22196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project MemberDiff methodDiff = new MemberDiff(removedMethod.name_); 22296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project methodDiff.oldType_ = removedMethod.returnType_; 22396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project methodDiff.newType_ = addedMethod.returnType_; 22496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project methodDiff.oldSignature_ = removedMethod.getSignature(); 22596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project methodDiff.newSignature_ = addedMethod.getSignature(); 22696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project methodDiff.oldExceptions_ = removedMethod.exceptions_; 22796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project methodDiff.newExceptions_ = addedMethod.exceptions_; 22896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project // The addModifiersChange field may not have been 22996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project // initialized yet if there were multiple methods of the same 23096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project // name. 23196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project diffMethods(methodDiff, removedMethod, addedMethod); 23296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project methodDiff.addModifiersChange(removedMethod.modifiers_.diff(addedMethod.modifiers_)); 23396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project // Track changes in documentation 23496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project if (APIComparator.docChanged(removedMethod.doc_, addedMethod.doc_)) { 23596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project String sig = methodDiff.newSignature_; 23696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project if (sig.compareTo("void") == 0) 23796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project sig = ""; 23896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project String fqName = pkgDiff.name_ + "." + classDiff.name_; 23996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project String link1 = "<a href=\"" + fqName + HTMLReportGenerator.reportFileExt + "\" class=\"hiddenlink\">"; 24096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project String link2 = "<a href=\"" + fqName + HTMLReportGenerator.reportFileExt + "#" + fqName + "." + addedMethod.name_ + "_changed(" + sig + ")\" class=\"hiddenlink\">"; 24196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project String id = pkgDiff.name_ + "." + classDiff.name_ + ".dmethod." + addedMethod.name_ + "(" + HTMLReportGenerator.simpleName(sig) + ")"; 24296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project String title = link1 + "Class <b>" + classDiff.name_ + "</b></a>, " + 24396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project link2 + HTMLReportGenerator.simpleName(methodDiff.newType_) + " <b>" + addedMethod.name_ + "(" + HTMLReportGenerator.simpleName(sig) + ")</b></a>"; 24496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project methodDiff.documentationChange_ = Diff.saveDocDiffs(pkgDiff.name_, classDiff.name_, removedMethod.doc_, addedMethod.doc_, id, title); 24596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project } 24696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project classDiff.methodsChanged.add(methodDiff); 24796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project // Now remove the entries from the remove and add lists 24896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project classDiff.methodsRemoved.remove(removedIdx); 24996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project classDiff.methodsAdded.remove(addedIdx); 25096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project if (trace) { 25196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project System.out.println("Merged the removal and addition of method " + 25296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project removedMethod.name_ + 25396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project " into one change. There were multiple methods of this name."); 25496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project } 25596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project } 25696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project } 25796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project 25896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project /** 25996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project * Track changes in methods related to abstract, native, and 26096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project * synchronized modifiers here. 26196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project */ 26296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project public static void diffMethods(MemberDiff methodDiff, 26396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project MethodAPI oldMethod, 26496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project MethodAPI newMethod) { 26596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project // Abstract or not 26696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project if (oldMethod.isAbstract_ != newMethod.isAbstract_) { 26796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project String changeText = ""; 26896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project if (oldMethod.isAbstract_) 26996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project changeText += "Changed from abstract to non-abstract."; 27096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project else 27196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project changeText += "Changed from non-abstract to abstract."; 27296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project methodDiff.addModifiersChange(changeText); 27396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project } 27496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project // Native or not 27596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project if (Diff.showAllChanges && 27696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project oldMethod.isNative_ != newMethod.isNative_) { 27796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project String changeText = ""; 27896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project if (oldMethod.isNative_) 27996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project changeText += "Changed from native to non-native."; 28096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project else 28196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project changeText += "Changed from non-native to native."; 28296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project methodDiff.addModifiersChange(changeText); 28396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project } 28496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project // Synchronized or not 28596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project if (Diff.showAllChanges && 28696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project oldMethod.isSynchronized_ != newMethod.isSynchronized_) { 28796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project String changeText = ""; 28896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project if (oldMethod.isSynchronized_) 28996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project changeText += "Changed from synchronized to non-synchronized."; 29096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project else 29196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project changeText += "Changed from non-synchronized to synchronized."; 29296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project methodDiff.addModifiersChange(changeText); 29396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project } 29496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project } 29596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project 29696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project /** 29796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project * Convert some removed and added fields into changed fields. 29896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project */ 29996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project public static void mergeRemoveAddField(FieldAPI removedField, ClassDiff classDiff, PackageDiff pkgDiff) { 30096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project // Search on the name of the field 30196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project int startRemoved = classDiff.fieldsRemoved.indexOf(removedField); 30296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project int endRemoved = classDiff.fieldsRemoved.lastIndexOf(removedField); 30396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project int startAdded = classDiff.fieldsAdded.indexOf(removedField); 30496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project int endAdded = classDiff.fieldsAdded.lastIndexOf(removedField); 30596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project if (startRemoved != -1 && startRemoved == endRemoved && 30696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project startAdded != -1 && startAdded == endAdded) { 30796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project // There is only one field with the name of the 30896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project // removedField in both the removed and added fields. 30996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project FieldAPI addedField = (FieldAPI)(classDiff.fieldsAdded.get(startAdded)); 31096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project if (addedField.inheritedFrom_ == null) { 31196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project // Create a MemberDiff for this change 31296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project MemberDiff fieldDiff = new MemberDiff(removedField.name_); 31396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project fieldDiff.oldType_ = removedField.type_; 31496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project fieldDiff.newType_ = addedField.type_; 31596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project fieldDiff.addModifiersChange(removedField.modifiers_.diff(addedField.modifiers_)); 31696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project // Track changes in documentation 31796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project if (APIComparator.docChanged(removedField.doc_, addedField.doc_)) { 31896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project String fqName = pkgDiff.name_ + "." + classDiff.name_; 31996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project String link1 = "<a href=\"" + fqName + HTMLReportGenerator.reportFileExt + "\" class=\"hiddenlink\">"; 32096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project String link2 = "<a href=\"" + fqName + HTMLReportGenerator.reportFileExt + "#" + fqName + "." + addedField.name_ + "\" class=\"hiddenlink\">"; 32196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project String id = pkgDiff.name_ + "." + classDiff.name_ + ".field." + addedField.name_; 32296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project String title = link1 + "Class <b>" + classDiff.name_ + "</b></a>, " + 32396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project link2 + HTMLReportGenerator.simpleName(fieldDiff.newType_) + " <b>" + addedField.name_ + "</b></a>"; 32496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project fieldDiff.documentationChange_ = Diff.saveDocDiffs(pkgDiff.name_, classDiff.name_, removedField.doc_, addedField.doc_, id, title); 32596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project } 32696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project classDiff.fieldsChanged.add(fieldDiff); 32796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project // Now remove the entries from the remove and add lists 32896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project classDiff.fieldsRemoved.remove(startRemoved); 32996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project classDiff.fieldsAdded.remove(startAdded); 33096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project if (trace) { 33196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project System.out.println("Merged the removal and addition of field " + 33296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project removedField.name_ + 33396b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project " into one change"); 33496b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project } 33596b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project } //if (addedField.inheritedFrom == null) 33696b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project } 33796b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project } 33896b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project 33996b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project /** Set to enable increased logging verbosity for debugging. */ 34096b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project private static boolean trace = false; 34196b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project 34296b00fec6cd6068c1c5ae09de0358340c0ec499eThe Android Open Source Project} 343