
gr.uom.java.xmi.diff.UMLModelDiff Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of refactoring-miner Show documentation
Show all versions of refactoring-miner Show documentation
RefactoringMiner is a library/API written in Java that can detect refactorings applied in the history of a Java project.
package gr.uom.java.xmi.diff;
import gr.uom.java.xmi.UMLAnonymousClass;
import gr.uom.java.xmi.UMLAttribute;
import gr.uom.java.xmi.UMLClass;
import gr.uom.java.xmi.UMLClassMatcher;
import gr.uom.java.xmi.UMLGeneralization;
import gr.uom.java.xmi.UMLOperation;
import gr.uom.java.xmi.UMLParameter;
import gr.uom.java.xmi.UMLRealization;
import gr.uom.java.xmi.UMLType;
import gr.uom.java.xmi.decomposition.AbstractCodeMapping;
import gr.uom.java.xmi.decomposition.AbstractExpression;
import gr.uom.java.xmi.decomposition.CompositeStatementObject;
import gr.uom.java.xmi.decomposition.CompositeStatementObjectMapping;
import gr.uom.java.xmi.decomposition.LeafMapping;
import gr.uom.java.xmi.decomposition.OperationInvocation;
import gr.uom.java.xmi.decomposition.StatementObject;
import gr.uom.java.xmi.decomposition.UMLOperationBodyMapper;
import gr.uom.java.xmi.decomposition.UMLOperationBodyMapperComparator;
import gr.uom.java.xmi.decomposition.VariableDeclaration;
import gr.uom.java.xmi.decomposition.replacement.MergeVariableReplacement;
import gr.uom.java.xmi.decomposition.replacement.Replacement;
import gr.uom.java.xmi.decomposition.replacement.Replacement.ReplacementType;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import org.refactoringminer.api.Refactoring;
import org.refactoringminer.api.RefactoringMinerTimedOutException;
import org.refactoringminer.api.RefactoringType;
import org.refactoringminer.util.PrefixSuffixUtils;
public class UMLModelDiff {
private static final int MAXIMUM_NUMBER_OF_COMPARED_METHODS = 100;
private List addedClasses;
private List removedClasses;
private List addedGeneralizations;
private List removedGeneralizations;
private List generalizationDiffList;
private List addedRealizations;
private List removedRealizations;
private List realizationDiffList;
private List commonClassDiffList;
private List classMoveDiffList;
private List innerClassMoveDiffList;
private List classRenameDiffList;
private List refactorings;
private Set deletedFolderPaths;
public UMLModelDiff() {
this.addedClasses = new ArrayList();
this.removedClasses = new ArrayList();
this.addedGeneralizations = new ArrayList();
this.removedGeneralizations = new ArrayList();
this.generalizationDiffList = new ArrayList();
this.realizationDiffList = new ArrayList();
this.addedRealizations = new ArrayList();
this.removedRealizations = new ArrayList();
this.commonClassDiffList = new ArrayList();
this.classMoveDiffList = new ArrayList();
this.innerClassMoveDiffList = new ArrayList();
this.classRenameDiffList = new ArrayList();
this.refactorings = new ArrayList();
this.deletedFolderPaths = new LinkedHashSet();
}
public void reportAddedClass(UMLClass umlClass) {
if(!addedClasses.contains(umlClass))
this.addedClasses.add(umlClass);
}
public void reportRemovedClass(UMLClass umlClass) {
if(!removedClasses.contains(umlClass))
this.removedClasses.add(umlClass);
}
public void reportAddedGeneralization(UMLGeneralization umlGeneralization) {
this.addedGeneralizations.add(umlGeneralization);
}
public void reportRemovedGeneralization(UMLGeneralization umlGeneralization) {
this.removedGeneralizations.add(umlGeneralization);
}
public void reportAddedRealization(UMLRealization umlRealization) {
this.addedRealizations.add(umlRealization);
}
public void reportRemovedRealization(UMLRealization umlRealization) {
this.removedRealizations.add(umlRealization);
}
public void addUMLClassDiff(UMLClassDiff classDiff) {
this.commonClassDiffList.add(classDiff);
}
public boolean commonlyImplementedOperations(UMLOperation operation1, UMLOperation operation2, UMLClassBaseDiff classDiff2) {
UMLClassBaseDiff classDiff1 = getUMLClassDiff(operation1.getClassName());
if(classDiff1 != null) {
Set commonInterfaces = classDiff1.nextClassCommonInterfaces(classDiff2);
for(UMLType commonInterface : commonInterfaces) {
UMLClassBaseDiff interfaceDiff = getUMLClassDiff(commonInterface);
if(interfaceDiff != null &&
interfaceDiff.containsOperationWithTheSameSignatureInOriginalClass(operation1) &&
interfaceDiff.containsOperationWithTheSameSignatureInNextClass(operation2)) {
return true;
}
}
}
return false;
}
private UMLClassBaseDiff getUMLClassDiff(String className) {
for(UMLClassDiff classDiff : commonClassDiffList) {
if(classDiff.matches(className))
return classDiff;
}
for(UMLClassMoveDiff classDiff : classMoveDiffList) {
if(classDiff.matches(className))
return classDiff;
}
for(UMLClassMoveDiff classDiff : innerClassMoveDiffList) {
if(classDiff.matches(className))
return classDiff;
}
for(UMLClassRenameDiff classDiff : classRenameDiffList) {
if(classDiff.matches(className))
return classDiff;
}
return null;
}
private UMLClassBaseDiff getUMLClassDiff(UMLType type) {
for(UMLClassDiff classDiff : commonClassDiffList) {
if(classDiff.matches(type))
return classDiff;
}
for(UMLClassMoveDiff classDiff : classMoveDiffList) {
if(classDiff.matches(type))
return classDiff;
}
for(UMLClassMoveDiff classDiff : innerClassMoveDiffList) {
if(classDiff.matches(type))
return classDiff;
}
for(UMLClassRenameDiff classDiff : classRenameDiffList) {
if(classDiff.matches(type))
return classDiff;
}
return null;
}
private UMLClassBaseDiff getUMLClassDiffWithAttribute(Replacement pattern) {
for(UMLClassDiff classDiff : commonClassDiffList) {
if(classDiff.findAttributeInOriginalClass(pattern.getBefore()) != null &&
classDiff.findAttributeInNextClass(pattern.getAfter()) != null)
return classDiff;
}
for(UMLClassMoveDiff classDiff : classMoveDiffList) {
if(classDiff.findAttributeInOriginalClass(pattern.getBefore()) != null &&
classDiff.findAttributeInNextClass(pattern.getAfter()) != null)
return classDiff;
}
for(UMLClassMoveDiff classDiff : innerClassMoveDiffList) {
if(classDiff.findAttributeInOriginalClass(pattern.getBefore()) != null &&
classDiff.findAttributeInNextClass(pattern.getAfter()) != null)
return classDiff;
}
for(UMLClassRenameDiff classDiff : classRenameDiffList) {
if(classDiff.findAttributeInOriginalClass(pattern.getBefore()) != null &&
classDiff.findAttributeInNextClass(pattern.getAfter()) != null)
return classDiff;
}
return null;
}
private List getUMLClassDiffWithExistingAttributeAfter(Replacement pattern) {
List classDiffs = new ArrayList();
for(UMLClassDiff classDiff : commonClassDiffList) {
if(classDiff.findAttributeInOriginalClass(pattern.getAfter()) != null &&
classDiff.findAttributeInNextClass(pattern.getAfter()) != null)
classDiffs.add(classDiff);
}
for(UMLClassMoveDiff classDiff : classMoveDiffList) {
if(classDiff.findAttributeInOriginalClass(pattern.getAfter()) != null &&
classDiff.findAttributeInNextClass(pattern.getAfter()) != null)
classDiffs.add(classDiff);
}
for(UMLClassMoveDiff classDiff : innerClassMoveDiffList) {
if(classDiff.findAttributeInOriginalClass(pattern.getAfter()) != null &&
classDiff.findAttributeInNextClass(pattern.getAfter()) != null)
classDiffs.add(classDiff);
}
for(UMLClassRenameDiff classDiff : classRenameDiffList) {
if(classDiff.findAttributeInOriginalClass(pattern.getAfter()) != null &&
classDiff.findAttributeInNextClass(pattern.getAfter()) != null)
classDiffs.add(classDiff);
}
return classDiffs;
}
private List getUMLClassDiffWithNewAttributeAfter(Replacement pattern) {
List classDiffs = new ArrayList();
for(UMLClassDiff classDiff : commonClassDiffList) {
if(classDiff.findAttributeInOriginalClass(pattern.getAfter()) == null &&
classDiff.findAttributeInNextClass(pattern.getAfter()) != null)
classDiffs.add(classDiff);
}
for(UMLClassMoveDiff classDiff : classMoveDiffList) {
if(classDiff.findAttributeInOriginalClass(pattern.getAfter()) == null &&
classDiff.findAttributeInNextClass(pattern.getAfter()) != null)
classDiffs.add(classDiff);
}
for(UMLClassMoveDiff classDiff : innerClassMoveDiffList) {
if(classDiff.findAttributeInOriginalClass(pattern.getAfter()) == null &&
classDiff.findAttributeInNextClass(pattern.getAfter()) != null)
classDiffs.add(classDiff);
}
for(UMLClassRenameDiff classDiff : classRenameDiffList) {
if(classDiff.findAttributeInOriginalClass(pattern.getAfter()) == null &&
classDiff.findAttributeInNextClass(pattern.getAfter()) != null)
classDiffs.add(classDiff);
}
return classDiffs;
}
public boolean isSubclassOf(String subclass, String finalSuperclass) {
return isSubclassOf(subclass, finalSuperclass, new LinkedHashSet());
}
private boolean isSubclassOf(String subclass, String finalSuperclass, Set visitedClasses) {
if(visitedClasses.contains(subclass)) {
return false;
}
else {
visitedClasses.add(subclass);
}
UMLClassBaseDiff subclassDiff = getUMLClassDiff(subclass);
if(subclassDiff == null) {
subclassDiff = getUMLClassDiff(UMLType.extractTypeObject(subclass));
}
if(subclassDiff != null) {
UMLType superclass = subclassDiff.getSuperclass();
if(superclass != null) {
if(checkInheritanceRelationship(superclass, finalSuperclass, visitedClasses)) {
return true;
}
}
else if(subclassDiff.getOldSuperclass() != null && subclassDiff.getNewSuperclass() != null &&
!subclassDiff.getOldSuperclass().equals(subclassDiff.getNewSuperclass()) && looksLikeAddedClass(subclassDiff.getNewSuperclass()) != null) {
UMLClass addedClass = looksLikeAddedClass(subclassDiff.getNewSuperclass());
if(addedClass.getSuperclass() != null) {
return checkInheritanceRelationship(addedClass.getSuperclass(), finalSuperclass, visitedClasses);
}
}
else if(subclassDiff.getOldSuperclass() == null && subclassDiff.getNewSuperclass() != null && looksLikeAddedClass(subclassDiff.getNewSuperclass()) != null) {
UMLClass addedClass = looksLikeAddedClass(subclassDiff.getNewSuperclass());
return checkInheritanceRelationship(UMLType.extractTypeObject(addedClass.getName()), finalSuperclass, visitedClasses);
}
for(UMLType implementedInterface : subclassDiff.getAddedImplementedInterfaces()) {
if(checkInheritanceRelationship(implementedInterface, finalSuperclass, visitedClasses)) {
return true;
}
}
for(UMLType implementedInterface : subclassDiff.getNextClass().getImplementedInterfaces()) {
if(checkInheritanceRelationship(implementedInterface, finalSuperclass, visitedClasses)) {
return true;
}
}
}
UMLClass addedClass = getAddedClass(subclass);
if(addedClass == null) {
addedClass = looksLikeAddedClass(UMLType.extractTypeObject(subclass));
}
if(addedClass != null) {
UMLType superclass = addedClass.getSuperclass();
if(superclass != null) {
return checkInheritanceRelationship(superclass, finalSuperclass, visitedClasses);
}
for(UMLType implementedInterface : addedClass.getImplementedInterfaces()) {
if(checkInheritanceRelationship(implementedInterface, finalSuperclass, visitedClasses)) {
return true;
}
}
}
UMLClass removedClass = getRemovedClass(subclass);
if(removedClass == null) {
removedClass = looksLikeRemovedClass(UMLType.extractTypeObject(subclass));
}
if(removedClass != null) {
UMLType superclass = removedClass.getSuperclass();
if(superclass != null) {
return checkInheritanceRelationship(superclass, finalSuperclass, visitedClasses);
}
for(UMLType implementedInterface : removedClass.getImplementedInterfaces()) {
if(checkInheritanceRelationship(implementedInterface, finalSuperclass, visitedClasses)) {
return true;
}
}
}
return false;
}
private boolean checkInheritanceRelationship(UMLType superclass, String finalSuperclass, Set visitedClasses) {
if(looksLikeSameType(superclass.getClassType(), finalSuperclass))
return true;
else
return isSubclassOf(superclass.getClassType(), finalSuperclass, visitedClasses);
}
private UMLClass looksLikeAddedClass(UMLType type) {
for(UMLClass umlClass : addedClasses) {
if(umlClass.getName().endsWith("." + type.getClassType())) {
return umlClass;
}
}
return null;
}
private UMLClass looksLikeRemovedClass(UMLType type) {
for(UMLClass umlClass : removedClasses) {
if(umlClass.getName().endsWith("." + type.getClassType())) {
return umlClass;
}
}
return null;
}
public UMLClass getAddedClass(String className) {
for(UMLClass umlClass : addedClasses) {
if(umlClass.getName().equals(className))
return umlClass;
}
return null;
}
public UMLClass getRemovedClass(String className) {
for(UMLClass umlClass : removedClasses) {
if(umlClass.getName().equals(className))
return umlClass;
}
return null;
}
private String isRenamedClass(UMLClass umlClass) {
for(UMLClassRenameDiff renameDiff : classRenameDiffList) {
if(renameDiff.getOriginalClass().equals(umlClass))
return renameDiff.getRenamedClass().getName();
}
return null;
}
private String isMovedClass(UMLClass umlClass) {
for(UMLClassMoveDiff moveDiff : classMoveDiffList) {
if(moveDiff.getOriginalClass().equals(umlClass))
return moveDiff.getMovedClass().getName();
}
return null;
}
public void checkForGeneralizationChanges() {
for(Iterator removedGeneralizationIterator = removedGeneralizations.iterator(); removedGeneralizationIterator.hasNext();) {
UMLGeneralization removedGeneralization = removedGeneralizationIterator.next();
for(Iterator addedGeneralizationIterator = addedGeneralizations.iterator(); addedGeneralizationIterator.hasNext();) {
UMLGeneralization addedGeneralization = addedGeneralizationIterator.next();
String renamedChild = isRenamedClass(removedGeneralization.getChild());
String movedChild = isMovedClass(removedGeneralization.getChild());
if(removedGeneralization.getChild().equals(addedGeneralization.getChild())) {
UMLGeneralizationDiff generalizationDiff = new UMLGeneralizationDiff(removedGeneralization, addedGeneralization);
addedGeneralizationIterator.remove();
removedGeneralizationIterator.remove();
generalizationDiffList.add(generalizationDiff);
break;
}
if( (renamedChild != null && renamedChild.equals(addedGeneralization.getChild().getName())) ||
(movedChild != null && movedChild.equals(addedGeneralization.getChild().getName()))) {
UMLGeneralizationDiff generalizationDiff = new UMLGeneralizationDiff(removedGeneralization, addedGeneralization);
addedGeneralizationIterator.remove();
removedGeneralizationIterator.remove();
generalizationDiffList.add(generalizationDiff);
break;
}
}
}
}
public void checkForRealizationChanges() {
for(Iterator removedRealizationIterator = removedRealizations.iterator(); removedRealizationIterator.hasNext();) {
UMLRealization removedRealization = removedRealizationIterator.next();
for(Iterator addedRealizationIterator = addedRealizations.iterator(); addedRealizationIterator.hasNext();) {
UMLRealization addedRealization = addedRealizationIterator.next();
String renamedChild = isRenamedClass(removedRealization.getClient());
String movedChild = isMovedClass(removedRealization.getClient());
//String renamedParent = isRenamedClass(removedRealization.getSupplier());
//String movedParent = isMovedClass(removedRealization.getSupplier());
if( (renamedChild != null && renamedChild.equals(addedRealization.getClient().getName())) ||
(movedChild != null && movedChild.equals(addedRealization.getClient().getName()))) {
UMLRealizationDiff realizationDiff = new UMLRealizationDiff(removedRealization, addedRealization);
addedRealizationIterator.remove();
removedRealizationIterator.remove();
realizationDiffList.add(realizationDiff);
break;
}
}
}
}
public void checkForMovedClasses(Map renamedFileHints, Set repositoryDirectories, UMLClassMatcher matcher) throws RefactoringMinerTimedOutException {
for(Iterator removedClassIterator = removedClasses.iterator(); removedClassIterator.hasNext();) {
UMLClass removedClass = removedClassIterator.next();
TreeSet diffSet = new TreeSet(new ClassMoveComparator());
for(Iterator addedClassIterator = addedClasses.iterator(); addedClassIterator.hasNext();) {
UMLClass addedClass = addedClassIterator.next();
String removedClassSourceFile = removedClass.getSourceFile();
String renamedFile = renamedFileHints.get(removedClassSourceFile);
String removedClassSourceFolder = "";
if(removedClassSourceFile.contains("/")) {
removedClassSourceFolder = removedClassSourceFile.substring(0, removedClassSourceFile.lastIndexOf("/"));
}
if(!repositoryDirectories.contains(removedClassSourceFolder)) {
deletedFolderPaths.add(removedClassSourceFolder);
//add deleted sub-directories
String subDirectory = new String(removedClassSourceFolder);
while(subDirectory.contains("/")) {
subDirectory = subDirectory.substring(0, subDirectory.lastIndexOf("/"));
if(!repositoryDirectories.contains(subDirectory)) {
deletedFolderPaths.add(subDirectory);
}
}
}
if(matcher.match(removedClass, addedClass, renamedFile)) {
if(!conflictingMoveOfTopLevelClass(removedClass, addedClass)) {
UMLClassMoveDiff classMoveDiff = new UMLClassMoveDiff(removedClass, addedClass, this);
diffSet.add(classMoveDiff);
}
}
}
if(!diffSet.isEmpty()) {
UMLClassMoveDiff minClassMoveDiff = diffSet.first();
minClassMoveDiff.process();
classMoveDiffList.add(minClassMoveDiff);
addedClasses.remove(minClassMoveDiff.getMovedClass());
removedClassIterator.remove();
}
}
List allClassMoves = new ArrayList(this.classMoveDiffList);
Collections.sort(allClassMoves);
for(int i=0; i renamedFileHints, UMLClassMatcher matcher) throws RefactoringMinerTimedOutException {
for(Iterator removedClassIterator = removedClasses.iterator(); removedClassIterator.hasNext();) {
UMLClass removedClass = removedClassIterator.next();
TreeSet diffSet = new TreeSet(new ClassRenameComparator());
for(Iterator addedClassIterator = addedClasses.iterator(); addedClassIterator.hasNext();) {
UMLClass addedClass = addedClassIterator.next();
String renamedFile = renamedFileHints.get(removedClass.getSourceFile());
if(matcher.match(removedClass, addedClass, renamedFile)) {
if(!conflictingMoveOfTopLevelClass(removedClass, addedClass) && !innerClassWithTheSameName(removedClass, addedClass)) {
UMLClassRenameDiff classRenameDiff = new UMLClassRenameDiff(removedClass, addedClass, this);
diffSet.add(classRenameDiff);
}
}
}
if(!diffSet.isEmpty()) {
UMLClassRenameDiff minClassRenameDiff = diffSet.first();
minClassRenameDiff.process();
classRenameDiffList.add(minClassRenameDiff);
addedClasses.remove(minClassRenameDiff.getRenamedClass());
removedClassIterator.remove();
}
}
List allClassMoves = new ArrayList(this.classMoveDiffList);
Collections.sort(allClassMoves);
for(UMLClassRenameDiff classRename : classRenameDiffList) {
for(UMLClassMoveDiff classMove : allClassMoves) {
if(classRename.isInnerClassMove(classMove)) {
innerClassMoveDiffList.add(classMove);
}
}
}
this.classMoveDiffList.removeAll(innerClassMoveDiffList);
}
private boolean innerClassWithTheSameName(UMLClass removedClass, UMLClass addedClass) {
if(!removedClass.isTopLevel() && !addedClass.isTopLevel()) {
String removedClassName = removedClass.getName();
String removedName = removedClassName.substring(removedClassName.lastIndexOf(".")+1, removedClassName.length());
String addedClassName = addedClass.getName();
String addedName = addedClassName.substring(addedClassName.lastIndexOf(".")+1, addedClassName.length());
if(removedName.equals(addedName)) {
return true;
}
}
return false;
}
public List getAddedGeneralizations() {
return addedGeneralizations;
}
public List getAddedRealizations() {
return addedRealizations;
}
private List checkForAttributeMovesIncludingRemovedClasses() {
List addedAttributes = getAddedAttributesInCommonClasses();
/*for(UMLClass addedClass : addedClasses) {
addedAttributes.addAll(addedClass.getAttributes());
}*/
List removedAttributes = getRemovedAttributesInCommonClasses();
for(UMLClass removedClass : removedClasses) {
removedAttributes.addAll(removedClass.getAttributes());
}
return checkForAttributeMoves(addedAttributes, removedAttributes);
}
private List checkForAttributeMovesIncludingAddedClasses() {
List addedAttributes = getAddedAttributesInCommonClasses();
for(UMLClass addedClass : addedClasses) {
addedAttributes.addAll(addedClass.getAttributes());
}
List removedAttributes = getRemovedAttributesInCommonClasses();
/*for(UMLClass removedClass : removedClasses) {
removedAttributes.addAll(removedClass.getAttributes());
}*/
return checkForAttributeMoves(addedAttributes, removedAttributes);
}
private List checkForAttributeMovesBetweenCommonClasses() {
List addedAttributes = getAddedAttributesInCommonClasses();
List removedAttributes = getRemovedAttributesInCommonClasses();
return checkForAttributeMoves(addedAttributes, removedAttributes);
}
private List checkForAttributeMovesBetweenRemovedAndAddedClasses() {
List addedAttributes = new ArrayList();
for(UMLClass addedClass : addedClasses) {
addedAttributes.addAll(addedClass.getAttributes());
}
List removedAttributes = new ArrayList();
for(UMLClass removedClass : removedClasses) {
removedAttributes.addAll(removedClass.getAttributes());
}
return checkForAttributeMoves(addedAttributes, removedAttributes);
}
private List checkForAttributeMoves(List addedAttributes, List removedAttributes) {
List refactorings = new ArrayList();
if(addedAttributes.size() <= removedAttributes.size()) {
for(UMLAttribute addedAttribute : addedAttributes) {
List candidates = new ArrayList();
for(UMLAttribute removedAttribute : removedAttributes) {
MoveAttributeRefactoring candidate = processPairOfAttributes(addedAttribute, removedAttribute);
if(candidate != null) {
candidates.add(candidate);
}
}
processCandidates(candidates, refactorings);
}
}
else {
for(UMLAttribute removedAttribute : removedAttributes) {
List candidates = new ArrayList();
for(UMLAttribute addedAttribute : addedAttributes) {
MoveAttributeRefactoring candidate = processPairOfAttributes(addedAttribute, removedAttribute);
if(candidate != null) {
candidates.add(candidate);
}
}
processCandidates(candidates, refactorings);
}
}
return refactorings;
}
private List filterOutDuplicateRefactorings(Set refactorings) {
List filtered = new ArrayList();
Map> map = new LinkedHashMap>();
for(Refactoring ref : refactorings) {
if(map.containsKey(ref.toString())) {
map.get(ref.toString()).add(ref);
}
else {
List refs = new ArrayList();
refs.add(ref);
map.put(ref.toString(), refs);
}
}
for(String key : map.keySet()) {
List refs = map.get(key);
if(refs.size() == 1) {
filtered.addAll(refs);
}
else {
filtered.addAll(filterOutBasedOnFilePath(refs));
}
}
return filtered;
}
private List filterOutBasedOnFilePath(List refs) {
List filtered = new ArrayList();
Map> groupBySourceFilePath = new LinkedHashMap>();
for(Refactoring ref : refs) {
String sourceFilePath = ref.getInvolvedClassesBeforeRefactoring().iterator().next().getLeft();
if(groupBySourceFilePath.containsKey(sourceFilePath)) {
groupBySourceFilePath.get(sourceFilePath).add(ref);
}
else {
List refs2 = new ArrayList();
refs2.add(ref);
groupBySourceFilePath.put(sourceFilePath, refs2);
}
}
for(String sourceFilePath : groupBySourceFilePath.keySet()) {
List sourceFilePathGroup = groupBySourceFilePath.get(sourceFilePath);
TreeMap> groupByLongestCommonSourceFilePath = new TreeMap>();
for(Refactoring ref : sourceFilePathGroup) {
String longestCommonFilePathPrefix = PrefixSuffixUtils.longestCommonPrefix(ref.getInvolvedClassesBeforeRefactoring().iterator().next().getLeft(),
ref.getInvolvedClassesAfterRefactoring().iterator().next().getLeft());
int length = longestCommonFilePathPrefix.length();
if(groupByLongestCommonSourceFilePath.containsKey(length)) {
groupByLongestCommonSourceFilePath.get(length).add(ref);
}
else {
List refs2 = new ArrayList();
refs2.add(ref);
groupByLongestCommonSourceFilePath.put(length, refs2);
}
}
filtered.addAll(groupByLongestCommonSourceFilePath.lastEntry().getValue());
}
return filtered;
}
private void processCandidates(List candidates, List refactorings) {
if(candidates.size() > 1) {
TreeMap> map = new TreeMap>();
for(MoveAttributeRefactoring candidate : candidates) {
int compatibility = computeCompatibility(candidate);
if(map.containsKey(compatibility)) {
map.get(compatibility).add(candidate);
}
else {
List refs = new ArrayList();
refs.add(candidate);
map.put(compatibility, refs);
}
}
int maxCompatibility = map.lastKey();
refactorings.addAll(map.get(maxCompatibility));
}
else if(candidates.size() == 1) {
refactorings.addAll(candidates);
}
}
private MoveAttributeRefactoring processPairOfAttributes(UMLAttribute addedAttribute, UMLAttribute removedAttribute) {
if(addedAttribute.getName().equals(removedAttribute.getName()) &&
addedAttribute.getType().equals(removedAttribute.getType())) {
if(isSubclassOf(removedAttribute.getClassName(), addedAttribute.getClassName())) {
PullUpAttributeRefactoring pullUpAttribute = new PullUpAttributeRefactoring(removedAttribute, addedAttribute);
return pullUpAttribute;
}
else if(isSubclassOf(addedAttribute.getClassName(), removedAttribute.getClassName())) {
PushDownAttributeRefactoring pushDownAttribute = new PushDownAttributeRefactoring(removedAttribute, addedAttribute);
return pushDownAttribute;
}
else if(sourceClassImportsTargetClass(removedAttribute.getClassName(), addedAttribute.getClassName()) ||
targetClassImportsSourceClass(removedAttribute.getClassName(), addedAttribute.getClassName())) {
if(!initializerContainsTypeLiteral(addedAttribute, removedAttribute)) {
MoveAttributeRefactoring moveAttribute = new MoveAttributeRefactoring(removedAttribute, addedAttribute);
return moveAttribute;
}
}
}
return null;
}
private boolean initializerContainsTypeLiteral(UMLAttribute addedAttribute, UMLAttribute removedAttribute) {
VariableDeclaration v1 = addedAttribute.getVariableDeclaration();
VariableDeclaration v2 = removedAttribute.getVariableDeclaration();
if(v1.getInitializer() != null && v2.getInitializer() != null) {
List typeLiterals1 = v1.getInitializer().getTypeLiterals();
List typeLiterals2 = v2.getInitializer().getTypeLiterals();
String className1 = addedAttribute.getNonQualifiedClassName();
String className2 = removedAttribute.getNonQualifiedClassName();
if(typeLiterals1.contains(className1 + ".class") && typeLiterals2.contains(className2 + ".class") &&
addedAttribute.getType().getClassType().endsWith("Logger") && removedAttribute.getType().getClassType().endsWith("Logger")) {
return true;
}
}
return false;
}
private int computeCompatibility(MoveAttributeRefactoring candidate) {
int count = 0;
for(Refactoring ref : refactorings) {
if(ref instanceof MoveOperationRefactoring) {
MoveOperationRefactoring moveRef = (MoveOperationRefactoring)ref;
if(moveRef.compatibleWith(candidate)) {
count++;
}
}
}
UMLClassBaseDiff sourceClassDiff = getUMLClassDiff(candidate.getSourceClassName());
UMLClassBaseDiff targetClassDiff = getUMLClassDiff(candidate.getTargetClassName());
if(sourceClassDiff != null) {
UMLType targetSuperclass = null;
if(targetClassDiff != null) {
targetSuperclass = targetClassDiff.getSuperclass();
}
List addedAttributes = sourceClassDiff.getAddedAttributes();
for(UMLAttribute addedAttribute : addedAttributes) {
if(looksLikeSameType(addedAttribute.getType().getClassType(), candidate.getTargetClassName())) {
count++;
}
if(targetSuperclass != null && looksLikeSameType(addedAttribute.getType().getClassType(), targetSuperclass.getClassType())) {
count++;
}
}
List originalAttributes = sourceClassDiff.originalClassAttributesOfType(candidate.getTargetClassName());
List nextAttributes = sourceClassDiff.nextClassAttributesOfType(candidate.getTargetClassName());
if(targetSuperclass != null) {
originalAttributes.addAll(sourceClassDiff.originalClassAttributesOfType(targetSuperclass.getClassType()));
nextAttributes.addAll(sourceClassDiff.nextClassAttributesOfType(targetSuperclass.getClassType()));
}
Set intersection = new LinkedHashSet(originalAttributes);
intersection.retainAll(nextAttributes);
if(!intersection.isEmpty()) {
count++;
}
}
return count;
}
private boolean sourceClassImportsSuperclassOfTargetClass(String sourceClassName, String targetClassName) {
UMLClassBaseDiff targetClassDiff = getUMLClassDiff(targetClassName);
if(targetClassDiff != null && targetClassDiff.getSuperclass() != null) {
UMLClassBaseDiff superclassOfTargetClassDiff = getUMLClassDiff(targetClassDiff.getSuperclass());
if(superclassOfTargetClassDiff != null) {
return sourceClassImportsTargetClass(sourceClassName, superclassOfTargetClassDiff.getNextClassName());
}
}
return false;
}
private boolean sourceClassImportsTargetClass(String sourceClassName, String targetClassName) {
UMLClassBaseDiff classDiff = getUMLClassDiff(sourceClassName);
if(classDiff == null) {
classDiff = getUMLClassDiff(UMLType.extractTypeObject(sourceClassName));
}
if(classDiff != null) {
return classDiff.nextClassImportsType(targetClassName) || classDiff.originalClassImportsType(targetClassName);
}
UMLClass removedClass = getRemovedClass(sourceClassName);
if(removedClass == null) {
removedClass = looksLikeRemovedClass(UMLType.extractTypeObject(sourceClassName));
}
if(removedClass != null) {
return removedClass.importsType(targetClassName);
}
return false;
}
private boolean targetClassImportsSourceClass(String sourceClassName, String targetClassName) {
UMLClassBaseDiff classDiff = getUMLClassDiff(targetClassName);
if(classDiff == null) {
classDiff = getUMLClassDiff(UMLType.extractTypeObject(targetClassName));
}
if(classDiff != null) {
return classDiff.originalClassImportsType(sourceClassName) || classDiff.nextClassImportsType(sourceClassName);
}
UMLClass addedClass = getAddedClass(targetClassName);
if(addedClass == null) {
addedClass = looksLikeAddedClass(UMLType.extractTypeObject(targetClassName));
}
if(addedClass != null) {
return addedClass.importsType(sourceClassName);
}
return false;
}
private List getAddedAttributesInCommonClasses() {
List addedAttributes = new ArrayList();
for(UMLClassDiff classDiff : commonClassDiffList) {
addedAttributes.addAll(classDiff.getAddedAttributes());
}
return addedAttributes;
}
private List getRemovedAttributesInCommonClasses() {
List removedAttributes = new ArrayList();
for(UMLClassDiff classDiff : commonClassDiffList) {
removedAttributes.addAll(classDiff.getRemovedAttributes());
}
return removedAttributes;
}
private List getAddedOperationsInCommonClasses() {
List addedOperations = new ArrayList();
for(UMLClassDiff classDiff : commonClassDiffList) {
addedOperations.addAll(classDiff.getAddedOperations());
}
return addedOperations;
}
private List getAddedAndExtractedOperationsInCommonClasses() {
List addedOperations = new ArrayList();
for(UMLClassDiff classDiff : commonClassDiffList) {
addedOperations.addAll(classDiff.getAddedOperations());
for(Refactoring ref : classDiff.getRefactorings()) {
if(ref instanceof ExtractOperationRefactoring) {
ExtractOperationRefactoring extractRef = (ExtractOperationRefactoring)ref;
addedOperations.add(extractRef.getExtractedOperation());
}
}
}
return addedOperations;
}
private List getAddedOperationsInMovedAndRenamedClasses() {
List addedOperations = new ArrayList();
for(UMLClassMoveDiff classDiff : innerClassMoveDiffList) {
addedOperations.addAll(classDiff.getAddedOperations());
}
for(UMLClassMoveDiff classDiff : classMoveDiffList) {
addedOperations.addAll(classDiff.getAddedOperations());
}
for(UMLClassRenameDiff classDiff : classRenameDiffList) {
addedOperations.addAll(classDiff.getAddedOperations());
}
return addedOperations;
}
private List getRemovedOperationsInCommonClasses() {
List removedOperations = new ArrayList();
for(UMLClassDiff classDiff : commonClassDiffList) {
removedOperations.addAll(classDiff.getRemovedOperations());
}
return removedOperations;
}
private List getRemovedOperationsInCommonMovedRenamedClasses() {
List removedOperations = new ArrayList();
for(UMLClassDiff classDiff : commonClassDiffList) {
removedOperations.addAll(classDiff.getRemovedOperations());
}
for(UMLClassMoveDiff classDiff : classMoveDiffList) {
removedOperations.addAll(classDiff.getRemovedOperations());
}
for(UMLClassMoveDiff classDiff : innerClassMoveDiffList) {
removedOperations.addAll(classDiff.getRemovedOperations());
}
for(UMLClassRenameDiff classDiff : classRenameDiffList) {
removedOperations.addAll(classDiff.getRemovedOperations());
}
return removedOperations;
}
private List getRemovedAndInlinedOperationsInCommonClasses() {
List removedOperations = new ArrayList();
for(UMLClassDiff classDiff : commonClassDiffList) {
removedOperations.addAll(classDiff.getRemovedOperations());
for(Refactoring ref : classDiff.getRefactorings()) {
if(ref instanceof InlineOperationRefactoring) {
InlineOperationRefactoring extractRef = (InlineOperationRefactoring)ref;
removedOperations.add(extractRef.getInlinedOperation());
}
}
}
return removedOperations;
}
private List getOperationBodyMappersInCommonClasses() {
List mappers = new ArrayList();
for(UMLClassDiff classDiff : commonClassDiffList) {
mappers.addAll(classDiff.getOperationBodyMapperList());
}
return mappers;
}
private List getOperationBodyMappersInMovedAndRenamedClasses() {
List mappers = new ArrayList();
for(UMLClassMoveDiff classDiff : classMoveDiffList) {
mappers.addAll(classDiff.getOperationBodyMapperList());
}
for(UMLClassMoveDiff classDiff : innerClassMoveDiffList) {
mappers.addAll(classDiff.getOperationBodyMapperList());
}
for(UMLClassRenameDiff classDiff : classRenameDiffList) {
mappers.addAll(classDiff.getOperationBodyMapperList());
}
return mappers;
}
private List identifyExtractClassRefactorings(List extends UMLClassBaseDiff> classDiffs) throws RefactoringMinerTimedOutException {
List refactorings = new ArrayList();
for(UMLClass addedClass : addedClasses) {
List candidates = new ArrayList();
UMLType addedClassSuperType = addedClass.getSuperclass();
if(!addedClass.isInterface()) {
for(UMLClassBaseDiff classDiff : classDiffs) {
UMLType classDiffSuperType = classDiff.getNewSuperclass();
boolean commonSuperType = addedClassSuperType != null && classDiffSuperType != null &&
addedClassSuperType.getClassType().equals(classDiffSuperType.getClassType());
boolean commonInterface = false;
for(UMLType addedClassInterface : addedClass.getImplementedInterfaces()) {
for(UMLType classDiffInterface : classDiff.getNextClass().getImplementedInterfaces()) {
if(addedClassInterface.getClassType().equals(classDiffInterface.getClassType())) {
commonInterface = true;
break;
}
}
if(commonInterface)
break;
}
boolean extendsAddedClass = classDiff.getNewSuperclass() != null &&
addedClass.getName().endsWith("." + classDiff.getNewSuperclass().getClassType());
UMLAttribute attributeOfExtractedClassType = attributeOfExtractedClassType(addedClass, classDiff);
boolean isTestClass = addedClass.isTestClass() && classDiff.getOriginalClass().isTestClass();
if((!commonSuperType && !commonInterface && !extendsAddedClass) || attributeOfExtractedClassType != null || isTestClass) {
ExtractClassRefactoring refactoring = atLeastOneCommonAttributeOrOperation(addedClass, classDiff, attributeOfExtractedClassType);
if(refactoring != null) {
CandidateExtractClassRefactoring candidate = new CandidateExtractClassRefactoring(classDiff, refactoring);
candidates.add(candidate);
}
}
}
}
if(!candidates.isEmpty()) {
boolean innerClassExtract = false;
for(CandidateExtractClassRefactoring candidate : candidates) {
if(candidate.innerClassExtract()) {
innerClassExtract = true;
detectSubRefactorings(candidate.getClassDiff(),
candidate.getRefactoring().getExtractedClass(),
candidate.getRefactoring().getRefactoringType());
refactorings.add(candidate.getRefactoring());
break;
}
}
if(!innerClassExtract) {
for(CandidateExtractClassRefactoring candidate : candidates) {
detectSubRefactorings(candidate.getClassDiff(),
candidate.getRefactoring().getExtractedClass(),
candidate.getRefactoring().getRefactoringType());
refactorings.add(candidate.getRefactoring());
}
}
}
}
return refactorings;
}
private UMLAttribute attributeOfExtractedClassType(UMLClass umlClass, UMLClassBaseDiff classDiff) {
List addedAttributes = classDiff.getAddedAttributes();
for(UMLAttribute addedAttribute : addedAttributes) {
if(umlClass.getName().endsWith("." + addedAttribute.getType().getClassType())) {
return addedAttribute;
}
}
return null;
}
private ExtractClassRefactoring atLeastOneCommonAttributeOrOperation(UMLClass umlClass, UMLClassBaseDiff classDiff, UMLAttribute attributeOfExtractedClassType) {
Set commonOperations = new LinkedHashSet();
for(UMLOperation operation : classDiff.getRemovedOperations()) {
if(!operation.isConstructor() && !operation.overridesObject()) {
if(umlClass.containsOperationWithTheSameSignatureIgnoringChangedTypes(operation)) {
commonOperations.add(operation);
}
}
}
Set commonAttributes = new LinkedHashSet();
for(UMLAttribute attribute : classDiff.getRemovedAttributes()) {
if(umlClass.containsAttributeWithTheSameNameIgnoringChangedType(attribute)) {
commonAttributes.add(attribute);
}
}
int threshold = 1;
if(attributeOfExtractedClassType != null)
threshold = 0;
if(commonOperations.size() > threshold || commonAttributes.size() > threshold) {
return new ExtractClassRefactoring(umlClass, classDiff, commonOperations, commonAttributes, attributeOfExtractedClassType);
}
return null;
}
private List identifyExtractSuperclassRefactorings() throws RefactoringMinerTimedOutException {
List refactorings = new ArrayList();
for(UMLClass addedClass : addedClasses) {
Set subclassSet = new LinkedHashSet();
String addedClassName = addedClass.getName();
for(UMLGeneralization addedGeneralization : addedGeneralizations) {
processAddedGeneralization(addedClass, subclassSet, addedGeneralization);
}
for(UMLGeneralizationDiff generalizationDiff : generalizationDiffList) {
UMLGeneralization addedGeneralization = generalizationDiff.getAddedGeneralization();
UMLGeneralization removedGeneralization = generalizationDiff.getRemovedGeneralization();
if(!addedGeneralization.getParent().equals(removedGeneralization.getParent())) {
processAddedGeneralization(addedClass, subclassSet, addedGeneralization);
}
}
for(UMLRealization addedRealization : addedRealizations) {
String supplier = addedRealization.getSupplier();
if(looksLikeSameType(supplier, addedClassName) && topLevelOrSameOuterClass(addedClass, addedRealization.getClient()) && getAddedClass(addedRealization.getClient().getName()) == null) {
UMLClassBaseDiff clientClassDiff = getUMLClassDiff(addedRealization.getClient().getName());
int implementedInterfaceOperations = 0;
boolean clientImplementsSupplier = false;
if(clientClassDiff != null) {
for(UMLOperation interfaceOperation : addedClass.getOperations()) {
if(clientClassDiff.containsOperationWithTheSameSignatureInOriginalClass(interfaceOperation)) {
implementedInterfaceOperations++;
}
}
clientImplementsSupplier = clientClassDiff.getOriginalClass().getImplementedInterfaces().contains(UMLType.extractTypeObject(supplier));
}
if((implementedInterfaceOperations > 0 || addedClass.getOperations().size() == 0) && !clientImplementsSupplier)
subclassSet.add(addedRealization.getClient());
}
}
if(subclassSet.size() > 0) {
ExtractSuperclassRefactoring extractSuperclassRefactoring = new ExtractSuperclassRefactoring(addedClass, subclassSet);
refactorings.add(extractSuperclassRefactoring);
}
}
return refactorings;
}
private void processAddedGeneralization(UMLClass addedClass, Set subclassSet, UMLGeneralization addedGeneralization) throws RefactoringMinerTimedOutException {
String parent = addedGeneralization.getParent();
UMLClass subclass = addedGeneralization.getChild();
if(looksLikeSameType(parent, addedClass.getName()) && topLevelOrSameOuterClass(addedClass, subclass) && getAddedClass(subclass.getName()) == null) {
UMLClassBaseDiff subclassDiff = getUMLClassDiff(subclass.getName());
if(subclassDiff != null) {
detectSubRefactorings(subclassDiff, addedClass, RefactoringType.EXTRACT_SUPERCLASS);
}
subclassSet.add(subclass);
}
}
private void detectSubRefactorings(UMLClassBaseDiff classDiff, UMLClass addedClass, RefactoringType parentType) throws RefactoringMinerTimedOutException {
for(UMLOperation addedOperation : addedClass.getOperations()) {
UMLOperation removedOperation = classDiff.containsRemovedOperationWithTheSameSignature(addedOperation);
if(removedOperation != null) {
classDiff.getRemovedOperations().remove(removedOperation);
Refactoring ref = null;
if(parentType.equals(RefactoringType.EXTRACT_SUPERCLASS)) {
ref = new PullUpOperationRefactoring(removedOperation, addedOperation);
}
else if(parentType.equals(RefactoringType.EXTRACT_CLASS)) {
ref = new MoveOperationRefactoring(removedOperation, addedOperation);
}
else if(parentType.equals(RefactoringType.EXTRACT_SUBCLASS)) {
ref = new PushDownOperationRefactoring(removedOperation, addedOperation);
}
this.refactorings.add(ref);
UMLOperationBodyMapper mapper = new UMLOperationBodyMapper(removedOperation, addedOperation, classDiff);
UMLOperationDiff operationSignatureDiff = new UMLOperationDiff(removedOperation, addedOperation, mapper.getMappings());
refactorings.addAll(operationSignatureDiff.getRefactorings());
checkForExtractedOperationsWithinMovedMethod(mapper, addedClass);
}
}
for(UMLAttribute addedAttribute : addedClass.getAttributes()) {
UMLAttribute removedAttribute = classDiff.containsRemovedAttributeWithTheSameSignature(addedAttribute);
if(removedAttribute != null) {
classDiff.getRemovedAttributes().remove(removedAttribute);
Refactoring ref = null;
if(parentType.equals(RefactoringType.EXTRACT_SUPERCLASS)) {
ref = new PullUpAttributeRefactoring(removedAttribute, addedAttribute);
}
else if(parentType.equals(RefactoringType.EXTRACT_CLASS)) {
ref = new MoveAttributeRefactoring(removedAttribute, addedAttribute);
}
else if(parentType.equals(RefactoringType.EXTRACT_SUBCLASS)) {
ref = new PushDownAttributeRefactoring(removedAttribute, addedAttribute);
}
this.refactorings.add(ref);
}
}
}
private void checkForExtractedOperationsWithinMovedMethod(UMLOperationBodyMapper movedMethodMapper, UMLClass addedClass) throws RefactoringMinerTimedOutException {
UMLOperation removedOperation = movedMethodMapper.getOperation1();
UMLOperation addedOperation = movedMethodMapper.getOperation2();
List removedInvocations = removedOperation.getAllOperationInvocations();
List addedInvocations = addedOperation.getAllOperationInvocations();
Set intersection = new LinkedHashSet(removedInvocations);
intersection.retainAll(addedInvocations);
Set newInvocations = new LinkedHashSet(addedInvocations);
newInvocations.removeAll(intersection);
for(OperationInvocation newInvocation : newInvocations) {
for(UMLOperation operation : addedClass.getOperations()) {
if(!operation.isAbstract() && !operation.hasEmptyBody() &&
newInvocation.matchesOperation(operation, addedOperation.variableTypeMap(), this)) {
ExtractOperationDetection detection = new ExtractOperationDetection(movedMethodMapper, addedClass.getOperations(), getUMLClassDiff(operation.getClassName()), this);
List refs = detection.check(operation);
this.refactorings.addAll(refs);
}
}
}
}
private boolean topLevelOrSameOuterClass(UMLClass class1, UMLClass class2) {
if(!class1.isTopLevel() && !class2.isTopLevel()) {
return class1.getPackageName().equals(class2.getPackageName());
}
return true;
}
public static boolean looksLikeSameType(String parent, String addedClassName) {
if (addedClassName.contains(".") && !parent.contains(".")) {
return parent.equals(addedClassName.substring(addedClassName.lastIndexOf(".") + 1));
}
if (parent.contains(".") && !addedClassName.contains(".")) {
return addedClassName.equals(parent.substring(parent.lastIndexOf(".") + 1));
}
if (parent.contains(".") && addedClassName.contains(".")) {
return UMLType.extractTypeObject(parent).equalClassType(UMLType.extractTypeObject(addedClassName));
}
return parent.equals(addedClassName);
}
private List identifyConvertAnonymousClassToTypeRefactorings() {
List refactorings = new ArrayList();
for(UMLClassDiff classDiff : commonClassDiffList) {
for(UMLAnonymousClass anonymousClass : classDiff.getRemovedAnonymousClasses()) {
for(UMLClass addedClass : addedClasses) {
if(addedClass.getAttributes().containsAll(anonymousClass.getAttributes()) &&
addedClass.getOperations().containsAll(anonymousClass.getOperations())) {
ConvertAnonymousClassToTypeRefactoring refactoring = new ConvertAnonymousClassToTypeRefactoring(anonymousClass, addedClass);
refactorings.add(refactoring);
}
}
}
}
return refactorings;
}
private List getMoveClassRefactorings() {
List refactorings = new ArrayList();
List renamePackageRefactorings = new ArrayList();
List moveSourceFolderRefactorings = new ArrayList();
for(UMLClassMoveDiff classMoveDiff : classMoveDiffList) {
UMLClass originalClass = classMoveDiff.getOriginalClass();
String originalName = originalClass.getName();
UMLClass movedClass = classMoveDiff.getMovedClass();
String movedName = movedClass.getName();
String originalPath = originalClass.getSourceFile();
String movedPath = movedClass.getSourceFile();
String originalPathPrefix = "";
if(originalPath.contains("/")) {
originalPathPrefix = originalPath.substring(0, originalPath.lastIndexOf('/'));
}
String movedPathPrefix = "";
if(movedPath.contains("/")) {
movedPathPrefix = movedPath.substring(0, movedPath.lastIndexOf('/'));
}
if (!originalName.equals(movedName)) {
MoveClassRefactoring refactoring = new MoveClassRefactoring(originalClass, movedClass);
RenamePattern renamePattern = refactoring.getRenamePattern();
//check if the the original path is a substring of the moved path and vice versa
if(renamePattern.getBefore().contains(renamePattern.getAfter()) ||
renamePattern.getAfter().contains(renamePattern.getBefore()) ||
!originalClass.isTopLevel() || !movedClass.isTopLevel()) {
refactorings.add(refactoring);
}
else {
boolean foundInMatchingRenamePackageRefactoring = false;
for(RenamePackageRefactoring renamePackageRefactoring : renamePackageRefactorings) {
if(renamePackageRefactoring.getPattern().equals(renamePattern)) {
renamePackageRefactoring.addMoveClassRefactoring(refactoring);
foundInMatchingRenamePackageRefactoring = true;
break;
}
}
if(!foundInMatchingRenamePackageRefactoring) {
renamePackageRefactorings.add(new RenamePackageRefactoring(refactoring));
}
}
} else if(!originalPathPrefix.equals(movedPathPrefix)) {
MovedClassToAnotherSourceFolder refactoring = new MovedClassToAnotherSourceFolder(originalClass, movedClass, originalPathPrefix, movedPathPrefix);
RenamePattern renamePattern = refactoring.getRenamePattern();
boolean foundInMatchingMoveSourceFolderRefactoring = false;
for(MoveSourceFolderRefactoring moveSourceFolderRefactoring : moveSourceFolderRefactorings) {
if(moveSourceFolderRefactoring.getPattern().equals(renamePattern)) {
moveSourceFolderRefactoring.addMovedClassToAnotherSourceFolder(refactoring);
foundInMatchingMoveSourceFolderRefactoring = true;
break;
}
}
if(!foundInMatchingMoveSourceFolderRefactoring) {
moveSourceFolderRefactorings.add(new MoveSourceFolderRefactoring(refactoring));
}
}
}
for(RenamePackageRefactoring renamePackageRefactoring : renamePackageRefactorings) {
List moveClassRefactorings = renamePackageRefactoring.getMoveClassRefactorings();
if(moveClassRefactorings.size() > 1 && isSourcePackageDeleted(renamePackageRefactoring)) {
refactorings.add(renamePackageRefactoring);
}
//else {
refactorings.addAll(moveClassRefactorings);
//}
}
refactorings.addAll(moveSourceFolderRefactorings);
return refactorings;
}
private boolean isSourcePackageDeleted(RenamePackageRefactoring renamePackageRefactoring) {
for(String deletedFolderPath : deletedFolderPaths) {
String originalPath = renamePackageRefactoring.getPattern().getBefore();
//remove last .
String trimmedOriginalPath = originalPath.endsWith(".") ? originalPath.substring(0, originalPath.length()-1) : originalPath;
String convertedPackageToFilePath = trimmedOriginalPath.replaceAll("\\.", "/");
if(deletedFolderPath.endsWith(convertedPackageToFilePath)) {
return true;
}
}
return false;
}
private List getRenameClassRefactorings() {
List refactorings = new ArrayList();
for(UMLClassRenameDiff classRenameDiff : classRenameDiffList) {
Refactoring refactoring = null;
if(classRenameDiff.samePackage())
refactoring = new RenameClassRefactoring(classRenameDiff.getOriginalClass(), classRenameDiff.getRenamedClass());
else
refactoring = new MoveAndRenameClassRefactoring(classRenameDiff.getOriginalClass(), classRenameDiff.getRenamedClass());
refactorings.add(refactoring);
}
return refactorings;
}
public List getRefactorings() throws RefactoringMinerTimedOutException {
Set refactorings = new LinkedHashSet();
refactorings.addAll(getMoveClassRefactorings());
refactorings.addAll(getRenameClassRefactorings());
refactorings.addAll(identifyConvertAnonymousClassToTypeRefactorings());
Map> renameMap = new LinkedHashMap>();
Map> mergeMap = new LinkedHashMap>();
for(UMLClassDiff classDiff : commonClassDiffList) {
refactorings.addAll(classDiff.getRefactorings());
extractMergePatterns(classDiff, mergeMap);
extractRenamePatterns(classDiff, renameMap);
}
for(UMLClassMoveDiff classDiff : classMoveDiffList) {
refactorings.addAll(classDiff.getRefactorings());
extractMergePatterns(classDiff, mergeMap);
extractRenamePatterns(classDiff, renameMap);
}
for(UMLClassMoveDiff classDiff : innerClassMoveDiffList) {
refactorings.addAll(classDiff.getRefactorings());
extractMergePatterns(classDiff, mergeMap);
extractRenamePatterns(classDiff, renameMap);
}
for(UMLClassRenameDiff classDiff : classRenameDiffList) {
refactorings.addAll(classDiff.getRefactorings());
extractMergePatterns(classDiff, mergeMap);
extractRenamePatterns(classDiff, renameMap);
}
Map typeRenamePatternMap = typeRenamePatternMap(refactorings);
for(RenamePattern pattern : typeRenamePatternMap.keySet()) {
if(typeRenamePatternMap.get(pattern) > 1) {
UMLClass removedClass = looksLikeRemovedClass(UMLType.extractTypeObject(pattern.getBefore()));
UMLClass addedClass = looksLikeAddedClass(UMLType.extractTypeObject(pattern.getAfter()));
if(removedClass != null && addedClass != null) {
UMLClassRenameDiff renameDiff = new UMLClassRenameDiff(removedClass, addedClass, this);
renameDiff.process();
refactorings.addAll(renameDiff.getRefactorings());
extractMergePatterns(renameDiff, mergeMap);
extractRenamePatterns(renameDiff, renameMap);
classRenameDiffList.add(renameDiff);
Refactoring refactoring = null;
if(renameDiff.samePackage())
refactoring = new RenameClassRefactoring(renameDiff.getOriginalClass(), renameDiff.getRenamedClass());
else
refactoring = new MoveAndRenameClassRefactoring(renameDiff.getOriginalClass(), renameDiff.getRenamedClass());
refactorings.add(refactoring);
}
}
}
for(MergeVariableReplacement merge : mergeMap.keySet()) {
UMLClassBaseDiff diff = null;
for(String mergedVariable : merge.getMergedVariables()) {
Replacement replacement = new Replacement(mergedVariable, merge.getAfter(), ReplacementType.VARIABLE_NAME);
diff = getUMLClassDiffWithAttribute(replacement);
}
if(diff != null) {
Set mergedAttributes = new LinkedHashSet();
Set mergedVariables = new LinkedHashSet();
for(String mergedVariable : merge.getMergedVariables()) {
UMLAttribute a1 = diff.findAttributeInOriginalClass(mergedVariable);
if(a1 != null) {
mergedAttributes.add(a1);
mergedVariables.add(a1.getVariableDeclaration());
}
}
UMLAttribute a2 = diff.findAttributeInNextClass(merge.getAfter());
Set set = mergeMap.get(merge);
if(mergedVariables.size() > 1 && mergedVariables.size() == merge.getMergedVariables().size() && a2 != null) {
MergeAttributeRefactoring ref = new MergeAttributeRefactoring(mergedVariables, a2.getVariableDeclaration(), diff.getOriginalClassName(), diff.getNextClassName(), set);
if(!refactorings.contains(ref)) {
refactorings.add(ref);
Refactoring conflictingRefactoring = attributeRenamed(mergedVariables, a2.getVariableDeclaration(), refactorings);
if(conflictingRefactoring != null) {
refactorings.remove(conflictingRefactoring);
}
}
}
}
}
for(Replacement pattern : renameMap.keySet()) {
UMLClassBaseDiff diff = getUMLClassDiffWithAttribute(pattern);
Set set = renameMap.get(pattern);
for(CandidateAttributeRefactoring candidate : set) {
if(candidate.getOriginalVariableDeclaration() == null && candidate.getRenamedVariableDeclaration() == null) {
if(diff != null) {
UMLAttribute a1 = diff.findAttributeInOriginalClass(pattern.getBefore());
UMLAttribute a2 = diff.findAttributeInNextClass(pattern.getAfter());
if(!diff.getOriginalClass().containsAttributeWithName(pattern.getAfter()) &&
!diff.getNextClass().containsAttributeWithName(pattern.getBefore()) &&
!attributeMerged(a1, a2, refactorings)) {
UMLAttributeDiff attributeDiff = new UMLAttributeDiff(a1, a2, diff.getOperationBodyMapperList());
Set attributeDiffRefactorings = attributeDiff.getRefactorings(set);
if(!refactorings.containsAll(attributeDiffRefactorings)) {
refactorings.addAll(attributeDiffRefactorings);
break;//it's not necessary to repeat the same process for all candidates in the set
}
}
}
}
else if(candidate.getOriginalVariableDeclaration() != null) {
List diffs1 = getUMLClassDiffWithExistingAttributeAfter(pattern);
List diffs2 = getUMLClassDiffWithNewAttributeAfter(pattern);
if(!diffs1.isEmpty()) {
UMLClassBaseDiff diff1 = diffs1.get(0);
UMLClassBaseDiff originalClassDiff = null;
if(candidate.getOriginalAttribute() != null) {
originalClassDiff = getUMLClassDiff(candidate.getOriginalAttribute().getClassName());
}
else {
originalClassDiff = getUMLClassDiff(candidate.getOperationBefore().getClassName());
}
if(diffs1.size() > 1) {
for(UMLClassBaseDiff classDiff : diffs1) {
if(isSubclassOf(originalClassDiff.nextClass.getName(), classDiff.nextClass.getName())) {
diff1 = classDiff;
break;
}
}
}
UMLAttribute a2 = diff1.findAttributeInNextClass(pattern.getAfter());
if(a2 != null) {
if(candidate.getOriginalVariableDeclaration().isAttribute()) {
if(originalClassDiff != null && originalClassDiff.removedAttributes.contains(candidate.getOriginalAttribute())) {
ReplaceAttributeRefactoring ref = new ReplaceAttributeRefactoring(candidate.getOriginalAttribute(), a2, set);
if(!refactorings.contains(ref)) {
refactorings.add(ref);
break;//it's not necessary to repeat the same process for all candidates in the set
}
}
}
else {
RenameVariableRefactoring ref = new RenameVariableRefactoring(candidate.getOriginalVariableDeclaration(), a2.getVariableDeclaration(), candidate.getOperationBefore(), candidate.getOperationAfter(), candidate.getAttributeReferences());
if(!refactorings.contains(ref)) {
refactorings.add(ref);
break;//it's not necessary to repeat the same process for all candidates in the set
}
}
}
}
else if(!diffs2.isEmpty()) {
UMLClassBaseDiff diff2 = diffs2.get(0);
UMLClassBaseDiff originalClassDiff = null;
if(candidate.getOriginalAttribute() != null) {
originalClassDiff = getUMLClassDiff(candidate.getOriginalAttribute().getClassName());
}
else {
originalClassDiff = getUMLClassDiff(candidate.getOperationBefore().getClassName());
}
if(diffs2.size() > 1) {
for(UMLClassBaseDiff classDiff : diffs2) {
if(isSubclassOf(originalClassDiff.nextClass.getName(), classDiff.nextClass.getName())) {
diff2 = classDiff;
break;
}
}
}
UMLAttribute a2 = diff2.findAttributeInNextClass(pattern.getAfter());
if(a2 != null) {
if(candidate.getOriginalVariableDeclaration().isAttribute()) {
if(originalClassDiff != null && originalClassDiff.removedAttributes.contains(candidate.getOriginalAttribute())) {
MoveAndRenameAttributeRefactoring ref = new MoveAndRenameAttributeRefactoring(candidate.getOriginalAttribute(), a2, set);
if(!refactorings.contains(ref)) {
refactorings.add(ref);
break;//it's not necessary to repeat the same process for all candidates in the set
}
}
}
else {
RenameVariableRefactoring ref = new RenameVariableRefactoring(candidate.getOriginalVariableDeclaration(), a2.getVariableDeclaration(), candidate.getOperationBefore(), candidate.getOperationAfter(), candidate.getAttributeReferences());
if(!refactorings.contains(ref)) {
refactorings.add(ref);
break;//it's not necessary to repeat the same process for all candidates in the set
}
}
}
}
}
}
}
refactorings.addAll(identifyExtractSuperclassRefactorings());
refactorings.addAll(identifyExtractClassRefactorings(commonClassDiffList));
refactorings.addAll(identifyExtractClassRefactorings(classMoveDiffList));
refactorings.addAll(identifyExtractClassRefactorings(innerClassMoveDiffList));
refactorings.addAll(identifyExtractClassRefactorings(classRenameDiffList));
checkForOperationMovesBetweenCommonClasses();
checkForOperationMovesIncludingAddedClasses();
checkForOperationMovesIncludingRemovedClasses();
checkForExtractedAndMovedOperations(getOperationBodyMappersInCommonClasses(), getAddedAndExtractedOperationsInCommonClasses());
checkForExtractedAndMovedOperations(getOperationBodyMappersInMovedAndRenamedClasses(), getAddedOperationsInMovedAndRenamedClasses());
checkForMovedAndInlinedOperations(getOperationBodyMappersInCommonClasses(), getRemovedAndInlinedOperationsInCommonClasses());
refactorings.addAll(checkForAttributeMovesBetweenCommonClasses());
refactorings.addAll(checkForAttributeMovesIncludingAddedClasses());
refactorings.addAll(checkForAttributeMovesIncludingRemovedClasses());
refactorings.addAll(this.refactorings);
for(UMLClassDiff classDiff : commonClassDiffList) {
inferMethodSignatureRelatedRefactorings(classDiff, refactorings);
}
for(UMLClassMoveDiff classDiff : classMoveDiffList) {
inferMethodSignatureRelatedRefactorings(classDiff, refactorings);
}
for(UMLClassMoveDiff classDiff : innerClassMoveDiffList) {
inferMethodSignatureRelatedRefactorings(classDiff, refactorings);
}
for(UMLClassRenameDiff classDiff : classRenameDiffList) {
inferMethodSignatureRelatedRefactorings(classDiff, refactorings);
}
return filterOutDuplicateRefactorings(refactorings);
}
private Map typeRenamePatternMap(Set refactorings) {
Map typeRenamePatternMap = new LinkedHashMap();
for(Refactoring ref : refactorings) {
if(ref instanceof ChangeVariableTypeRefactoring) {
ChangeVariableTypeRefactoring refactoring = (ChangeVariableTypeRefactoring)ref;
RenamePattern pattern = new RenamePattern(refactoring.getOriginalVariable().getType().toString(), refactoring.getChangedTypeVariable().getType().toString());
if(typeRenamePatternMap.containsKey(pattern)) {
typeRenamePatternMap.put(pattern, typeRenamePatternMap.get(pattern) + 1);
}
else {
typeRenamePatternMap.put(pattern, 1);
}
}
else if(ref instanceof ChangeAttributeTypeRefactoring) {
ChangeAttributeTypeRefactoring refactoring = (ChangeAttributeTypeRefactoring)ref;
RenamePattern pattern = new RenamePattern(refactoring.getOriginalAttribute().getType().toString(), refactoring.getChangedTypeAttribute().getType().toString());
if(typeRenamePatternMap.containsKey(pattern)) {
typeRenamePatternMap.put(pattern, typeRenamePatternMap.get(pattern) + 1);
}
else {
typeRenamePatternMap.put(pattern, 1);
}
}
else if(ref instanceof ChangeReturnTypeRefactoring) {
ChangeReturnTypeRefactoring refactoring = (ChangeReturnTypeRefactoring)ref;
RenamePattern pattern = new RenamePattern(refactoring.getOriginalType().toString(), refactoring.getChangedType().toString());
if(typeRenamePatternMap.containsKey(pattern)) {
typeRenamePatternMap.put(pattern, typeRenamePatternMap.get(pattern) + 1);
}
else {
typeRenamePatternMap.put(pattern, 1);
}
}
}
return typeRenamePatternMap;
}
private void inferMethodSignatureRelatedRefactorings(UMLClassBaseDiff classDiff, Set refactorings) {
if(classDiff.getOriginalClass().isInterface() && classDiff.getNextClass().isInterface()) {
for(UMLOperation removedOperation : classDiff.getRemovedOperations()) {
for(UMLOperation addedOperation : classDiff.getAddedOperations()) {
List mappers = findMappersWithMatchingSignatures(removedOperation, addedOperation);
if(!mappers.isEmpty()) {
UMLOperationDiff operationSignatureDiff = new UMLOperationDiff(removedOperation, addedOperation);
if(operationSignatureDiff.isOperationRenamed()) {
RenameOperationRefactoring refactoring = new RenameOperationRefactoring(removedOperation, addedOperation);
refactorings.add(refactoring);
}
Set signatureRefactorings = operationSignatureDiff.getRefactorings();
refactorings.addAll(signatureRefactorings);
if(signatureRefactorings.isEmpty()) {
inferRefactoringsFromMatchingMappers(mappers, operationSignatureDiff, refactorings);
}
}
}
}
}
else if(classDiff.getOriginalClass().isAbstract() && classDiff.getNextClass().isAbstract()) {
for(UMLOperation removedOperation : classDiff.getRemovedOperations()) {
for(UMLOperation addedOperation : classDiff.getAddedOperations()) {
if(removedOperation.isAbstract() && addedOperation.isAbstract()) {
List mappers = findMappersWithMatchingSignatures(removedOperation, addedOperation);
if(!mappers.isEmpty()) {
UMLOperationDiff operationSignatureDiff = new UMLOperationDiff(removedOperation, addedOperation);
if(operationSignatureDiff.isOperationRenamed()) {
RenameOperationRefactoring refactoring = new RenameOperationRefactoring(removedOperation, addedOperation);
refactorings.add(refactoring);
}
Set signatureRefactorings = operationSignatureDiff.getRefactorings();
refactorings.addAll(signatureRefactorings);
if(signatureRefactorings.isEmpty()) {
inferRefactoringsFromMatchingMappers(mappers, operationSignatureDiff, refactorings);
}
}
}
}
}
}
}
private void inferRefactoringsFromMatchingMappers(List mappers, UMLOperationDiff operationSignatureDiff, Set refactorings) {
for(UMLOperationBodyMapper mapper : mappers) {
for(Refactoring refactoring : mapper.getRefactoringsAfterPostProcessing()) {
if(refactoring instanceof RenameVariableRefactoring) {
RenameVariableRefactoring rename = (RenameVariableRefactoring)refactoring;
UMLParameter matchingRemovedParameter = null;
for(UMLParameter parameter : operationSignatureDiff.getRemovedParameters()) {
if(parameter.getName().equals(rename.getOriginalVariable().getVariableName()) &&
parameter.getType().equals(rename.getOriginalVariable().getType())) {
matchingRemovedParameter = parameter;
break;
}
}
UMLParameter matchingAddedParameter = null;
for(UMLParameter parameter : operationSignatureDiff.getAddedParameters()) {
if(parameter.getName().equals(rename.getRenamedVariable().getVariableName()) &&
parameter.getType().equals(rename.getRenamedVariable().getType())) {
matchingAddedParameter = parameter;
break;
}
}
if(matchingRemovedParameter != null && matchingAddedParameter != null) {
RenameVariableRefactoring newRename = new RenameVariableRefactoring(matchingRemovedParameter.getVariableDeclaration(), matchingAddedParameter.getVariableDeclaration(),
operationSignatureDiff.getRemovedOperation(), operationSignatureDiff.getAddedOperation(), new LinkedHashSet());
refactorings.add(newRename);
}
}
else if(refactoring instanceof ChangeVariableTypeRefactoring) {
ChangeVariableTypeRefactoring changeType = (ChangeVariableTypeRefactoring)refactoring;
UMLParameter matchingRemovedParameter = null;
for(UMLParameter parameter : operationSignatureDiff.getRemovedParameters()) {
if(parameter.getName().equals(changeType.getOriginalVariable().getVariableName()) &&
parameter.getType().equals(changeType.getOriginalVariable().getType())) {
matchingRemovedParameter = parameter;
break;
}
}
UMLParameter matchingAddedParameter = null;
for(UMLParameter parameter : operationSignatureDiff.getAddedParameters()) {
if(parameter.getName().equals(changeType.getChangedTypeVariable().getVariableName()) &&
parameter.getType().equals(changeType.getChangedTypeVariable().getType())) {
matchingAddedParameter = parameter;
break;
}
}
if(matchingRemovedParameter != null && matchingAddedParameter != null) {
ChangeVariableTypeRefactoring newChangeType = new ChangeVariableTypeRefactoring(matchingRemovedParameter.getVariableDeclaration(), matchingAddedParameter.getVariableDeclaration(),
operationSignatureDiff.getRemovedOperation(), operationSignatureDiff.getAddedOperation(), new LinkedHashSet());
refactorings.add(newChangeType);
}
}
}
}
}
private List findMappersWithMatchingSignatures(UMLOperation operation1, UMLOperation operation2) {
List mappers = new ArrayList();
for(UMLClassDiff classDiff : commonClassDiffList) {
UMLOperationBodyMapper mapper = classDiff.findMapperWithMatchingSignatures(operation1, operation2);
if(mapper != null) {
mappers.add(mapper);
}
}
for(UMLClassMoveDiff classDiff : classMoveDiffList) {
UMLOperationBodyMapper mapper = classDiff.findMapperWithMatchingSignatures(operation1, operation2);
if(mapper != null) {
mappers.add(mapper);
}
}
for(UMLClassMoveDiff classDiff : innerClassMoveDiffList) {
UMLOperationBodyMapper mapper = classDiff.findMapperWithMatchingSignatures(operation1, operation2);
if(mapper != null) {
mappers.add(mapper);
}
}
for(UMLClassRenameDiff classDiff : classRenameDiffList) {
UMLOperationBodyMapper mapper = classDiff.findMapperWithMatchingSignatures(operation1, operation2);
if(mapper != null) {
mappers.add(mapper);
}
}
return mappers;
}
public List findMappersWithMatchingSignature2(UMLOperation operation2) {
List mappers = new ArrayList();
for(UMLClassDiff classDiff : commonClassDiffList) {
UMLOperationBodyMapper mapper = classDiff.findMapperWithMatchingSignature2(operation2);
if(mapper != null) {
mappers.add(mapper);
}
}
for(UMLClassMoveDiff classDiff : classMoveDiffList) {
UMLOperationBodyMapper mapper = classDiff.findMapperWithMatchingSignature2(operation2);
if(mapper != null) {
mappers.add(mapper);
}
}
for(UMLClassMoveDiff classDiff : innerClassMoveDiffList) {
UMLOperationBodyMapper mapper = classDiff.findMapperWithMatchingSignature2(operation2);
if(mapper != null) {
mappers.add(mapper);
}
}
for(UMLClassRenameDiff classDiff : classRenameDiffList) {
UMLOperationBodyMapper mapper = classDiff.findMapperWithMatchingSignature2(operation2);
if(mapper != null) {
mappers.add(mapper);
}
}
return mappers;
}
private void extractMergePatterns(UMLClassBaseDiff classDiff, Map> mergeMap) {
for(CandidateMergeVariableRefactoring candidate : classDiff.getCandidateAttributeMerges()) {
Set before = new LinkedHashSet();
for(String mergedVariable : candidate.getMergedVariables()) {
before.add(PrefixSuffixUtils.normalize(mergedVariable));
}
String after = PrefixSuffixUtils.normalize(candidate.getNewVariable());
MergeVariableReplacement merge = new MergeVariableReplacement(before, after);
if(mergeMap.containsKey(merge)) {
mergeMap.get(merge).add(candidate);
}
else {
Set set = new LinkedHashSet();
set.add(candidate);
mergeMap.put(merge, set);
}
}
}
private void extractRenamePatterns(UMLClassBaseDiff classDiff, Map> map) {
for(CandidateAttributeRefactoring candidate : classDiff.getCandidateAttributeRenames()) {
String before = PrefixSuffixUtils.normalize(candidate.getOriginalVariableName());
String after = PrefixSuffixUtils.normalize(candidate.getRenamedVariableName());
if(before.contains(".") && after.contains(".")) {
String prefix1 = before.substring(0, before.lastIndexOf(".") + 1);
String prefix2 = after.substring(0, after.lastIndexOf(".") + 1);
if(prefix1.equals(prefix2)) {
before = before.substring(prefix1.length(), before.length());
after = after.substring(prefix2.length(), after.length());
}
}
Replacement renamePattern = new Replacement(before, after, ReplacementType.VARIABLE_NAME);
if(map.containsKey(renamePattern)) {
map.get(renamePattern).add(candidate);
}
else {
Set set = new LinkedHashSet();
set.add(candidate);
map.put(renamePattern, set);
}
}
}
private void checkForMovedAndInlinedOperations(List mappers, List removedOperations) throws RefactoringMinerTimedOutException {
for(Iterator removedOperationIterator = removedOperations.iterator(); removedOperationIterator.hasNext();) {
UMLOperation removedOperation = removedOperationIterator.next();
for(UMLOperationBodyMapper mapper : mappers) {
if(!mapper.getNonMappedLeavesT2().isEmpty() || !mapper.getNonMappedInnerNodesT2().isEmpty() || !mapper.getReplacementsInvolvingMethodInvocation().isEmpty()) {
List operationInvocations = mapper.getOperation1().getAllOperationInvocations();
List removedOperationInvocations = new ArrayList();
for(OperationInvocation invocation : operationInvocations) {
if(invocation.matchesOperation(removedOperation, mapper.getOperation1().variableTypeMap(), this)) {
removedOperationInvocations.add(invocation);
}
}
if(removedOperationInvocations.size() > 0 && !invocationMatchesWithAddedOperation(removedOperationInvocations.get(0), mapper.getOperation1().variableTypeMap(), mapper.getOperation2().getAllOperationInvocations())) {
OperationInvocation removedOperationInvocation = removedOperationInvocations.get(0);
List arguments = removedOperationInvocation.getArguments();
List parameters = removedOperation.getParameterNameList();
Map parameterToArgumentMap = new LinkedHashMap();
//special handling for methods with varargs parameter for which no argument is passed in the matching invocation
int size = Math.min(arguments.size(), parameters.size());
for(int i=0; i mappingList = new ArrayList(operationBodyMapper.getMappings());
if((operationBodyMapper.getOperation1().isGetter() || operationBodyMapper.getOperation1().isDelegate() != null) && mappingList.size() == 1) {
List parentMappingList = new ArrayList(parentMapper.getMappings());
for(AbstractCodeMapping mapping : parentMappingList) {
if(mapping.getFragment2().equals(mappingList.get(0).getFragment2())) {
return false;
}
if(mapping instanceof CompositeStatementObjectMapping) {
CompositeStatementObjectMapping compositeMapping = (CompositeStatementObjectMapping)mapping;
CompositeStatementObject fragment2 = (CompositeStatementObject)compositeMapping.getFragment2();
for(AbstractExpression expression : fragment2.getExpressions()) {
if(expression.equals(mappingList.get(0).getFragment2())) {
return false;
}
}
}
}
}
int delegateStatements = 0;
for(StatementObject statement : operationBodyMapper.getNonMappedLeavesT1()) {
OperationInvocation invocation = statement.invocationCoveringEntireFragment();
if(invocation != null && invocation.matchesOperation(operationBodyMapper.getOperation1())) {
delegateStatements++;
}
}
int mappings = operationBodyMapper.mappingsWithoutBlocks();
int nonMappedElementsT1 = operationBodyMapper.nonMappedElementsT1()-delegateStatements;
List exactMatchList = operationBodyMapper.getExactMatches();
int exactMatches = exactMatchList.size();
return mappings > 0 && (mappings > nonMappedElementsT1 ||
(exactMatches == 1 && !exactMatchList.get(0).getFragment1().throwsNewException() && nonMappedElementsT1-exactMatches < 10) ||
(exactMatches > 1 && nonMappedElementsT1-exactMatches < 20));
}
private boolean invocationMatchesWithAddedOperation(OperationInvocation removedOperationInvocation, Map variableTypeMap, List operationInvocationsInNewMethod) {
if(operationInvocationsInNewMethod.contains(removedOperationInvocation)) {
for(UMLOperation addedOperation : getAddedOperationsInCommonClasses()) {
if(removedOperationInvocation.matchesOperation(addedOperation, variableTypeMap, this)) {
return true;
}
}
}
return false;
}
private void checkForExtractedAndMovedOperations(List mappers, List addedOperations) throws RefactoringMinerTimedOutException {
for(Iterator addedOperationIterator = addedOperations.iterator(); addedOperationIterator.hasNext();) {
UMLOperation addedOperation = addedOperationIterator.next();
for(UMLOperationBodyMapper mapper : mappers) {
if((mapper.nonMappedElementsT1() > 0 || !mapper.getReplacementsInvolvingMethodInvocation().isEmpty()) && !mapper.containsExtractOperationRefactoring(addedOperation)) {
List operationInvocations = ExtractOperationDetection.getInvocationsInSourceOperationAfterExtraction(mapper);
List addedOperationInvocations = new ArrayList