gr.uom.java.xmi.decomposition.UMLOperationBodyMapper 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.decomposition;
import gr.uom.java.xmi.UMLAnonymousClass;
import gr.uom.java.xmi.UMLAttribute;
import gr.uom.java.xmi.UMLOperation;
import gr.uom.java.xmi.UMLParameter;
import gr.uom.java.xmi.UMLType;
import gr.uom.java.xmi.LocationInfo.CodeElementType;
import gr.uom.java.xmi.decomposition.replacement.AddVariableReplacement;
import gr.uom.java.xmi.decomposition.replacement.ClassInstanceCreationWithMethodInvocationReplacement;
import gr.uom.java.xmi.decomposition.replacement.CompositeReplacement;
import gr.uom.java.xmi.decomposition.replacement.IntersectionReplacement;
import gr.uom.java.xmi.decomposition.replacement.MergeVariableReplacement;
import gr.uom.java.xmi.decomposition.replacement.MethodInvocationReplacement;
import gr.uom.java.xmi.decomposition.replacement.MethodInvocationWithClassInstanceCreationReplacement;
import gr.uom.java.xmi.decomposition.replacement.ObjectCreationReplacement;
import gr.uom.java.xmi.decomposition.replacement.Replacement;
import gr.uom.java.xmi.decomposition.replacement.SplitVariableReplacement;
import gr.uom.java.xmi.decomposition.replacement.Replacement.ReplacementType;
import gr.uom.java.xmi.decomposition.replacement.VariableReplacementWithMethodInvocation;
import gr.uom.java.xmi.decomposition.replacement.VariableReplacementWithMethodInvocation.Direction;
import gr.uom.java.xmi.diff.CandidateAttributeRefactoring;
import gr.uom.java.xmi.diff.CandidateMergeVariableRefactoring;
import gr.uom.java.xmi.diff.CandidateSplitVariableRefactoring;
import gr.uom.java.xmi.diff.ExtractVariableRefactoring;
import gr.uom.java.xmi.diff.StringDistance;
import gr.uom.java.xmi.diff.UMLClassBaseDiff;
import gr.uom.java.xmi.diff.UMLModelDiff;
import gr.uom.java.xmi.diff.UMLOperationDiff;
import gr.uom.java.xmi.diff.UMLParameterDiff;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
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 java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.refactoringminer.api.Refactoring;
import org.refactoringminer.api.RefactoringMinerTimedOutException;
import org.refactoringminer.util.PrefixSuffixUtils;
public class UMLOperationBodyMapper implements Comparable {
private UMLOperation operation1;
private UMLOperation operation2;
private Set mappings;
private List nonMappedLeavesT1;
private List nonMappedLeavesT2;
private List nonMappedInnerNodesT1;
private List nonMappedInnerNodesT2;
private Set refactorings = new LinkedHashSet();
private Set candidateAttributeRenames = new LinkedHashSet();
private Set candidateAttributeMerges = new LinkedHashSet();
private Set candidateAttributeSplits = new LinkedHashSet();
private List childMappers = new ArrayList();
private UMLOperationBodyMapper parentMapper;
private static final Pattern SPLIT_CONDITIONAL_PATTERN = Pattern.compile("(\\|\\|)|(&&)|(\\?)|(:)");
public static final String SPLIT_CONCAT_STRING_PATTERN = "(\\s)*(\\+)(\\s)*";
private static final Pattern DOUBLE_QUOTES = Pattern.compile("\"([^\"]*)\"|(\\S+)");
private UMLClassBaseDiff classDiff;
private UMLModelDiff modelDiff;
private UMLOperation callSiteOperation;
private Map codeFragmentOperationMap1 = new LinkedHashMap();
private Map codeFragmentOperationMap2 = new LinkedHashMap();
public UMLOperationBodyMapper(UMLOperation operation1, UMLOperation operation2, UMLClassBaseDiff classDiff) throws RefactoringMinerTimedOutException {
this.classDiff = classDiff;
if(classDiff != null)
this.modelDiff = classDiff.getModelDiff();
this.operation1 = operation1;
this.operation2 = operation2;
this.mappings = new LinkedHashSet();
this.nonMappedLeavesT1 = new ArrayList();
this.nonMappedLeavesT2 = new ArrayList();
this.nonMappedInnerNodesT1 = new ArrayList();
this.nonMappedInnerNodesT2 = new ArrayList();
OperationBody body1 = operation1.getBody();
OperationBody body2 = operation2.getBody();
if(body1 != null && body2 != null) {
CompositeStatementObject composite1 = body1.getCompositeStatement();
CompositeStatementObject composite2 = body2.getCompositeStatement();
List leaves1 = composite1.getLeaves();
List leaves2 = composite2.getLeaves();
UMLOperationDiff operationDiff = new UMLOperationDiff(operation1, operation2);
Map parameterToArgumentMap1 = new LinkedHashMap();
Map parameterToArgumentMap2 = new LinkedHashMap();
List addedParameters = operationDiff.getAddedParameters();
if(addedParameters.size() == 1) {
UMLParameter addedParameter = addedParameters.get(0);
if(UMLModelDiff.looksLikeSameType(addedParameter.getType().getClassType(), operation1.getClassName())) {
parameterToArgumentMap1.put("this.", "");
//replace "parameterName." with ""
parameterToArgumentMap2.put(addedParameter.getName() + ".", "");
}
}
List removedParameters = operationDiff.getRemovedParameters();
if(removedParameters.size() == 1) {
UMLParameter removedParameter = removedParameters.get(0);
if(UMLModelDiff.looksLikeSameType(removedParameter.getType().getClassType(), operation2.getClassName())) {
parameterToArgumentMap1.put(removedParameter.getName() + ".", "");
parameterToArgumentMap2.put("this.", "");
}
}
resetNodes(leaves1);
//replace parameters with arguments in leaves1
if(!parameterToArgumentMap1.isEmpty()) {
for(StatementObject leave1 : leaves1) {
leave1.replaceParametersWithArguments(parameterToArgumentMap1);
}
}
resetNodes(leaves2);
//replace parameters with arguments in leaves2
if(!parameterToArgumentMap2.isEmpty()) {
for(StatementObject leave2 : leaves2) {
leave2.replaceParametersWithArguments(parameterToArgumentMap2);
}
}
processLeaves(leaves1, leaves2, new LinkedHashMap());
List innerNodes1 = composite1.getInnerNodes();
innerNodes1.remove(composite1);
List innerNodes2 = composite2.getInnerNodes();
innerNodes2.remove(composite2);
resetNodes(innerNodes1);
//replace parameters with arguments in innerNodes1
if(!parameterToArgumentMap1.isEmpty()) {
for(CompositeStatementObject innerNode1 : innerNodes1) {
innerNode1.replaceParametersWithArguments(parameterToArgumentMap1);
}
}
resetNodes(innerNodes2);
//replace parameters with arguments in innerNodes2
if(!parameterToArgumentMap2.isEmpty()) {
for(CompositeStatementObject innerNode2 : innerNodes2) {
innerNode2.replaceParametersWithArguments(parameterToArgumentMap2);
}
}
processInnerNodes(innerNodes1, innerNodes2, new LinkedHashMap());
nonMappedLeavesT1.addAll(leaves1);
nonMappedLeavesT2.addAll(leaves2);
nonMappedInnerNodesT1.addAll(innerNodes1);
nonMappedInnerNodesT2.addAll(innerNodes2);
for(StatementObject statement : getNonMappedLeavesT2()) {
temporaryVariableAssignment(statement, nonMappedLeavesT2);
}
for(StatementObject statement : getNonMappedLeavesT1()) {
inlinedVariableAssignment(statement, nonMappedLeavesT2);
}
}
}
private UMLOperationBodyMapper(LambdaExpressionObject lambda1, LambdaExpressionObject lambda2, UMLOperationBodyMapper parentMapper) throws RefactoringMinerTimedOutException {
this.classDiff = parentMapper.classDiff;
if(classDiff != null)
this.modelDiff = classDiff.getModelDiff();
this.operation1 = parentMapper.operation1;
this.operation2 = parentMapper.operation2;
this.mappings = new LinkedHashSet();
this.nonMappedLeavesT1 = new ArrayList();
this.nonMappedLeavesT2 = new ArrayList();
this.nonMappedInnerNodesT1 = new ArrayList();
this.nonMappedInnerNodesT2 = new ArrayList();
if(lambda1.getExpression() != null && lambda2.getExpression() != null) {
List leaves1 = new ArrayList();
leaves1.add(lambda1.getExpression());
List leaves2 = new ArrayList();
leaves2.add(lambda2.getExpression());
processLeaves(leaves1, leaves2, new LinkedHashMap());
}
else if(lambda1.getBody() != null && lambda2.getBody() != null) {
CompositeStatementObject composite1 = lambda1.getBody().getCompositeStatement();
CompositeStatementObject composite2 = lambda2.getBody().getCompositeStatement();
List leaves1 = composite1.getLeaves();
List leaves2 = composite2.getLeaves();
processLeaves(leaves1, leaves2, new LinkedHashMap());
List innerNodes1 = composite1.getInnerNodes();
List innerNodes2 = composite2.getInnerNodes();
processInnerNodes(innerNodes1, innerNodes2, new LinkedHashMap());
nonMappedLeavesT1.addAll(leaves1);
nonMappedLeavesT2.addAll(leaves2);
nonMappedInnerNodesT1.addAll(innerNodes1);
nonMappedInnerNodesT2.addAll(innerNodes2);
for(StatementObject statement : getNonMappedLeavesT2()) {
temporaryVariableAssignment(statement, nonMappedLeavesT2);
}
for(StatementObject statement : getNonMappedLeavesT1()) {
inlinedVariableAssignment(statement, nonMappedLeavesT2);
}
}
}
public void addChildMapper(UMLOperationBodyMapper mapper) {
this.childMappers.add(mapper);
//TODO add logic to remove the mappings from "this" mapper,
//which are less similar than the mappings of the mapper passed as parameter
}
public List getChildMappers() {
return childMappers;
}
public UMLOperationBodyMapper getParentMapper() {
return parentMapper;
}
public UMLOperation getCallSiteOperation() {
return callSiteOperation;
}
private void resetNodes(List extends AbstractCodeFragment> nodes) {
for(AbstractCodeFragment node : nodes) {
node.resetArgumentization();
}
}
private boolean returnWithVariableReplacement(AbstractCodeMapping mapping) {
if(mapping.getReplacements().size() == 1) {
Replacement r = mapping.getReplacements().iterator().next();
if(r.getType().equals(ReplacementType.VARIABLE_NAME)) {
String fragment1 = mapping.getFragment1().getString();
String fragment2 = mapping.getFragment2().getString();
if(fragment1.equals("return " + r.getBefore() + ";\n") && fragment2.equals("return " + r.getAfter() + ";\n")) {
return true;
}
}
}
return false;
}
private boolean nullLiteralReplacements(AbstractCodeMapping mapping) {
int numberOfReplacements = mapping.getReplacements().size();
int nullLiteralReplacements = 0;
int methodInvocationReplacementsToIgnore = 0;
int variableNameReplacementsToIgnore = 0;
for(Replacement replacement : mapping.getReplacements()) {
if(replacement.getType().equals(ReplacementType.NULL_LITERAL_REPLACED_WITH_CONDITIONAL_EXPRESSION) ||
replacement.getType().equals(ReplacementType.VARIABLE_REPLACED_WITH_NULL_LITERAL) ||
(replacement.getType().equals(ReplacementType.ARGUMENT_REPLACED_WITH_VARIABLE) && (replacement.getBefore().equals("null") || replacement.getAfter().equals("null")))) {
nullLiteralReplacements++;
}
else if(replacement instanceof MethodInvocationReplacement) {
MethodInvocationReplacement invocationReplacement = (MethodInvocationReplacement)replacement;
OperationInvocation invokedOperationBefore = invocationReplacement.getInvokedOperationBefore();
OperationInvocation invokedOperationAfter = invocationReplacement.getInvokedOperationAfter();
if(invokedOperationBefore.getName().equals(invokedOperationAfter.getName()) &&
invokedOperationBefore.getArguments().size() == invokedOperationAfter.getArguments().size()) {
methodInvocationReplacementsToIgnore++;
}
}
else if(replacement.getType().equals(ReplacementType.VARIABLE_NAME)) {
variableNameReplacementsToIgnore++;
}
}
return nullLiteralReplacements > 0 && numberOfReplacements == nullLiteralReplacements + methodInvocationReplacementsToIgnore + variableNameReplacementsToIgnore;
}
public UMLOperationBodyMapper(UMLOperationBodyMapper operationBodyMapper, UMLOperation addedOperation,
Map parameterToArgumentMap1, Map parameterToArgumentMap2, UMLClassBaseDiff classDiff) throws RefactoringMinerTimedOutException {
this.parentMapper = operationBodyMapper;
this.operation1 = operationBodyMapper.operation1;
this.callSiteOperation = operationBodyMapper.operation2;
this.operation2 = addedOperation;
this.classDiff = classDiff;
this.mappings = new LinkedHashSet();
this.nonMappedLeavesT1 = new ArrayList();
this.nonMappedLeavesT2 = new ArrayList();
this.nonMappedInnerNodesT1 = new ArrayList();
this.nonMappedInnerNodesT2 = new ArrayList();
OperationBody addedOperationBody = addedOperation.getBody();
if(addedOperationBody != null) {
CompositeStatementObject composite2 = addedOperationBody.getCompositeStatement();
List leaves1 = operationBodyMapper.getNonMappedLeavesT1();
List innerNodes1 = operationBodyMapper.getNonMappedInnerNodesT1();
//adding leaves that were mapped with replacements
Set addedLeaves1 = new LinkedHashSet();
Set addedInnerNodes1 = new LinkedHashSet();
for(StatementObject nonMappedLeaf1 : new ArrayList<>(operationBodyMapper.getNonMappedLeavesT1())) {
expandAnonymousAndLambdas(nonMappedLeaf1, leaves1, innerNodes1, addedLeaves1, addedInnerNodes1, operationBodyMapper);
}
for(AbstractCodeMapping mapping : operationBodyMapper.getMappings()) {
if(!returnWithVariableReplacement(mapping) && !nullLiteralReplacements(mapping) && (!mapping.getReplacements().isEmpty() || !mapping.getFragment1().equalFragment(mapping.getFragment2()))) {
AbstractCodeFragment fragment = mapping.getFragment1();
expandAnonymousAndLambdas(fragment, leaves1, innerNodes1, addedLeaves1, addedInnerNodes1, operationBodyMapper);
}
}
List leaves2 = composite2.getLeaves();
List innerNodes2 = composite2.getInnerNodes();
Set addedLeaves2 = new LinkedHashSet();
Set addedInnerNodes2 = new LinkedHashSet();
for(StatementObject statement : leaves2) {
if(!statement.getAnonymousClassDeclarations().isEmpty()) {
List anonymousList = operation2.getAnonymousClassList();
for(UMLAnonymousClass anonymous : anonymousList) {
if(anonymous.isDirectlyNested() && statement.getLocationInfo().subsumes(anonymous.getLocationInfo())) {
for(UMLOperation anonymousOperation : anonymous.getOperations()) {
List anonymousClassLeaves = anonymousOperation.getBody().getCompositeStatement().getLeaves();
for(StatementObject anonymousLeaf : anonymousClassLeaves) {
if(!leaves2.contains(anonymousLeaf)) {
addedLeaves2.add(anonymousLeaf);
codeFragmentOperationMap2.put(anonymousLeaf, anonymousOperation);
}
}
List anonymousClassInnerNodes = anonymousOperation.getBody().getCompositeStatement().getInnerNodes();
for(CompositeStatementObject anonymousInnerNode : anonymousClassInnerNodes) {
if(!innerNodes2.contains(anonymousInnerNode)) {
addedInnerNodes2.add(anonymousInnerNode);
codeFragmentOperationMap2.put(anonymousInnerNode, anonymousOperation);
}
}
}
}
}
}
if(!statement.getLambdas().isEmpty()) {
for(LambdaExpressionObject lambda : statement.getLambdas()) {
if(lambda.getBody() != null) {
List lambdaLeaves = lambda.getBody().getCompositeStatement().getLeaves();
for(StatementObject lambdaLeaf : lambdaLeaves) {
if(!leaves2.contains(lambdaLeaf)) {
addedLeaves2.add(lambdaLeaf);
codeFragmentOperationMap2.put(lambdaLeaf, operation2);
}
}
List lambdaInnerNodes = lambda.getBody().getCompositeStatement().getInnerNodes();
for(CompositeStatementObject lambdaInnerNode : lambdaInnerNodes) {
if(!innerNodes2.contains(lambdaInnerNode)) {
addedInnerNodes2.add(lambdaInnerNode);
codeFragmentOperationMap2.put(lambdaInnerNode, operation2);
}
}
}
}
}
}
leaves2.addAll(addedLeaves2);
resetNodes(leaves1);
//replace parameters with arguments in leaves1
if(!parameterToArgumentMap1.isEmpty()) {
for(StatementObject leave1 : leaves1) {
leave1.replaceParametersWithArguments(parameterToArgumentMap1);
}
}
resetNodes(leaves2);
//replace parameters with arguments in leaves2
if(!parameterToArgumentMap2.isEmpty()) {
for(StatementObject leave2 : leaves2) {
leave2.replaceParametersWithArguments(parameterToArgumentMap2);
}
}
//compare leaves from T1 with leaves from T2
processLeaves(leaves1, leaves2, parameterToArgumentMap2);
//adding innerNodes that were mapped with replacements
for(AbstractCodeMapping mapping : operationBodyMapper.getMappings()) {
if(!mapping.getReplacements().isEmpty() || !mapping.getFragment1().equalFragment(mapping.getFragment2())) {
AbstractCodeFragment fragment = mapping.getFragment1();
if(fragment instanceof CompositeStatementObject) {
CompositeStatementObject statement = (CompositeStatementObject)fragment;
if(!innerNodes1.contains(statement)) {
innerNodes1.add(statement);
addedInnerNodes1.add(statement);
}
}
}
}
innerNodes2.remove(composite2);
innerNodes2.addAll(addedInnerNodes2);
resetNodes(innerNodes1);
//replace parameters with arguments in innerNodes1
if(!parameterToArgumentMap1.isEmpty()) {
for(CompositeStatementObject innerNode1 : innerNodes1) {
innerNode1.replaceParametersWithArguments(parameterToArgumentMap1);
}
}
resetNodes(innerNodes2);
//replace parameters with arguments in innerNode2
if(!parameterToArgumentMap2.isEmpty()) {
for(CompositeStatementObject innerNode2 : innerNodes2) {
innerNode2.replaceParametersWithArguments(parameterToArgumentMap2);
}
}
//compare inner nodes from T1 with inner nodes from T2
processInnerNodes(innerNodes1, innerNodes2, parameterToArgumentMap2);
//match expressions in inner nodes from T1 with leaves from T2
List expressionsT1 = new ArrayList();
for(CompositeStatementObject composite : operationBodyMapper.getNonMappedInnerNodesT1()) {
for(AbstractExpression expression : composite.getExpressions()) {
expression.replaceParametersWithArguments(parameterToArgumentMap1);
expressionsT1.add(expression);
}
}
int numberOfMappings = mappings.size();
processLeaves(expressionsT1, leaves2, parameterToArgumentMap2);
List mappings = new ArrayList<>(this.mappings);
for(int i = numberOfMappings; i < mappings.size(); i++) {
mappings.get(i).temporaryVariableAssignment(refactorings);
}
// TODO remove non-mapped inner nodes from T1 corresponding to mapped expressions
//remove the leaves that were mapped with replacement, if they are not mapped again for a second time
leaves1.removeAll(addedLeaves1);
leaves2.removeAll(addedLeaves2);
//remove the innerNodes that were mapped with replacement, if they are not mapped again for a second time
innerNodes1.removeAll(addedInnerNodes1);
innerNodes2.removeAll(addedInnerNodes2);
nonMappedLeavesT1.addAll(leaves1);
nonMappedLeavesT2.addAll(leaves2);
nonMappedInnerNodesT1.addAll(innerNodes1);
nonMappedInnerNodesT2.addAll(innerNodes2);
for(StatementObject statement : getNonMappedLeavesT2()) {
temporaryVariableAssignment(statement, nonMappedLeavesT2);
}
for(StatementObject statement : getNonMappedLeavesT1()) {
inlinedVariableAssignment(statement, nonMappedLeavesT2);
}
}
}
private void expandAnonymousAndLambdas(AbstractCodeFragment fragment, List leaves1,
List innerNodes1, Set addedLeaves1,
Set addedInnerNodes1, UMLOperationBodyMapper operationBodyMapper) {
if(fragment instanceof StatementObject) {
StatementObject statement = (StatementObject)fragment;
if(!leaves1.contains(statement)) {
leaves1.add(statement);
addedLeaves1.add(statement);
}
if(!statement.getAnonymousClassDeclarations().isEmpty()) {
List anonymousList = operationBodyMapper.getOperation1().getAnonymousClassList();
for(UMLAnonymousClass anonymous : anonymousList) {
if(statement.getLocationInfo().subsumes(anonymous.getLocationInfo())) {
for(UMLOperation anonymousOperation : anonymous.getOperations()) {
List anonymousClassLeaves = anonymousOperation.getBody().getCompositeStatement().getLeaves();
for(StatementObject anonymousLeaf : anonymousClassLeaves) {
if(!leaves1.contains(anonymousLeaf)) {
leaves1.add(anonymousLeaf);
addedLeaves1.add(anonymousLeaf);
codeFragmentOperationMap1.put(anonymousLeaf, anonymousOperation);
}
}
List anonymousClassInnerNodes = anonymousOperation.getBody().getCompositeStatement().getInnerNodes();
for(CompositeStatementObject anonymousInnerNode : anonymousClassInnerNodes) {
if(!innerNodes1.contains(anonymousInnerNode)) {
innerNodes1.add(anonymousInnerNode);
addedInnerNodes1.add(anonymousInnerNode);
codeFragmentOperationMap1.put(anonymousInnerNode, anonymousOperation);
}
}
}
}
}
}
if(!statement.getLambdas().isEmpty()) {
for(LambdaExpressionObject lambda : statement.getLambdas()) {
if(lambda.getBody() != null) {
List lambdaLeaves = lambda.getBody().getCompositeStatement().getLeaves();
for(StatementObject lambdaLeaf : lambdaLeaves) {
if(!leaves1.contains(lambdaLeaf)) {
leaves1.add(lambdaLeaf);
addedLeaves1.add(lambdaLeaf);
codeFragmentOperationMap1.put(lambdaLeaf, operation1);
}
}
List lambdaInnerNodes = lambda.getBody().getCompositeStatement().getInnerNodes();
for(CompositeStatementObject lambdaInnerNode : lambdaInnerNodes) {
if(!innerNodes1.contains(lambdaInnerNode)) {
innerNodes1.add(lambdaInnerNode);
addedInnerNodes1.add(lambdaInnerNode);
codeFragmentOperationMap1.put(lambdaInnerNode, operation1);
}
}
}
}
}
}
}
public UMLOperationBodyMapper(UMLOperation removedOperation, UMLOperationBodyMapper operationBodyMapper,
Map parameterToArgumentMap, UMLClassBaseDiff classDiff) throws RefactoringMinerTimedOutException {
this.parentMapper = operationBodyMapper;
this.operation1 = removedOperation;
this.operation2 = operationBodyMapper.operation2;
this.callSiteOperation = operationBodyMapper.operation1;
this.classDiff = classDiff;
this.mappings = new LinkedHashSet();
this.nonMappedLeavesT1 = new ArrayList();
this.nonMappedLeavesT2 = new ArrayList();
this.nonMappedInnerNodesT1 = new ArrayList();
this.nonMappedInnerNodesT2 = new ArrayList();
OperationBody removedOperationBody = removedOperation.getBody();
if(removedOperationBody != null) {
CompositeStatementObject composite1 = removedOperationBody.getCompositeStatement();
List leaves1 = composite1.getLeaves();
List leaves2 = operationBodyMapper.getNonMappedLeavesT2();
//adding leaves that were mapped with replacements or are inexact matches
Set addedLeaves2 = new LinkedHashSet();
for(AbstractCodeMapping mapping : operationBodyMapper.getMappings()) {
if(!returnWithVariableReplacement(mapping) && !nullLiteralReplacements(mapping) && (!mapping.getReplacements().isEmpty() || !mapping.getFragment1().equalFragment(mapping.getFragment2()))) {
AbstractCodeFragment fragment = mapping.getFragment2();
if(fragment instanceof StatementObject) {
StatementObject statement = (StatementObject)fragment;
if(!leaves2.contains(statement)) {
leaves2.add(statement);
addedLeaves2.add(statement);
}
}
}
}
resetNodes(leaves1);
//replace parameters with arguments in leaves1
if(!parameterToArgumentMap.isEmpty()) {
//check for temporary variables that the argument might be assigned to
for(StatementObject leave2 : leaves2) {
List variableDeclarations = leave2.getVariableDeclarations();
for(VariableDeclaration variableDeclaration : variableDeclarations) {
for(String parameter : parameterToArgumentMap.keySet()) {
String argument = parameterToArgumentMap.get(parameter);
if(variableDeclaration.getInitializer() != null && argument.equals(variableDeclaration.getInitializer().toString())) {
parameterToArgumentMap.put(parameter, variableDeclaration.getVariableName());
}
}
}
}
for(StatementObject leave1 : leaves1) {
leave1.replaceParametersWithArguments(parameterToArgumentMap);
}
}
//compare leaves from T1 with leaves from T2
processLeaves(leaves1, leaves2, parameterToArgumentMap);
List innerNodes1 = composite1.getInnerNodes();
innerNodes1.remove(composite1);
List innerNodes2 = operationBodyMapper.getNonMappedInnerNodesT2();
//adding innerNodes that were mapped with replacements or are inexact matches
Set addedInnerNodes2 = new LinkedHashSet();
for(AbstractCodeMapping mapping : operationBodyMapper.getMappings()) {
if(!mapping.getReplacements().isEmpty() || !mapping.getFragment1().equalFragment(mapping.getFragment2())) {
AbstractCodeFragment fragment = mapping.getFragment2();
if(fragment instanceof CompositeStatementObject) {
CompositeStatementObject statement = (CompositeStatementObject)fragment;
if(!innerNodes2.contains(statement)) {
innerNodes2.add(statement);
addedInnerNodes2.add(statement);
}
}
}
}
resetNodes(innerNodes1);
//replace parameters with arguments in innerNodes1
if(!parameterToArgumentMap.isEmpty()) {
for(CompositeStatementObject innerNode1 : innerNodes1) {
innerNode1.replaceParametersWithArguments(parameterToArgumentMap);
}
}
//compare inner nodes from T1 with inner nodes from T2
processInnerNodes(innerNodes1, innerNodes2, parameterToArgumentMap);
//match expressions in inner nodes from T2 with leaves from T1
List expressionsT2 = new ArrayList();
for(CompositeStatementObject composite : operationBodyMapper.getNonMappedInnerNodesT2()) {
for(AbstractExpression expression : composite.getExpressions()) {
expressionsT2.add(expression);
}
}
processLeaves(leaves1, expressionsT2, parameterToArgumentMap);
//remove the leaves that were mapped with replacement, if they are not mapped again for a second time
leaves2.removeAll(addedLeaves2);
//remove the innerNodes that were mapped with replacement, if they are not mapped again for a second time
innerNodes2.removeAll(addedInnerNodes2);
nonMappedLeavesT1.addAll(leaves1);
nonMappedLeavesT2.addAll(leaves2);
nonMappedInnerNodesT1.addAll(innerNodes1);
nonMappedInnerNodesT2.addAll(innerNodes2);
for(StatementObject statement : getNonMappedLeavesT2()) {
temporaryVariableAssignment(statement, nonMappedLeavesT2);
}
for(StatementObject statement : getNonMappedLeavesT1()) {
inlinedVariableAssignment(statement, nonMappedLeavesT2);
}
}
}
public UMLOperation getOperation1() {
return operation1;
}
public UMLOperation getOperation2() {
return operation2;
}
public Set getRefactorings() {
VariableReplacementAnalysis analysis = new VariableReplacementAnalysis(this, refactorings, classDiff);
refactorings.addAll(analysis.getVariableRenames());
refactorings.addAll(analysis.getVariableMerges());
refactorings.addAll(analysis.getVariableSplits());
candidateAttributeRenames.addAll(analysis.getCandidateAttributeRenames());
candidateAttributeMerges.addAll(analysis.getCandidateAttributeMerges());
candidateAttributeSplits.addAll(analysis.getCandidateAttributeSplits());
TypeReplacementAnalysis typeAnalysis = new TypeReplacementAnalysis(this.getMappings());
refactorings.addAll(typeAnalysis.getChangedTypes());
return refactorings;
}
public Set getRefactoringsAfterPostProcessing() {
return refactorings;
}
public Set getCandidateAttributeRenames() {
return candidateAttributeRenames;
}
public Set getCandidateAttributeMerges() {
return candidateAttributeMerges;
}
public Set getCandidateAttributeSplits() {
return candidateAttributeSplits;
}
public Set getMappings() {
return mappings;
}
public List getNonMappedLeavesT1() {
return nonMappedLeavesT1;
}
public List getNonMappedLeavesT2() {
return nonMappedLeavesT2;
}
public List getNonMappedInnerNodesT1() {
return nonMappedInnerNodesT1;
}
public List getNonMappedInnerNodesT2() {
return nonMappedInnerNodesT2;
}
public int mappingsWithoutBlocks() {
int count = 0;
for(AbstractCodeMapping mapping : getMappings()) {
if(mapping.getFragment1().countableStatement() && mapping.getFragment2().countableStatement())
count++;
}
return count;
}
public int nonMappedElementsT1() {
int nonMappedInnerNodeCount = 0;
for(CompositeStatementObject composite : getNonMappedInnerNodesT1()) {
if(composite.countableStatement())
nonMappedInnerNodeCount++;
}
int nonMappedLeafCount = 0;
for(StatementObject statement : getNonMappedLeavesT1()) {
if(statement.countableStatement())
nonMappedLeafCount++;
}
return nonMappedLeafCount + nonMappedInnerNodeCount;
}
public int nonMappedLeafElementsT1() {
int nonMappedLeafCount = 0;
for(StatementObject statement : getNonMappedLeavesT1()) {
if(statement.countableStatement())
nonMappedLeafCount++;
}
return nonMappedLeafCount;
}
public int nonMappedElementsT2() {
int nonMappedInnerNodeCount = 0;
for(CompositeStatementObject composite : getNonMappedInnerNodesT2()) {
if(composite.countableStatement())
nonMappedInnerNodeCount++;
}
int nonMappedLeafCount = 0;
for(StatementObject statement : getNonMappedLeavesT2()) {
if(statement.countableStatement() && !isTemporaryVariableAssignment(statement))
nonMappedLeafCount++;
}
return nonMappedLeafCount + nonMappedInnerNodeCount;
}
public int nonMappedLeafElementsT2() {
int nonMappedLeafCount = 0;
for(StatementObject statement : getNonMappedLeavesT2()) {
if(statement.countableStatement() && !isTemporaryVariableAssignment(statement))
nonMappedLeafCount++;
}
return nonMappedLeafCount;
}
private boolean isTemporaryVariableAssignment(StatementObject statement) {
for(Refactoring refactoring : refactorings) {
if(refactoring instanceof ExtractVariableRefactoring) {
ExtractVariableRefactoring extractVariable = (ExtractVariableRefactoring)refactoring;
if(statement.getVariableDeclarations().contains(extractVariable.getVariableDeclaration())) {
return true;
}
}
}
return false;
}
private void inlinedVariableAssignment(StatementObject statement, List nonMappedLeavesT2) {
for(AbstractCodeMapping mapping : getMappings()) {
mapping.inlinedVariableAssignment(statement, nonMappedLeavesT2, refactorings);
}
}
private void temporaryVariableAssignment(StatementObject statement, List nonMappedLeavesT2) {
for(AbstractCodeMapping mapping : getMappings()) {
UMLClassBaseDiff classDiff = this.classDiff != null ? this.classDiff : parentMapper != null ? parentMapper.classDiff : null;
mapping.temporaryVariableAssignment(statement, nonMappedLeavesT2, refactorings, classDiff);
}
}
public int nonMappedElementsT2CallingAddedOperation(List addedOperations) {
int nonMappedInnerNodeCount = 0;
for(CompositeStatementObject composite : getNonMappedInnerNodesT2()) {
if(composite.countableStatement()) {
Map> methodInvocationMap = composite.getMethodInvocationMap();
for(String key : methodInvocationMap.keySet()) {
for(OperationInvocation invocation : methodInvocationMap.get(key)) {
for(UMLOperation operation : addedOperations) {
if(invocation.matchesOperation(operation, operation2.variableTypeMap(), modelDiff)) {
nonMappedInnerNodeCount++;
break;
}
}
}
}
}
}
int nonMappedLeafCount = 0;
for(StatementObject statement : getNonMappedLeavesT2()) {
if(statement.countableStatement()) {
Map> methodInvocationMap = statement.getMethodInvocationMap();
for(String key : methodInvocationMap.keySet()) {
for(OperationInvocation invocation : methodInvocationMap.get(key)) {
for(UMLOperation operation : addedOperations) {
if(invocation.matchesOperation(operation, operation2.variableTypeMap(), modelDiff)) {
nonMappedLeafCount++;
break;
}
}
}
}
}
}
return nonMappedLeafCount + nonMappedInnerNodeCount;
}
public int nonMappedElementsT1CallingRemovedOperation(List removedOperations) {
int nonMappedInnerNodeCount = 0;
for(CompositeStatementObject composite : getNonMappedInnerNodesT1()) {
if(composite.countableStatement()) {
Map> methodInvocationMap = composite.getMethodInvocationMap();
for(String key : methodInvocationMap.keySet()) {
for(OperationInvocation invocation : methodInvocationMap.get(key)) {
for(UMLOperation operation : removedOperations) {
if(invocation.matchesOperation(operation, operation1.variableTypeMap(), modelDiff)) {
nonMappedInnerNodeCount++;
break;
}
}
}
}
}
}
int nonMappedLeafCount = 0;
for(StatementObject statement : getNonMappedLeavesT1()) {
if(statement.countableStatement()) {
Map> methodInvocationMap = statement.getMethodInvocationMap();
for(String key : methodInvocationMap.keySet()) {
for(OperationInvocation invocation : methodInvocationMap.get(key)) {
for(UMLOperation operation : removedOperations) {
if(invocation.matchesOperation(operation, operation1.variableTypeMap(), modelDiff)) {
nonMappedLeafCount++;
break;
}
}
}
}
}
}
return nonMappedLeafCount + nonMappedInnerNodeCount;
}
public boolean callsRemovedAndAddedOperation(List removedOperations, List addedOperations) {
boolean removedOperationCalled = false;
for(OperationInvocation invocation : operation1.getAllOperationInvocations()) {
for(UMLOperation operation : removedOperations) {
if(invocation.matchesOperation(operation, operation1.variableTypeMap(), modelDiff)) {
removedOperationCalled = true;
break;
}
}
if(removedOperationCalled)
break;
}
boolean addedOperationCalled = false;
for(OperationInvocation invocation : operation2.getAllOperationInvocations()) {
for(UMLOperation operation : addedOperations) {
if(invocation.matchesOperation(operation, operation2.variableTypeMap(), modelDiff)) {
addedOperationCalled = true;
break;
}
}
if(addedOperationCalled)
break;
}
return removedOperationCalled && addedOperationCalled;
}
public int exactMatches() {
int count = 0;
for(AbstractCodeMapping mapping : getMappings()) {
if(mapping.isExact() && mapping.getFragment1().countableStatement() && mapping.getFragment2().countableStatement() &&
!mapping.getFragment1().getString().equals("try"))
count++;
}
return count;
}
public List getExactMatches() {
List exactMatches = new ArrayList();
for(AbstractCodeMapping mapping : getMappings()) {
if(mapping.isExact() && mapping.getFragment1().countableStatement() && mapping.getFragment2().countableStatement() &&
!mapping.getFragment1().getString().equals("try"))
exactMatches.add(mapping);
}
return exactMatches;
}
private int editDistance() {
int count = 0;
for(AbstractCodeMapping mapping : getMappings()) {
if(mapping.isIdenticalWithExtractedVariable() || mapping.isIdenticalWithInlinedVariable()) {
continue;
}
String s1 = preprocessInput1(mapping.getFragment1(), mapping.getFragment2());
String s2 = preprocessInput2(mapping.getFragment1(), mapping.getFragment2());
if(!s1.equals(s2)) {
count += StringDistance.editDistance(s1, s2);
}
}
return count;
}
public double normalizedEditDistance() {
double editDistance = 0;
double maxLength = 0;
for(AbstractCodeMapping mapping : getMappings()) {
if(mapping.isIdenticalWithExtractedVariable() || mapping.isIdenticalWithInlinedVariable()) {
continue;
}
String s1 = preprocessInput1(mapping.getFragment1(), mapping.getFragment2());
String s2 = preprocessInput2(mapping.getFragment1(), mapping.getFragment2());
if(!s1.equals(s2)) {
editDistance += StringDistance.editDistance(s1, s2);
maxLength += Math.max(s1.length(), s2.length());
}
}
return editDistance/maxLength;
}
public int operationNameEditDistance() {
return StringDistance.editDistance(this.operation1.getName(), this.operation2.getName());
}
public Set getReplacements() {
Set replacements = new LinkedHashSet();
for(AbstractCodeMapping mapping : getMappings()) {
replacements.addAll(mapping.getReplacements());
}
return replacements;
}
public Set getReplacementsInvolvingMethodInvocation() {
Set replacements = new LinkedHashSet();
for(AbstractCodeMapping mapping : getMappings()) {
for(Replacement replacement : mapping.getReplacements()) {
if(replacement instanceof MethodInvocationReplacement ||
replacement instanceof VariableReplacementWithMethodInvocation ||
replacement instanceof ClassInstanceCreationWithMethodInvocationReplacement ||
replacement.getType().equals(ReplacementType.ARGUMENT_REPLACED_WITH_RIGHT_HAND_SIDE_OF_ASSIGNMENT_EXPRESSION)) {
replacements.add(replacement);
}
}
}
return replacements;
}
public Set getMethodInvocationRenameReplacements() {
Set replacements = new LinkedHashSet();
for(AbstractCodeMapping mapping : getMappings()) {
for(Replacement replacement : mapping.getReplacements()) {
if(replacement.getType().equals(ReplacementType.METHOD_INVOCATION_NAME) ||
replacement.getType().equals(ReplacementType.METHOD_INVOCATION_NAME_AND_ARGUMENT)) {
replacements.add((MethodInvocationReplacement) replacement);
}
}
}
return replacements;
}
public void processInnerNodes(List innerNodes1, List innerNodes2,
Map parameterToArgumentMap) throws RefactoringMinerTimedOutException {
List removedOperations = classDiff != null ? classDiff.getRemovedOperations() : new ArrayList();
List addedOperations = classDiff != null ? classDiff.getAddedOperations() : new ArrayList();
if(innerNodes1.size() <= innerNodes2.size()) {
//exact string+depth matching - inner nodes
for(ListIterator innerNodeIterator1 = innerNodes1.listIterator(); innerNodeIterator1.hasNext();) {
CompositeStatementObject statement1 = innerNodeIterator1.next();
TreeSet mappingSet = new TreeSet();
for(ListIterator innerNodeIterator2 = innerNodes2.listIterator(); innerNodeIterator2.hasNext();) {
CompositeStatementObject statement2 = innerNodeIterator2.next();
double score = computeScore(statement1, statement2, removedOperations, addedOperations);
if((statement1.getString().equals(statement2.getString()) || statement1.getArgumentizedString().equals(statement2.getArgumentizedString())) &&
statement1.getDepth() == statement2.getDepth() &&
(score > 0 || Math.max(statement1.getStatements().size(), statement2.getStatements().size()) == 0)) {
CompositeStatementObjectMapping mapping = createCompositeMapping(statement1, statement2, parameterToArgumentMap, score);
mappingSet.add(mapping);
}
}
if(!mappingSet.isEmpty()) {
CompositeStatementObjectMapping minStatementMapping = mappingSet.first();
mappings.add(minStatementMapping);
innerNodes2.remove(minStatementMapping.getFragment2());
innerNodeIterator1.remove();
}
}
//exact string matching - inner nodes - finds moves to another level
for(ListIterator innerNodeIterator1 = innerNodes1.listIterator(); innerNodeIterator1.hasNext();) {
CompositeStatementObject statement1 = innerNodeIterator1.next();
TreeSet mappingSet = new TreeSet();
for(ListIterator innerNodeIterator2 = innerNodes2.listIterator(); innerNodeIterator2.hasNext();) {
CompositeStatementObject statement2 = innerNodeIterator2.next();
double score = computeScore(statement1, statement2, removedOperations, addedOperations);
if((statement1.getString().equals(statement2.getString()) || statement1.getArgumentizedString().equals(statement2.getArgumentizedString())) &&
(score > 0 || Math.max(statement1.getStatements().size(), statement2.getStatements().size()) == 0)) {
CompositeStatementObjectMapping mapping = createCompositeMapping(statement1, statement2, parameterToArgumentMap, score);
mappingSet.add(mapping);
}
}
if(!mappingSet.isEmpty()) {
CompositeStatementObjectMapping minStatementMapping = mappingSet.first();
mappings.add(minStatementMapping);
innerNodes2.remove(minStatementMapping.getFragment2());
innerNodeIterator1.remove();
}
}
// exact matching - inner nodes - with variable renames
for(ListIterator innerNodeIterator1 = innerNodes1.listIterator(); innerNodeIterator1.hasNext();) {
CompositeStatementObject statement1 = innerNodeIterator1.next();
TreeSet mappingSet = new TreeSet();
for(ListIterator innerNodeIterator2 = innerNodes2.listIterator(); innerNodeIterator2.hasNext();) {
CompositeStatementObject statement2 = innerNodeIterator2.next();
ReplacementInfo replacementInfo = initializeReplacementInfo(statement1, statement2, innerNodes1, innerNodes2);
Set replacements = findReplacementsWithExactMatching(statement1, statement2, parameterToArgumentMap, replacementInfo);
double score = computeScore(statement1, statement2, removedOperations, addedOperations);
if(score == 0 && replacements != null && replacements.size() == 1 &&
(replacements.iterator().next().getType().equals(ReplacementType.INFIX_OPERATOR) || replacements.iterator().next().getType().equals(ReplacementType.INVERT_CONDITIONAL))) {
//special handling when there is only an infix operator or invert conditional replacement, but no children mapped
score = 1;
}
if(replacements != null &&
(score > 0 || Math.max(statement1.getStatements().size(), statement2.getStatements().size()) == 0)) {
CompositeStatementObjectMapping mapping = createCompositeMapping(statement1, statement2, parameterToArgumentMap, score);
mapping.addReplacements(replacements);
mappingSet.add(mapping);
}
}
if(!mappingSet.isEmpty()) {
CompositeStatementObjectMapping minStatementMapping = mappingSet.first();
mappings.add(minStatementMapping);
innerNodes2.remove(minStatementMapping.getFragment2());
innerNodeIterator1.remove();
}
}
}
else {
//exact string+depth matching - inner nodes
for(ListIterator innerNodeIterator2 = innerNodes2.listIterator(); innerNodeIterator2.hasNext();) {
CompositeStatementObject statement2 = innerNodeIterator2.next();
TreeSet mappingSet = new TreeSet();
for(ListIterator innerNodeIterator1 = innerNodes1.listIterator(); innerNodeIterator1.hasNext();) {
CompositeStatementObject statement1 = innerNodeIterator1.next();
double score = computeScore(statement1, statement2, removedOperations, addedOperations);
if((statement1.getString().equals(statement2.getString()) || statement1.getArgumentizedString().equals(statement2.getArgumentizedString())) &&
statement1.getDepth() == statement2.getDepth() &&
(score > 0 || Math.max(statement1.getStatements().size(), statement2.getStatements().size()) == 0)) {
CompositeStatementObjectMapping mapping = createCompositeMapping(statement1, statement2, parameterToArgumentMap, score);
mappingSet.add(mapping);
}
}
if(!mappingSet.isEmpty()) {
CompositeStatementObjectMapping minStatementMapping = mappingSet.first();
mappings.add(minStatementMapping);
innerNodes1.remove(minStatementMapping.getFragment1());
innerNodeIterator2.remove();
}
}
//exact string matching - inner nodes - finds moves to another level
for(ListIterator innerNodeIterator2 = innerNodes2.listIterator(); innerNodeIterator2.hasNext();) {
CompositeStatementObject statement2 = innerNodeIterator2.next();
TreeSet mappingSet = new TreeSet();
for(ListIterator innerNodeIterator1 = innerNodes1.listIterator(); innerNodeIterator1.hasNext();) {
CompositeStatementObject statement1 = innerNodeIterator1.next();
double score = computeScore(statement1, statement2, removedOperations, addedOperations);
if((statement1.getString().equals(statement2.getString()) || statement1.getArgumentizedString().equals(statement2.getArgumentizedString())) &&
(score > 0 || Math.max(statement1.getStatements().size(), statement2.getStatements().size()) == 0)) {
CompositeStatementObjectMapping mapping = createCompositeMapping(statement1, statement2, parameterToArgumentMap, score);
mappingSet.add(mapping);
}
}
if(!mappingSet.isEmpty()) {
CompositeStatementObjectMapping minStatementMapping = mappingSet.first();
mappings.add(minStatementMapping);
innerNodes1.remove(minStatementMapping.getFragment1());
innerNodeIterator2.remove();
}
}
// exact matching - inner nodes - with variable renames
for(ListIterator innerNodeIterator2 = innerNodes2.listIterator(); innerNodeIterator2.hasNext();) {
CompositeStatementObject statement2 = innerNodeIterator2.next();
TreeSet mappingSet = new TreeSet();
for(ListIterator innerNodeIterator1 = innerNodes1.listIterator(); innerNodeIterator1.hasNext();) {
CompositeStatementObject statement1 = innerNodeIterator1.next();
ReplacementInfo replacementInfo = initializeReplacementInfo(statement1, statement2, innerNodes1, innerNodes2);
Set replacements = findReplacementsWithExactMatching(statement1, statement2, parameterToArgumentMap, replacementInfo);
double score = computeScore(statement1, statement2, removedOperations, addedOperations);
if(score == 0 && replacements != null && replacements.size() == 1 &&
(replacements.iterator().next().getType().equals(ReplacementType.INFIX_OPERATOR) || replacements.iterator().next().getType().equals(ReplacementType.INVERT_CONDITIONAL))) {
//special handling when there is only an infix operator or invert conditional replacement, but no children mapped
score = 1;
}
if(replacements != null &&
(score > 0 || Math.max(statement1.getStatements().size(), statement2.getStatements().size()) == 0)) {
CompositeStatementObjectMapping mapping = createCompositeMapping(statement1, statement2, parameterToArgumentMap, score);
mapping.addReplacements(replacements);
mappingSet.add(mapping);
}
}
if(!mappingSet.isEmpty()) {
CompositeStatementObjectMapping minStatementMapping = mappingSet.first();
mappings.add(minStatementMapping);
innerNodes1.remove(minStatementMapping.getFragment1());
innerNodeIterator2.remove();
}
}
}
}
private double computeScore(CompositeStatementObject statement1, CompositeStatementObject statement2,
List removedOperations, List addedOperations) {
if(statement1 instanceof TryStatementObject && statement2 instanceof TryStatementObject) {
return compositeChildMatchingScore((TryStatementObject)statement1, (TryStatementObject)statement2, mappings, removedOperations, addedOperations);
}
return compositeChildMatchingScore(statement1, statement2, mappings, removedOperations, addedOperations);
}
private CompositeStatementObjectMapping createCompositeMapping(CompositeStatementObject statement1,
CompositeStatementObject statement2, Map parameterToArgumentMap, double score) {
UMLOperation operation1 = codeFragmentOperationMap1.containsKey(statement1) ? codeFragmentOperationMap1.get(statement1) : this.operation1;
UMLOperation operation2 = codeFragmentOperationMap2.containsKey(statement2) ? codeFragmentOperationMap2.get(statement2) : this.operation2;
CompositeStatementObjectMapping mapping = new CompositeStatementObjectMapping(statement1, statement2, operation1, operation2, score);
for(String key : parameterToArgumentMap.keySet()) {
String value = parameterToArgumentMap.get(key);
if(!key.equals(value) && ReplacementUtil.contains(statement2.getString(), key) && ReplacementUtil.contains(statement1.getString(), value)) {
mapping.addReplacement(new Replacement(value, key, ReplacementType.VARIABLE_NAME));
}
}
return mapping;
}
public void processLeaves(List extends AbstractCodeFragment> leaves1, List extends AbstractCodeFragment> leaves2,
Map parameterToArgumentMap) throws RefactoringMinerTimedOutException {
List> postponedMappingSets = new ArrayList>();
if(leaves1.size() <= leaves2.size()) {
//exact string+depth matching - leaf nodes
for(ListIterator extends AbstractCodeFragment> leafIterator1 = leaves1.listIterator(); leafIterator1.hasNext();) {
AbstractCodeFragment leaf1 = leafIterator1.next();
TreeSet mappingSet = new TreeSet();
for(ListIterator extends AbstractCodeFragment> leafIterator2 = leaves2.listIterator(); leafIterator2.hasNext();) {
AbstractCodeFragment leaf2 = leafIterator2.next();
String argumentizedString1 = preprocessInput1(leaf1, leaf2);
String argumentizedString2 = preprocessInput2(leaf1, leaf2);
if((leaf1.getString().equals(leaf2.getString()) || argumentizedString1.equals(argumentizedString2)) && leaf1.getDepth() == leaf2.getDepth()) {
LeafMapping mapping = createLeafMapping(leaf1, leaf2, parameterToArgumentMap);
mappingSet.add(mapping);
}
}
if(!mappingSet.isEmpty()) {
LeafMapping minStatementMapping = mappingSet.first();
mappings.add(minStatementMapping);
leaves2.remove(minStatementMapping.getFragment2());
leafIterator1.remove();
}
}
//exact string matching - leaf nodes - finds moves to another level
for(ListIterator extends AbstractCodeFragment> leafIterator1 = leaves1.listIterator(); leafIterator1.hasNext();) {
AbstractCodeFragment leaf1 = leafIterator1.next();
TreeSet mappingSet = new TreeSet();
for(ListIterator extends AbstractCodeFragment> leafIterator2 = leaves2.listIterator(); leafIterator2.hasNext();) {
AbstractCodeFragment leaf2 = leafIterator2.next();
String argumentizedString1 = preprocessInput1(leaf1, leaf2);
String argumentizedString2 = preprocessInput2(leaf1, leaf2);
if((leaf1.getString().equals(leaf2.getString()) || argumentizedString1.equals(argumentizedString2))) {
LeafMapping mapping = createLeafMapping(leaf1, leaf2, parameterToArgumentMap);
mappingSet.add(mapping);
}
}
if(!mappingSet.isEmpty()) {
LeafMapping minStatementMapping = mappingSet.first();
mappings.add(minStatementMapping);
leaves2.remove(minStatementMapping.getFragment2());
leafIterator1.remove();
}
}
// exact matching with variable renames
for(ListIterator extends AbstractCodeFragment> leafIterator1 = leaves1.listIterator(); leafIterator1.hasNext();) {
AbstractCodeFragment leaf1 = leafIterator1.next();
TreeSet mappingSet = new TreeSet();
for(ListIterator extends AbstractCodeFragment> leafIterator2 = leaves2.listIterator(); leafIterator2.hasNext();) {
AbstractCodeFragment leaf2 = leafIterator2.next();
ReplacementInfo replacementInfo = initializeReplacementInfo(leaf1, leaf2, leaves1, leaves2);
Set replacements = findReplacementsWithExactMatching(leaf1, leaf2, parameterToArgumentMap, replacementInfo);
if (replacements != null) {
LeafMapping mapping = createLeafMapping(leaf1, leaf2, parameterToArgumentMap);
mapping.addReplacements(replacements);
for(AbstractCodeFragment leaf : leaves2) {
if(leaf.equals(leaf2)) {
break;
}
UMLClassBaseDiff classDiff = this.classDiff != null ? this.classDiff : parentMapper != null ? parentMapper.classDiff : null;
mapping.temporaryVariableAssignment(leaf, leaves2, refactorings, classDiff);
if(mapping.isIdenticalWithExtractedVariable()) {
break;
}
}
for(AbstractCodeFragment leaf : leaves1) {
if(leaf.equals(leaf1)) {
break;
}
mapping.inlinedVariableAssignment(leaf, leaves2, refactorings);
if(mapping.isIdenticalWithInlinedVariable()) {
break;
}
}
mappingSet.add(mapping);
}
}
if(!mappingSet.isEmpty()) {
AbstractMap.SimpleEntry switchParentEntry = null;
if(variableDeclarationMappingsWithSameReplacementTypes(mappingSet)) {
//postpone mapping
postponedMappingSets.add(mappingSet);
}
else if((switchParentEntry = multipleMappingsUnderTheSameSwitch(mappingSet)) != null) {
LeafMapping bestMapping = findBestMappingBasedOnMappedSwitchCases(switchParentEntry, mappingSet);
mappings.add(bestMapping);
leaves2.remove(bestMapping.getFragment1());
leafIterator1.remove();
}
else {
LeafMapping minStatementMapping = mappingSet.first();
mappings.add(minStatementMapping);
leaves2.remove(minStatementMapping.getFragment2());
leafIterator1.remove();
}
}
}
}
else {
//exact string+depth matching - leaf nodes
for(ListIterator extends AbstractCodeFragment> leafIterator2 = leaves2.listIterator(); leafIterator2.hasNext();) {
AbstractCodeFragment leaf2 = leafIterator2.next();
TreeSet mappingSet = new TreeSet();
for(ListIterator extends AbstractCodeFragment> leafIterator1 = leaves1.listIterator(); leafIterator1.hasNext();) {
AbstractCodeFragment leaf1 = leafIterator1.next();
String argumentizedString1 = preprocessInput1(leaf1, leaf2);
String argumentizedString2 = preprocessInput2(leaf1, leaf2);
if((leaf1.getString().equals(leaf2.getString()) || argumentizedString1.equals(argumentizedString2)) && leaf1.getDepth() == leaf2.getDepth()) {
LeafMapping mapping = createLeafMapping(leaf1, leaf2, parameterToArgumentMap);
mappingSet.add(mapping);
}
}
if(!mappingSet.isEmpty()) {
LeafMapping minStatementMapping = mappingSet.first();
mappings.add(minStatementMapping);
leaves1.remove(minStatementMapping.getFragment1());
leafIterator2.remove();
}
}
//exact string matching - leaf nodes - finds moves to another level
for(ListIterator extends AbstractCodeFragment> leafIterator2 = leaves2.listIterator(); leafIterator2.hasNext();) {
AbstractCodeFragment leaf2 = leafIterator2.next();
TreeSet mappingSet = new TreeSet();
for(ListIterator extends AbstractCodeFragment> leafIterator1 = leaves1.listIterator(); leafIterator1.hasNext();) {
AbstractCodeFragment leaf1 = leafIterator1.next();
String argumentizedString1 = preprocessInput1(leaf1, leaf2);
String argumentizedString2 = preprocessInput2(leaf1, leaf2);
if((leaf1.getString().equals(leaf2.getString()) || argumentizedString1.equals(argumentizedString2))) {
LeafMapping mapping = createLeafMapping(leaf1, leaf2, parameterToArgumentMap);
mappingSet.add(mapping);
}
}
if(!mappingSet.isEmpty()) {
LeafMapping minStatementMapping = mappingSet.first();
mappings.add(minStatementMapping);
leaves1.remove(minStatementMapping.getFragment1());
leafIterator2.remove();
}
}
// exact matching with variable renames
for(ListIterator extends AbstractCodeFragment> leafIterator2 = leaves2.listIterator(); leafIterator2.hasNext();) {
AbstractCodeFragment leaf2 = leafIterator2.next();
TreeSet mappingSet = new TreeSet();
for(ListIterator extends AbstractCodeFragment> leafIterator1 = leaves1.listIterator(); leafIterator1.hasNext();) {
AbstractCodeFragment leaf1 = leafIterator1.next();
ReplacementInfo replacementInfo = initializeReplacementInfo(leaf1, leaf2, leaves1, leaves2);
Set replacements = findReplacementsWithExactMatching(leaf1, leaf2, parameterToArgumentMap, replacementInfo);
if (replacements != null) {
LeafMapping mapping = createLeafMapping(leaf1, leaf2, parameterToArgumentMap);
mapping.addReplacements(replacements);
for(AbstractCodeFragment leaf : leaves2) {
if(leaf.equals(leaf2)) {
break;
}
UMLClassBaseDiff classDiff = this.classDiff != null ? this.classDiff : parentMapper != null ? parentMapper.classDiff : null;
mapping.temporaryVariableAssignment(leaf, leaves2, refactorings, classDiff);
if(mapping.isIdenticalWithExtractedVariable()) {
break;
}
}
for(AbstractCodeFragment leaf : leaves1) {
if(leaf.equals(leaf1)) {
break;
}
mapping.inlinedVariableAssignment(leaf, leaves2, refactorings);
if(mapping.isIdenticalWithInlinedVariable()) {
break;
}
}
mappingSet.add(mapping);
}
}
if(!mappingSet.isEmpty()) {
AbstractMap.SimpleEntry switchParentEntry = null;
if(variableDeclarationMappingsWithSameReplacementTypes(mappingSet)) {
//postpone mapping
postponedMappingSets.add(mappingSet);
}
else if((switchParentEntry = multipleMappingsUnderTheSameSwitch(mappingSet)) != null) {
LeafMapping bestMapping = findBestMappingBasedOnMappedSwitchCases(switchParentEntry, mappingSet);
mappings.add(bestMapping);
leaves1.remove(bestMapping.getFragment1());
leafIterator2.remove();
}
else {
LeafMapping minStatementMapping = mappingSet.first();
mappings.add(minStatementMapping);
leaves1.remove(minStatementMapping.getFragment1());
leafIterator2.remove();
}
}
}
}
for(TreeSet postponed : postponedMappingSets) {
Set mappingsToBeAdded = new LinkedHashSet();
for(LeafMapping variableDeclarationMapping : postponed) {
for(AbstractCodeMapping previousMapping : this.mappings) {
Set intersection = variableDeclarationMapping.commonReplacements(previousMapping);
if(!intersection.isEmpty()) {
for(Replacement commonReplacement : intersection) {
if(commonReplacement.getType().equals(ReplacementType.VARIABLE_NAME) &&
variableDeclarationMapping.getFragment1().getVariableDeclaration(commonReplacement.getBefore()) != null &&
variableDeclarationMapping.getFragment2().getVariableDeclaration(commonReplacement.getAfter()) != null) {
mappingsToBeAdded.add(variableDeclarationMapping);
}
}
}
}
}
if(mappingsToBeAdded.size() == 1) {
LeafMapping minStatementMapping = mappingsToBeAdded.iterator().next();
this.mappings.add(minStatementMapping);
leaves1.remove(minStatementMapping.getFragment1());
leaves2.remove(minStatementMapping.getFragment2());
}
else {
LeafMapping minStatementMapping = postponed.first();
this.mappings.add(minStatementMapping);
leaves1.remove(minStatementMapping.getFragment1());
leaves2.remove(minStatementMapping.getFragment2());
}
}
}
private ReplacementInfo initializeReplacementInfo(AbstractCodeFragment leaf1, AbstractCodeFragment leaf2,
List extends AbstractCodeFragment> leaves1, List extends AbstractCodeFragment> leaves2) {
List extends AbstractCodeFragment> l1 = new ArrayList(leaves1);
l1.remove(leaf1);
List extends AbstractCodeFragment> l2 = new ArrayList(leaves2);
l2.remove(leaf2);
ReplacementInfo replacementInfo = new ReplacementInfo(
preprocessInput1(leaf1, leaf2),
preprocessInput2(leaf1, leaf2),
l1, l2);
return replacementInfo;
}
private boolean variableDeclarationMappingsWithSameReplacementTypes(Set mappingSet) {
if(mappingSet.size() > 1) {
Set variableDeclarationMappings = new LinkedHashSet();
for(LeafMapping mapping : mappingSet) {
if(mapping.getFragment1().getVariableDeclarations().size() > 0 &&
mapping.getFragment2().getVariableDeclarations().size() > 0) {
variableDeclarationMappings.add(mapping);
}
}
if(variableDeclarationMappings.size() == mappingSet.size()) {
Set replacementTypes = null;
Set mappingsWithSameReplacementTypes = new LinkedHashSet();
for(LeafMapping mapping : variableDeclarationMappings) {
if(replacementTypes == null) {
replacementTypes = mapping.getReplacementTypes();
mappingsWithSameReplacementTypes.add(mapping);
}
else if(mapping.getReplacementTypes().equals(replacementTypes)) {
mappingsWithSameReplacementTypes.add(mapping);
}
else if(mapping.getReplacementTypes().containsAll(replacementTypes) || replacementTypes.containsAll(mapping.getReplacementTypes())) {
OperationInvocation invocation1 = mapping.getFragment1().invocationCoveringEntireFragment();
OperationInvocation invocation2 = mapping.getFragment2().invocationCoveringEntireFragment();
if(invocation1 != null && invocation2 != null) {
for(Replacement replacement : mapping.getReplacements()) {
if(replacement.getType().equals(ReplacementType.VARIABLE_NAME)) {
if(invocation1.getName().equals(replacement.getBefore()) && invocation2.getName().equals(replacement.getAfter())) {
mappingsWithSameReplacementTypes.add(mapping);
break;
}
}
}
}
}
}
if(mappingsWithSameReplacementTypes.size() == mappingSet.size()) {
return true;
}
}
}
return false;
}
private LeafMapping findBestMappingBasedOnMappedSwitchCases(AbstractMap.SimpleEntry switchParentEntry, TreeSet mappingSet) {
CompositeStatementObject switchParent1 = switchParentEntry.getKey();
CompositeStatementObject switchParent2 = switchParentEntry.getValue();
AbstractCodeMapping currentSwitchCase = null;
for(AbstractCodeMapping mapping : this.mappings) {
AbstractCodeFragment fragment1 = mapping.getFragment1();
AbstractCodeFragment fragment2 = mapping.getFragment2();
if(fragment1 instanceof AbstractStatement && fragment2 instanceof AbstractStatement) {
AbstractStatement statement1 = (AbstractStatement)fragment1;
AbstractStatement statement2 = (AbstractStatement)fragment2;
CompositeStatementObject parent1 = statement1.getParent();
CompositeStatementObject parent2 = statement2.getParent();
if(parent1 == switchParent1 && parent2 == switchParent2 && mapping.isExact() &&
statement1.getLocationInfo().getCodeElementType().equals(CodeElementType.SWITCH_CASE) &&
statement2.getLocationInfo().getCodeElementType().equals(CodeElementType.SWITCH_CASE)) {
currentSwitchCase = mapping;
}
else if(parent1 == switchParent1 && parent2 == switchParent2 &&
statement1.getLocationInfo().getCodeElementType().equals(CodeElementType.BREAK_STATEMENT) &&
statement2.getLocationInfo().getCodeElementType().equals(CodeElementType.BREAK_STATEMENT)) {
if(currentSwitchCase != null) {
for(LeafMapping leafMapping : mappingSet) {
if(leafMapping.getFragment1().getIndex() > currentSwitchCase.getFragment1().getIndex() &&
leafMapping.getFragment2().getIndex() > currentSwitchCase.getFragment2().getIndex() &&
leafMapping.getFragment1().getIndex() < mapping.getFragment1().getIndex() &&
leafMapping.getFragment2().getIndex() < mapping.getFragment2().getIndex()) {
return leafMapping;
}
}
}
}
else if(parent1 == switchParent1 && parent2 == switchParent2 &&
statement1.getLocationInfo().getCodeElementType().equals(CodeElementType.RETURN_STATEMENT) &&
statement2.getLocationInfo().getCodeElementType().equals(CodeElementType.RETURN_STATEMENT)) {
if(currentSwitchCase != null) {
for(LeafMapping leafMapping : mappingSet) {
if(leafMapping.getFragment1().getIndex() > currentSwitchCase.getFragment1().getIndex() &&
leafMapping.getFragment2().getIndex() > currentSwitchCase.getFragment2().getIndex() &&
leafMapping.getFragment1().getIndex() < mapping.getFragment1().getIndex() &&
leafMapping.getFragment2().getIndex() < mapping.getFragment2().getIndex()) {
return leafMapping;
}
}
}
}
}
}
return mappingSet.first();
}
private AbstractMap.SimpleEntry multipleMappingsUnderTheSameSwitch(Set mappingSet) {
CompositeStatementObject switchParent1 = null;
CompositeStatementObject switchParent2 = null;
if(mappingSet.size() > 1) {
for(LeafMapping mapping : mappingSet) {
AbstractCodeFragment fragment1 = mapping.getFragment1();
AbstractCodeFragment fragment2 = mapping.getFragment2();
if(fragment1 instanceof AbstractStatement && fragment2 instanceof AbstractStatement) {
AbstractStatement statement1 = (AbstractStatement)fragment1;
AbstractStatement statement2 = (AbstractStatement)fragment2;
CompositeStatementObject parent1 = statement1.getParent();
CompositeStatementObject parent2 = statement2.getParent();
if(parent1.getLocationInfo().getCodeElementType().equals(CodeElementType.SWITCH_STATEMENT) &&
parent2.getLocationInfo().getCodeElementType().equals(CodeElementType.SWITCH_STATEMENT)) {
if(switchParent1 == null && switchParent2 == null) {
switchParent1 = parent1;
switchParent2 = parent2;
}
else if(switchParent1 != parent1 || switchParent2 != parent2) {
return null;
}
}
else {
return null;
}
}
}
}
if(switchParent1 != null && switchParent2 != null) {
return new AbstractMap.SimpleEntry<>(switchParent1, switchParent2);
}
return null;
}
private LeafMapping createLeafMapping(AbstractCodeFragment leaf1, AbstractCodeFragment leaf2, Map parameterToArgumentMap) {
UMLOperation operation1 = codeFragmentOperationMap1.containsKey(leaf1) ? codeFragmentOperationMap1.get(leaf1) : this.operation1;
UMLOperation operation2 = codeFragmentOperationMap2.containsKey(leaf2) ? codeFragmentOperationMap2.get(leaf2) : this.operation2;
LeafMapping mapping = new LeafMapping(leaf1, leaf2, operation1, operation2);
for(String key : parameterToArgumentMap.keySet()) {
String value = parameterToArgumentMap.get(key);
if(!key.equals(value) && ReplacementUtil.contains(leaf2.getString(), key) && ReplacementUtil.contains(leaf1.getString(), value)) {
mapping.addReplacement(new Replacement(value, key, ReplacementType.VARIABLE_NAME));
}
}
return mapping;
}
private String preprocessInput1(AbstractCodeFragment leaf1, AbstractCodeFragment leaf2) {
return preprocessInput(leaf1, leaf2);
}
private String preprocessInput2(AbstractCodeFragment leaf1, AbstractCodeFragment leaf2) {
return preprocessInput(leaf2, leaf1);
}
private String preprocessInput(AbstractCodeFragment leaf1, AbstractCodeFragment leaf2) {
String argumentizedString = new String(leaf1.getArgumentizedString());
if (leaf1 instanceof StatementObject && leaf2 instanceof AbstractExpression) {
if (argumentizedString.startsWith("return ") && argumentizedString.endsWith(";\n")) {
argumentizedString = argumentizedString.substring("return ".length(),
argumentizedString.lastIndexOf(";\n"));
}
}
return argumentizedString;
}
private static class ReplacementInfo {
private String argumentizedString1;
private String argumentizedString2;
private int rawDistance;
private Set replacements;
private List extends AbstractCodeFragment> statements1;
private List extends AbstractCodeFragment> statements2;
public ReplacementInfo(String argumentizedString1, String argumentizedString2,
List extends AbstractCodeFragment> statements1, List extends AbstractCodeFragment> statements2) {
this.argumentizedString1 = argumentizedString1;
this.argumentizedString2 = argumentizedString2;
this.statements1 = statements1;
this.statements2 = statements2;
this.rawDistance = StringDistance.editDistance(argumentizedString1, argumentizedString2);
this.replacements = new LinkedHashSet();
}
public String getArgumentizedString1() {
return argumentizedString1;
}
public String getArgumentizedString2() {
return argumentizedString2;
}
public void setArgumentizedString1(String string) {
this.argumentizedString1 = string;
this.rawDistance = StringDistance.editDistance(this.argumentizedString1, this.argumentizedString2);
}
public int getRawDistance() {
return rawDistance;
}
public void addReplacement(Replacement r) {
this.replacements.add(r);
}
public void addReplacements(Set replacementsToBeAdded) {
this.replacements.addAll(replacementsToBeAdded);
}
public void removeReplacements(Set replacementsToBeRemoved) {
this.replacements.removeAll(replacementsToBeRemoved);
}
public Set getReplacements() {
return replacements;
}
public List getReplacements(ReplacementType type) {
List replacements = new ArrayList();
for(Replacement replacement : this.replacements) {
if(replacement.getType().equals(type)) {
replacements.add(replacement);
}
}
return replacements;
}
}
private boolean nonMatchedStatementUsesVariableInArgument(List extends AbstractCodeFragment> statements, String variable, String otherArgument) {
for(AbstractCodeFragment statement : statements) {
OperationInvocation invocation = statement.invocationCoveringEntireFragment();
if(invocation != null) {
for(String argument : invocation.getArguments()) {
String argumentNoWhiteSpace = argument.replaceAll("\\s","");
if(argument.contains(variable) && !argument.equals(variable) && !argumentNoWhiteSpace.contains("+" + variable + "+") &&
!argumentNoWhiteSpace.contains(variable + "+") && !argumentNoWhiteSpace.contains("+" + variable) && !argument.equals(otherArgument)) {
return true;
}
}
}
}
return false;
}
private Set findReplacementsWithExactMatching(AbstractCodeFragment statement1, AbstractCodeFragment statement2,
Map parameterToArgumentMap, ReplacementInfo replacementInfo) throws RefactoringMinerTimedOutException {
List variableDeclarations1 = new ArrayList(statement1.getVariableDeclarations());
List variableDeclarations2 = new ArrayList(statement2.getVariableDeclarations());
VariableDeclaration variableDeclarationWithArrayInitializer1 = declarationWithArrayInitializer(variableDeclarations1);
VariableDeclaration variableDeclarationWithArrayInitializer2 = declarationWithArrayInitializer(variableDeclarations2);
OperationInvocation invocationCoveringTheEntireStatement1 = statement1.invocationCoveringEntireFragment();
OperationInvocation invocationCoveringTheEntireStatement2 = statement2.invocationCoveringEntireFragment();
Set variables1 = new LinkedHashSet(statement1.getVariables());
Set variables2 = new LinkedHashSet(statement2.getVariables());
Set variableIntersection = new LinkedHashSet(variables1);
variableIntersection.retainAll(variables2);
// ignore the variables in the intersection that also appear with "this." prefix in the sets of variables
// ignore the variables in the intersection that are static fields
Set variablesToBeRemovedFromTheIntersection = new LinkedHashSet();
for(String variable : variableIntersection) {
if(!variable.startsWith("this.") && !variableIntersection.contains("this."+variable) &&
(variables1.contains("this."+variable) || variables2.contains("this."+variable))) {
variablesToBeRemovedFromTheIntersection.add(variable);
}
if(invocationCoveringTheEntireStatement1 != null && invocationCoveringTheEntireStatement2 != null &&
invocationCoveringTheEntireStatement1.identicalName(invocationCoveringTheEntireStatement2)) {
if(!invocationCoveringTheEntireStatement1.getArguments().contains(variable) &&
invocationCoveringTheEntireStatement2.getArguments().contains(variable)) {
for(String argument : invocationCoveringTheEntireStatement1.getArguments()) {
String argumentNoWhiteSpace = argument.replaceAll("\\s","");
if(argument.contains(variable) && !argument.equals(variable) && !argumentNoWhiteSpace.contains("+" + variable + "+") &&
!argumentNoWhiteSpace.contains(variable + "+") && !argumentNoWhiteSpace.contains("+" + variable) &&
!nonMatchedStatementUsesVariableInArgument(replacementInfo.statements1, variable, argument)) {
variablesToBeRemovedFromTheIntersection.add(variable);
}
}
}
else if(invocationCoveringTheEntireStatement1.getArguments().contains(variable) &&
!invocationCoveringTheEntireStatement2.getArguments().contains(variable)) {
for(String argument : invocationCoveringTheEntireStatement2.getArguments()) {
String argumentNoWhiteSpace = argument.replaceAll("\\s","");
if(argument.contains(variable) && !argument.equals(variable) && !argumentNoWhiteSpace.contains("+" + variable + "+") &&
!argumentNoWhiteSpace.contains(variable + "+") && !argumentNoWhiteSpace.contains("+" + variable) &&
!nonMatchedStatementUsesVariableInArgument(replacementInfo.statements2, variable, argument)) {
variablesToBeRemovedFromTheIntersection.add(variable);
}
}
}
}
if(variable.toUpperCase().equals(variable) && !ReplacementUtil.sameCharsBeforeAfter(statement1.getString(), statement2.getString(), variable)) {
variablesToBeRemovedFromTheIntersection.add(variable);
}
}
variableIntersection.removeAll(variablesToBeRemovedFromTheIntersection);
// remove common variables from the two sets
variables1.removeAll(variableIntersection);
variables2.removeAll(variableIntersection);
// replace variables with the corresponding arguments
replaceVariablesWithArguments(variables1, parameterToArgumentMap);
replaceVariablesWithArguments(variables2, parameterToArgumentMap);
Map> methodInvocationMap1 = new LinkedHashMap>(statement1.getMethodInvocationMap());
Map> methodInvocationMap2 = new LinkedHashMap>(statement2.getMethodInvocationMap());
Set methodInvocations1 = new LinkedHashSet(methodInvocationMap1.keySet());
Set methodInvocations2 = new LinkedHashSet(methodInvocationMap2.keySet());
Map> creationMap1 = new LinkedHashMap>(statement1.getCreationMap());
Map> creationMap2 = new LinkedHashMap>(statement2.getCreationMap());
Set creations1 = new LinkedHashSet(creationMap1.keySet());
Set creations2 = new LinkedHashSet(creationMap2.keySet());
Set arguments1 = new LinkedHashSet(statement1.getArguments());
Set