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.UMLClass;
import gr.uom.java.xmi.UMLComment;
import gr.uom.java.xmi.UMLInitializer;
import gr.uom.java.xmi.UMLOperation;
import gr.uom.java.xmi.UMLParameter;
import gr.uom.java.xmi.VariableDeclarationContainer;
import gr.uom.java.xmi.ListCompositeType;
import gr.uom.java.xmi.LocationInfo.CodeElementType;
import gr.uom.java.xmi.UMLAnnotation;
import static gr.uom.java.xmi.Constants.JAVA;
import static gr.uom.java.xmi.UMLModelASTReader.processBlock;
import static gr.uom.java.xmi.decomposition.ReplacementAlgorithm.findReplacementsWithExactMatching;
import static gr.uom.java.xmi.decomposition.ReplacementAlgorithm.processLambdas;
import static gr.uom.java.xmi.decomposition.ReplacementAlgorithm.streamAPICalls;
import static gr.uom.java.xmi.decomposition.ReplacementAlgorithm.streamAPIName;
import static gr.uom.java.xmi.decomposition.StringBasedHeuristics.*;
import static gr.uom.java.xmi.decomposition.Visitor.stringify;
import gr.uom.java.xmi.decomposition.replacement.CompositeReplacement;
import gr.uom.java.xmi.decomposition.replacement.IntersectionReplacement;
import gr.uom.java.xmi.decomposition.replacement.MethodInvocationReplacement;
import gr.uom.java.xmi.decomposition.replacement.Replacement;
import gr.uom.java.xmi.decomposition.replacement.Replacement.ReplacementType;
import gr.uom.java.xmi.diff.UMLAnonymousClassDiff;
import gr.uom.java.xmi.diff.AddParameterRefactoring;
import gr.uom.java.xmi.diff.AssertThrowsRefactoring;
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.ExtractOperationDetection;
import gr.uom.java.xmi.diff.ExtractOperationRefactoring;
import gr.uom.java.xmi.diff.ExtractVariableRefactoring;
import gr.uom.java.xmi.diff.InlineOperationRefactoring;
import gr.uom.java.xmi.diff.InlineVariableRefactoring;
import gr.uom.java.xmi.diff.InvertConditionRefactoring;
import gr.uom.java.xmi.diff.LeafMappingProvider;
import gr.uom.java.xmi.diff.MergeCatchRefactoring;
import gr.uom.java.xmi.diff.MergeConditionalRefactoring;
import gr.uom.java.xmi.diff.MergeVariableRefactoring;
import gr.uom.java.xmi.diff.ReferenceBasedRefactoring;
import gr.uom.java.xmi.diff.RemoveParameterRefactoring;
import gr.uom.java.xmi.diff.ReplaceAnonymousWithLambdaRefactoring;
import gr.uom.java.xmi.diff.ReplaceLoopWithPipelineRefactoring;
import gr.uom.java.xmi.diff.ReplacePipelineWithLoopRefactoring;
import gr.uom.java.xmi.diff.SplitConditionalRefactoring;
import gr.uom.java.xmi.diff.SplitVariableRefactoring;
import gr.uom.java.xmi.diff.StringDistance;
import gr.uom.java.xmi.diff.UMLAbstractClassDiff;
import gr.uom.java.xmi.diff.UMLClassMoveDiff;
import gr.uom.java.xmi.diff.UMLCommentListDiff;
import gr.uom.java.xmi.diff.UMLDocumentationDiffProvider;
import gr.uom.java.xmi.diff.UMLJavadocDiff;
import gr.uom.java.xmi.diff.UMLModelDiff;
import gr.uom.java.xmi.diff.UMLOperationDiff;
import gr.uom.java.xmi.diff.UMLParameterDiff;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
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.Map.Entry;
import java.util.Optional;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.stream.Collectors;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.commons.lang3.tuple.Triple;
import org.eclipse.jdt.core.dom.ASTNode;
import org.refactoringminer.api.Refactoring;
import org.refactoringminer.api.RefactoringMinerTimedOutException;
import org.refactoringminer.api.RefactoringType;
import org.refactoringminer.util.PrefixSuffixUtils;
public class UMLOperationBodyMapper implements Comparable, UMLDocumentationDiffProvider {
private VariableDeclarationContainer container1;
private VariableDeclarationContainer container2;
private Set mappings;
private List nonMappedLeavesT1;
private List nonMappedLeavesT2;
private List nonMappedInnerNodesT1;
private List nonMappedInnerNodesT2;
private Set mappingHashcodesT1 = new HashSet();
private Set mappingHashcodesT2 = new HashSet();
private Set refactorings = new LinkedHashSet();
private Set> matchedVariables = new LinkedHashSet<>();
private Set candidateAttributeRenames = new LinkedHashSet();
private Set candidateAttributeMerges = new LinkedHashSet();
private Set candidateAttributeSplits = new LinkedHashSet();
private Set anonymousClassDiffs = new LinkedHashSet();
private Set childMappers = new LinkedHashSet();
private UMLOperationBodyMapper parentMapper;
private static final int MAXIMUM_NUMBER_OF_COMPARED_STATEMENTS = 1500;
private UMLOperationDiff operationSignatureDiff;
private UMLAbstractClassDiff classDiff;
private UMLModelDiff modelDiff;
private VariableDeclarationContainer callSiteOperation;
private Map codeFragmentOperationMap1 = new LinkedHashMap();
private Map codeFragmentOperationMap2 = new LinkedHashMap();
private Set removedVariables;
private Set addedVariables;
private Set> movedVariables;
private int callsToExtractedMethod = 0;
private boolean nested;
private boolean lambdaBodyMapper;
private AbstractCall operationInvocation;
private Map parameterToArgumentMap1;
private Map parameterToArgumentMap2;
private Set ifBecomingElseIf = new HashSet<>();
private Set ifAddingElseIf = new HashSet<>();
private Map> extractedStatements = new LinkedHashMap<>();
private List invocationsInSourceOperationAfterExtraction;
private Optional javadocDiff = Optional.empty();
private UMLCommentListDiff commentListDiff;
private Set> commentedCode = new LinkedHashSet<>();
private Set> unCommentedCode = new LinkedHashSet<>();
public List getInvocationsInSourceOperationAfterExtraction() {
if(invocationsInSourceOperationAfterExtraction == null) {
this.invocationsInSourceOperationAfterExtraction = ExtractOperationDetection.getInvocationsInSourceOperationAfterExtraction(this);
}
return invocationsInSourceOperationAfterExtraction;
}
public boolean isNested() {
return nested;
}
private Set statementsWithStreamAPICalls(List leaves) {
Set streamAPICalls = new LinkedHashSet();
for(AbstractCodeFragment statement : leaves) {
AbstractCall invocation = statement.invocationCoveringEntireFragment();
if(invocation == null) {
invocation = statement.assignmentInvocationCoveringEntireStatement();
}
if(invocation != null && (invocation.actualString().contains(JAVA.LAMBDA_ARROW) ||
invocation.actualString().contains(JAVA.METHOD_REFERENCE))) {
for(AbstractCall inv : statement.getMethodInvocations()) {
if(streamAPIName(inv.getName())) {
streamAPICalls.add(statement);
break;
}
}
}
}
return streamAPICalls;
}
//Mappers for Move Code
public UMLOperationBodyMapper(UMLOperationBodyMapper mapper1, UMLOperationBodyMapper mapper2, UMLAbstractClassDiff classDiff) throws RefactoringMinerTimedOutException {
this.classDiff = classDiff;
this.modelDiff = classDiff != null ? classDiff.getModelDiff() : null;
this.container1 = mapper1.getContainer1();
this.container2 = mapper2.getContainer2();
this.mappings = new LinkedHashSet();
this.nonMappedLeavesT1 = new ArrayList();
this.nonMappedLeavesT2 = new ArrayList();
this.nonMappedInnerNodesT1 = new ArrayList();
this.nonMappedInnerNodesT2 = new ArrayList();
List leaves1 = new ArrayList<>(mapper1.getNonMappedLeavesT1());
List leaves2 = new ArrayList<>(mapper2.getNonMappedLeavesT2());
List innerNodes1 = new ArrayList<>(mapper1.getNonMappedInnerNodesT1());
List innerNodes2 = new ArrayList<>(mapper2.getNonMappedInnerNodesT2());
resetNodes(leaves1);
resetNodes(leaves2);
processLeaves(leaves1, leaves2, new LinkedHashMap(), false);
resetNodes(innerNodes1);
resetNodes(innerNodes2);
processInnerNodes(innerNodes1, innerNodes2, leaves1, leaves2, new LinkedHashMap(), false);
nonMappedLeavesT1.addAll(leaves1);
nonMappedLeavesT2.addAll(leaves2);
nonMappedInnerNodesT1.addAll(innerNodes1);
nonMappedInnerNodesT2.addAll(innerNodes2);
if(mapper1.commentListDiff != null && mapper2.commentListDiff != null) {
this.commentListDiff = new UMLCommentListDiff(mapper1.commentListDiff.getDeletedComments(), mapper2.commentListDiff.getAddedComments());
checkUnmatchedStatementsBeingCommented();
}
}
public UMLOperationBodyMapper(UMLOperation removedOperation, UMLOperationBodyMapper mapper2, UMLAbstractClassDiff classDiff) throws RefactoringMinerTimedOutException {
this.classDiff = classDiff;
this.modelDiff = classDiff != null ? classDiff.getModelDiff() : null;
this.container1 = removedOperation;
this.container2 = mapper2.getContainer2();
this.mappings = new LinkedHashSet();
this.nonMappedLeavesT1 = new ArrayList();
this.nonMappedLeavesT2 = new ArrayList();
this.nonMappedInnerNodesT1 = new ArrayList();
this.nonMappedInnerNodesT2 = new ArrayList();
OperationBody body1 = removedOperation.getBody();
if(body1 != null) {
List leaves1 = new ArrayList<>(body1.getCompositeStatement().getLeaves());
List leaves2 = new ArrayList<>(mapper2.getNonMappedLeavesT2());
List innerNodes1 = new ArrayList<>(body1.getCompositeStatement().getInnerNodes());
List innerNodes2 = new ArrayList<>(mapper2.getNonMappedInnerNodesT2());
resetNodes(leaves1);
resetNodes(leaves2);
processLeaves(leaves1, leaves2, new LinkedHashMap(), false);
resetNodes(innerNodes1);
resetNodes(innerNodes2);
processInnerNodes(innerNodes1, innerNodes2, leaves1, leaves2, new LinkedHashMap(), false);
nonMappedLeavesT1.addAll(leaves1);
nonMappedLeavesT2.addAll(leaves2);
nonMappedInnerNodesT1.addAll(innerNodes1);
nonMappedInnerNodesT2.addAll(innerNodes2);
if(mapper2.commentListDiff != null) {
this.commentListDiff = new UMLCommentListDiff(container1.getComments(), mapper2.commentListDiff.getAddedComments());
checkUnmatchedStatementsBeingCommented();
}
}
}
public UMLOperationBodyMapper(UMLOperationBodyMapper mapper1, UMLOperation addedOperation, UMLAbstractClassDiff classDiff) throws RefactoringMinerTimedOutException {
this.classDiff = classDiff;
this.modelDiff = classDiff != null ? classDiff.getModelDiff() : null;
this.container1 = mapper1.getContainer1();
this.container2 = addedOperation;
this.mappings = new LinkedHashSet();
this.nonMappedLeavesT1 = new ArrayList();
this.nonMappedLeavesT2 = new ArrayList();
this.nonMappedInnerNodesT1 = new ArrayList();
this.nonMappedInnerNodesT2 = new ArrayList();
OperationBody body2 = addedOperation.getBody();
if(body2 != null) {
List leaves1 = new ArrayList<>(mapper1.getNonMappedLeavesT1());
List leaves2 = new ArrayList<>(body2.getCompositeStatement().getLeaves());
List innerNodes1 = new ArrayList<>(mapper1.getNonMappedInnerNodesT1());
List innerNodes2 = new ArrayList<>(body2.getCompositeStatement().getInnerNodes());
resetNodes(leaves1);
resetNodes(leaves2);
processLeaves(leaves1, leaves2, new LinkedHashMap(), false);
resetNodes(innerNodes1);
resetNodes(innerNodes2);
processInnerNodes(innerNodes1, innerNodes2, leaves1, leaves2, new LinkedHashMap(), false);
nonMappedLeavesT1.addAll(leaves1);
nonMappedLeavesT2.addAll(leaves2);
nonMappedInnerNodesT1.addAll(innerNodes1);
nonMappedInnerNodesT2.addAll(innerNodes2);
if(mapper1.commentListDiff != null) {
this.commentListDiff = new UMLCommentListDiff(mapper1.commentListDiff.getDeletedComments(), container2.getComments());
checkUnmatchedStatementsBeingCommented();
}
}
}
public UMLOperationBodyMapper(UMLOperation operation1, UMLOperation operation2, UMLAbstractClassDiff classDiff) throws RefactoringMinerTimedOutException {
this.classDiff = classDiff;
this.modelDiff = classDiff != null ? classDiff.getModelDiff() : null;
this.container1 = operation1;
this.container2 = operation2;
this.mappings = new LinkedHashSet();
this.nonMappedLeavesT1 = new ArrayList();
this.nonMappedLeavesT2 = new ArrayList();
this.nonMappedInnerNodesT1 = new ArrayList();
this.nonMappedInnerNodesT2 = new ArrayList();
this.operationSignatureDiff = new UMLOperationDiff(operation1, operation2, classDiff);
OperationBody body1 = operation1.getBody();
OperationBody body2 = operation2.getBody();
if(body1 != null && body2 != null) {
if(classDiff != null) {
List list1 = body1.stringRepresentation();
for(UMLOperation addedOperation : classDiff.getAddedOperations()) {
if(addedOperation.getBody() != null) {
List list2 = new ArrayList<>(addedOperation.getBody().stringRepresentation());
if(list2.size() > 3) {
//remove first and last blocks
list2.remove(0);
list2.remove(list2.size()-1);
int indexOfSubList = Collections.indexOfSubList(list1, list2);
if(indexOfSubList >= 0) {
while(list2.contains("}")) {
list2.remove("}");
}
List allStatements = body1.getCompositeStatement().getAllStatements();
Set subSet = new LinkedHashSet();
boolean firstFound = false;
int index = 0;
for(AbstractStatement statement1 : allStatements) {
if(index == list2.size()) {
firstFound = false;
index = 0;
}
if(!firstFound) {
if(statement1 instanceof CompositeStatementObject) {
CompositeStatementObject comp1 = (CompositeStatementObject)statement1;
if(comp1.toStringForStringRepresentation().equals(list1.get(indexOfSubList))) {
firstFound = true;
subSet.add(statement1);
index++;
}
}
else if(statement1.getString().equals(list1.get(indexOfSubList))) {
firstFound = true;
subSet.add(statement1);
index++;
}
}
else {
if(statement1 instanceof CompositeStatementObject) {
CompositeStatementObject comp1 = (CompositeStatementObject)statement1;
if(comp1.toStringForStringRepresentation().equals(list2.get(index))) {
subSet.add(statement1);
}
}
else if(statement1.getString().equals(list2.get(index))) {
subSet.add(statement1);
}
index++;
}
}
extractedStatements.put(addedOperation, subSet);
}
else if(list1.containsAll(list2) && list2.size() >= 10) {
while(list2.contains("}")) {
list2.remove("}");
}
List allStatements = body1.getCompositeStatement().getAllStatements();
Set subSet = new LinkedHashSet();
boolean firstFound = false;
int index = 0;
for(AbstractStatement statement1 : allStatements) {
if(statement1.isLastStatementWithReturn()) {
break;
}
if(!firstFound) {
if(statement1 instanceof CompositeStatementObject) {
CompositeStatementObject comp1 = (CompositeStatementObject)statement1;
if(comp1.toStringForStringRepresentation().equals(list2.get(0))) {
firstFound = true;
subSet.add(statement1);
index++;
}
}
else if(statement1.getString().equals(list2.get(0))) {
firstFound = true;
subSet.add(statement1);
index++;
}
}
else if(index < list2.size()) {
if(statement1 instanceof CompositeStatementObject) {
CompositeStatementObject comp1 = (CompositeStatementObject)statement1;
if(comp1.toStringForStringRepresentation().equals(list2.get(index))) {
subSet.add(statement1);
index++;
}
}
else if(statement1.getString().equals(list2.get(index))) {
subSet.add(statement1);
index++;
}
else {
int tmpIndex = index + 1;
//skip statements in extracted method
for(int i=tmpIndex; i anonymous1 = body1.getAllAnonymousClassDeclarations();
List nestedAnonymous1 = new ArrayList();
for(AnonymousClassDeclarationObject anonymous : anonymous1) {
nestedAnonymous1.addAll(anonymous.getAnonymousClassDeclarationsRecursively());
}
List anonymous2 = body2.getAllAnonymousClassDeclarations();
List nestedAnonymous2 = new ArrayList();
for(AnonymousClassDeclarationObject anonymous : anonymous2) {
nestedAnonymous2.addAll(anonymous.getAnonymousClassDeclarationsRecursively());
}
List lambdas1 = body1.getAllLambdas();
List nestedLambdas1 = new ArrayList<>();
int lambdasWithBody1 = 0;
int lambdasWithExpression1 = 0;
for(LambdaExpressionObject lambda1 : lambdas1) {
if(lambda1.getBody() != null)
lambdasWithBody1++;
if(lambda1.getExpression() != null)
lambdasWithExpression1++;
collectNestedLambdaExpressions(lambda1, nestedLambdas1);
}
List lambdas2 = body2.getAllLambdas();
List nestedLambdas2 = new ArrayList<>();
int lambdasWithBody2 = 0;
int lambdasWithExpression2 = 0;
for(LambdaExpressionObject lambda2 : lambdas2) {
if(lambda2.getBody() != null)
lambdasWithBody2++;
if(lambda2.getExpression() != null)
lambdasWithExpression2++;
collectNestedLambdaExpressions(lambda2, nestedLambdas2);
}
CompositeStatementObject composite1 = body1.getCompositeStatement();
CompositeStatementObject composite2 = body2.getCompositeStatement();
List leaves1 = composite1.getLeaves();
List leaves2 = composite2.getLeaves();
List innerNodes1 = composite1.getInnerNodes();
innerNodes1.remove(composite1);
List innerNodes2 = composite2.getInnerNodes();
innerNodes2.remove(composite2);
int totalNodes1 = leaves1.size() + innerNodes1.size();
int totalNodes2 = leaves2.size() + innerNodes2.size();
int assertThrows1 = 0;
for(AbstractCall call : container1.getAllOperationInvocations()) {
if(call.getName().equals("assertThrows")) {
assertThrows1++;
}
}
int assertThrows2 = 0;
for(AbstractCall call : container2.getAllOperationInvocations()) {
if(call.getName().equals("assertThrows")) {
assertThrows2++;
}
}
boolean anonymousCollapse = Math.abs(totalNodes1 - totalNodes2) > 2*Math.min(totalNodes1, totalNodes2);
if(!operation1.isDeclaredInAnonymousClass() && !operation2.isDeclaredInAnonymousClass() && anonymousCollapse) {
if((anonymous1.size() == 1 && anonymous2.size() == 0) ||
(anonymous1.size() == 1 && anonymous2.size() == 1 && anonymous1.get(0).getAnonymousClassDeclarations().size() > 0 && anonymous2.get(0).getAnonymousClassDeclarations().size() == 0) ||
(anonymous1.size() + nestedAnonymous1.size() == anonymous2.size() + nestedAnonymous2.size() + 1 && anonymous1.get(0).getAnonymousClassDeclarations().size() > 0)) {
AbstractCodeFragment anonymousFragment = null;
for(AbstractCodeFragment leaf1 : leaves1) {
if(leaf1.getAnonymousClassDeclarations().size() > 0) {
anonymousFragment = leaf1;
break;
}
}
if(anonymousFragment != null) {
expandAnonymousAndLambdas(anonymousFragment, leaves1, innerNodes1, new LinkedHashSet<>(), new LinkedHashSet<>(), anonymousClassList1(), codeFragmentOperationMap1, operation1, true);
}
}
else if(lambdas1.size() == 1 && anonymous2.size() == 0 && lambdas2.size() == 0) {
AbstractCodeFragment lambdaFragment = null;
for(AbstractCodeFragment leaf1 : leaves1) {
if(leaf1.getLambdas().size() > 0) {
lambdaFragment = leaf1;
break;
}
}
if(lambdaFragment != null) {
expandAnonymousAndLambdas(lambdaFragment, leaves1, innerNodes1, new LinkedHashSet<>(), new LinkedHashSet<>(), anonymousClassList1(), codeFragmentOperationMap1, operation1, true);
}
}
else if((anonymous1.size() == 0 && anonymous2.size() == 1) ||
(anonymous1.size() == 1 && anonymous2.size() == 1 && anonymous1.get(0).getAnonymousClassDeclarations().size() == 0 && anonymous2.get(0).getAnonymousClassDeclarations().size() > 0) ||
(anonymous1.size() + nestedAnonymous1.size() + 1 == anonymous2.size() + nestedAnonymous2.size() && anonymous2.get(0).getAnonymousClassDeclarations().size() > 0)) {
AbstractCodeFragment anonymousFragment = null;
for(AbstractCodeFragment leaf2 : leaves2) {
if(leaf2.getAnonymousClassDeclarations().size() > 0) {
anonymousFragment = leaf2;
break;
}
}
if(anonymousFragment != null) {
expandAnonymousAndLambdas(anonymousFragment, leaves2, innerNodes2, new LinkedHashSet<>(), new LinkedHashSet<>(), anonymousClassList2(), codeFragmentOperationMap2, operation2, true);
}
}
else if(anonymous1.size() == 0 && lambdas1.size() == 0 && lambdas2.size() == 1) {
AbstractCodeFragment lambdaFragment = null;
for(AbstractCodeFragment leaf2 : leaves2) {
if(leaf2.getLambdas().size() > 0) {
lambdaFragment = leaf2;
break;
}
}
if(lambdaFragment != null) {
expandAnonymousAndLambdas(lambdaFragment, leaves2, innerNodes2, new LinkedHashSet<>(), new LinkedHashSet<>(), anonymousClassList2(), codeFragmentOperationMap2, operation2, true);
}
}
else if (assertThrows1 == 0 && assertThrows2 > 0) {
handleAssertThrowsLambda(leaves1, leaves2, innerNodes2, lambdas2, operation2);
}
}
else if(operation1.hasTestAnnotation() && operation2.hasTestAnnotation() && assertThrows2 > 0 &&
(lambdas2.size() + nestedLambdas2.size() == lambdas1.size() + nestedLambdas1.size() + assertThrows2 ||
lambdas2.size() == lambdas1.size() + assertThrows2 || assertThrows1 == 0)) {
handleAssertThrowsLambda(leaves1, leaves2, innerNodes2, lambdas2, operation2);
}
Set streamAPIStatements1 = statementsWithStreamAPICalls(leaves1);
Set streamAPIStatements2 = statementsWithStreamAPICalls(leaves2);
if(streamAPIStatements1.size() == 0 && streamAPIStatements2.size() > 0) {
for(AbstractCodeFragment streamAPICall : streamAPIStatements2) {
if(streamAPICall.getLambdas().size() > 0) {
expandAnonymousAndLambdas(streamAPICall, leaves2, innerNodes2, new LinkedHashSet<>(), new LinkedHashSet<>(), anonymousClassList2(), codeFragmentOperationMap2, operation2, false);
}
}
for(AbstractCodeFragment leaf1 : new ArrayList<>(leaves1)) {
if(leaf1.getLambdas().size() > 0) {
expandAnonymousAndLambdas(leaf1, leaves1, innerNodes1, new LinkedHashSet<>(), new LinkedHashSet<>(), anonymousClassList1(), codeFragmentOperationMap1, operation1, true);
}
}
}
else if(streamAPIStatements1.size() > 0 && streamAPIStatements2.size() == 0) {
for(AbstractCodeFragment streamAPICall : streamAPIStatements1) {
if(streamAPICall.getLambdas().size() > 0) {
expandAnonymousAndLambdas(streamAPICall, leaves1, innerNodes1, new LinkedHashSet<>(), new LinkedHashSet<>(), anonymousClassList1(), codeFragmentOperationMap1, operation1, false);
}
}
for(AbstractCodeFragment leaf2 : new ArrayList<>(leaves2)) {
if(leaf2.getLambdas().size() > 0) {
expandAnonymousAndLambdas(leaf2, leaves2, innerNodes2, new LinkedHashSet<>(), new LinkedHashSet<>(), anonymousClassList2(), codeFragmentOperationMap2, operation2, true);
}
}
}
if(lambdas1.size() == lambdas2.size() && lambdasWithBody1 != lambdasWithBody2) {
for(AbstractCodeFragment leaf1 : new ArrayList<>(leaves1)) {
if(leaf1.getLambdas().size() > 0) {
expandAnonymousAndLambdas(leaf1, leaves1, innerNodes1, new LinkedHashSet<>(), new LinkedHashSet<>(), anonymousClassList1(), codeFragmentOperationMap1, operation1, true);
}
}
for(AbstractCodeFragment leaf2 : new ArrayList<>(leaves2)) {
if(leaf2.getLambdas().size() > 0) {
expandAnonymousAndLambdas(leaf2, leaves2, innerNodes2, new LinkedHashSet<>(), new LinkedHashSet<>(), anonymousClassList2(), codeFragmentOperationMap2, operation2, true);
}
}
}
Map parameterToArgumentMap1 = new LinkedHashMap();
Map parameterToArgumentMap2 = new LinkedHashMap();
List addedParameters = operationSignatureDiff.getAddedParameters();
if(addedParameters.size() == 1) {
UMLParameter addedParameter = addedParameters.get(0);
if(!operation1.isDeclaredInAnonymousClass() && UMLModelDiff.looksLikeSameType(addedParameter.getType().getClassType(), operation1.getClassName())) {
parameterToArgumentMap1.put(JAVA.THIS_DOT, "");
//replace "parameterName." with ""
parameterToArgumentMap2.put(addedParameter.getName() + ".", "");
}
}
List removedParameters = operationSignatureDiff.getRemovedParameters();
if(removedParameters.size() == 1) {
UMLParameter removedParameter = removedParameters.get(0);
if(!operation2.isDeclaredInAnonymousClass() && UMLModelDiff.looksLikeSameType(removedParameter.getType().getClassType(), operation2.getClassName())) {
parameterToArgumentMap1.put(removedParameter.getName() + ".", "");
parameterToArgumentMap2.put(JAVA.THIS_DOT, "");
}
}
List parameterDiffList = operationSignatureDiff.getParameterDiffList();
for(UMLParameterDiff parameterDiff : parameterDiffList) {
UMLParameter addedParameter = parameterDiff.getAddedParameter();
UMLParameter removedParameter = parameterDiff.getRemovedParameter();
if(!operation1.isDeclaredInAnonymousClass() && !operation2.isDeclaredInAnonymousClass() &&
UMLModelDiff.looksLikeSameType(addedParameter.getType().getClassType(), operation1.getClassName()) &&
UMLModelDiff.looksLikeSameType(removedParameter.getType().getClassType(), operation2.getClassName())) {
parameterToArgumentMap1.put(JAVA.THIS_DOT, "");
parameterToArgumentMap2.put(addedParameter.getName() + ".", "");
parameterToArgumentMap1.put(removedParameter.getName() + ".", "");
parameterToArgumentMap2.put(JAVA.THIS_DOT, "");
}
}
if(classDiff != null) {
for(UMLAttribute attribute : classDiff.getOriginalClass().getAttributes()) {
if(!operation2.isDeclaredInAnonymousClass() && UMLModelDiff.looksLikeSameType(attribute.getType().getClassType(), operation2.getClassName())) {
parameterToArgumentMap1.put(attribute.getName() + ".", "");
parameterToArgumentMap2.put(JAVA.THIS_DOT, "");
}
}
}
resetNodes(leaves1);
//replace parameters with arguments in leaves1
if(!parameterToArgumentMap1.isEmpty()) {
for(AbstractCodeFragment leave1 : leaves1) {
leave1.replaceParametersWithArguments(parameterToArgumentMap1);
}
}
resetNodes(leaves2);
//replace parameters with arguments in leaves2
if(!parameterToArgumentMap2.isEmpty()) {
for(AbstractCodeFragment leave2 : leaves2) {
leave2.replaceParametersWithArguments(parameterToArgumentMap2);
}
}
boolean isomorphic = isomorphicCompositeStructure(innerNodes1, innerNodes2);
processLeaves(leaves1, leaves2, new LinkedHashMap(), isomorphic);
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);
}
}
boolean containsCallToExtractedMethod = containsCallToExtractedMethod(leaves2);
processInnerNodes(innerNodes1, innerNodes2, leaves1, leaves2, new LinkedHashMap(), containsCallToExtractedMethod);
if(streamAPIStatements1.size() == 0 && streamAPIStatements2.size() > 0) {
processStreamAPIStatements(leaves1, leaves2, innerNodes1, streamAPIStatements2);
}
else if(streamAPIStatements1.size() > 0 && streamAPIStatements2.size() == 0) {
processStreamAPIStatements(leaves1, leaves2, streamAPIStatements1, innerNodes2);
}
for(Refactoring r : this.refactorings) {
if(r instanceof ReplaceLoopWithPipelineRefactoring) {
ReplaceLoopWithPipelineRefactoring refactoring = (ReplaceLoopWithPipelineRefactoring)r;
CompositeStatementObject parent1 = null;
for(AbstractCodeFragment fragment : refactoring.getCodeFragmentsBefore()) {
if(fragment.getLocationInfo().getCodeElementType().equals(CodeElementType.FOR_STATEMENT) ||
fragment.getLocationInfo().getCodeElementType().equals(CodeElementType.ENHANCED_FOR_STATEMENT) ||
fragment.getLocationInfo().getCodeElementType().equals(CodeElementType.WHILE_STATEMENT) ||
fragment.getLocationInfo().getCodeElementType().equals(CodeElementType.DO_STATEMENT)) {
parent1 = fragment.getParent();
break;
}
}
CompositeStatementObject parent2 = null;
for(AbstractCodeFragment fragment : refactoring.getCodeFragmentsAfter()) {
parent2 = fragment.getParent();
break;
}
if(parent1 != null && parent2 != null && parent1.getParent() != null && parent2.getParent() != null) {
boolean parentMappingFound = false;
for(AbstractCodeMapping mapping : this.mappings) {
if(mapping.getFragment1().equals(parent1) && mapping.getFragment2().equals(parent2)) {
parentMappingFound = true;
}
}
if(!parentMappingFound) {
List nodes1 = new ArrayList<>();
while(parent1.getParent() != null) {
if(innerNodes1.contains(parent1)) {
nodes1.add(parent1);
}
parent1 = parent1.getParent();
}
List nodes2 = new ArrayList<>();
while(parent2.getParent() != null) {
if(innerNodes2.contains(parent2)) {
nodes2.add(parent2);
}
parent2 = parent2.getParent();
}
processInnerNodes(nodes1, nodes2, leaves1, leaves2, new LinkedHashMap(), false);
}
}
}
}
//match expressions in inner nodes from T1 with leaves from T2
List expressionsT1 = new ArrayList();
int remainingUnmatchedIfStatements1 = 0;
for(CompositeStatementObject composite : innerNodes1) {
if(!nonMappedCompositeExistsIdenticalInExtractedMethod(composite)) {
if(composite.getLocationInfo().getCodeElementType().equals(CodeElementType.IF_STATEMENT)) {
remainingUnmatchedIfStatements1++;
}
for(AbstractExpression expression : composite.getExpressions()) {
expression.replaceParametersWithArguments(parameterToArgumentMap1);
expressionsT1.add(expression);
}
}
}
for(AbstractCodeMapping mapping : mappings) {
if(mapping instanceof CompositeStatementObjectMapping && !mapping.getFragment1().equalFragment(mapping.getFragment2()) && !mapping.isIdenticalWithExtractedVariable() && !mapping.isIdenticalWithInlinedVariable()) {
CompositeStatementObject composite = (CompositeStatementObject)mapping.getFragment1();
for(AbstractExpression expression : composite.getExpressions()) {
if(expression.getLocationInfo().getCodeElementType().equals(CodeElementType.ENHANCED_FOR_STATEMENT_PARAMETER_NAME) &&
mapping.getFragment1().getVariableDeclarations().toString().equals(mapping.getFragment2().getVariableDeclarations().toString())) {
continue;
}
AbstractCall call1 = expression.invocationCoveringEntireFragment();
if(call1 != null) {
CompositeStatementObject comp2 = (CompositeStatementObject)mapping.getFragment2();
if(comp2.getExpressions().size() == 1) {
AbstractExpression expression2 = comp2.getExpressions().get(0);
AbstractCall call2 = expression2.invocationCoveringEntireFragment();
if(call2 != null && call1.identicalExpression(call2) && (call1.equalArguments(call2) ||
call1.identicalOrReplacedArguments(call2, mapping.getReplacements(), Collections.emptyList()))) {
continue;
}
}
}
expression.replaceParametersWithArguments(parameterToArgumentMap1);
expressionsT1.add(expression);
}
}
if(remainingUnmatchedIfStatements1 > 0 && mapping instanceof LeafMapping && mapping.getFragment1().getTernaryOperatorExpressions().size() == 0 &&
(mapping.getFragment2().getTernaryOperatorExpressions().size() > 0 || mapping.getFragment2().getString().contains(" == ") || mapping.getFragment2().getString().contains(" != ")) &&
!leaves2.contains(mapping.getFragment2())) {
leaves2.add(mapping.getFragment2());
//remove from hashCodes, so that it can be re-matched
mappingHashcodesT2.remove(mapping.getFragment2().hashCode());
}
}
int numberOfMappings = mappings.size();
processLeaves(expressionsT1, leaves2, parameterToArgumentMap2, false);
List mappings = new ArrayList<>(this.mappings);
for(int i = numberOfMappings; i < mappings.size(); i++) {
if(!isSplitConditionalExpression(mappings.get(i))) {
mappings.get(i).temporaryVariableAssignment(refactorings, leaves2, parentMapper != null);
}
else {
this.mappings.remove(mappings.get(i));
}
}
if(container1.getBodyHashCode() != container2.getBodyHashCode() && containsCallToExtractedMethod) {
for(Iterator mappingIterator = this.mappings.iterator(); mappingIterator.hasNext();) {
AbstractCodeMapping mapping = mappingIterator.next();
boolean ifChangedToElseIf = false;
if(ifBecomingElseIf.contains(mapping)) {
int mappedChildrenSize = 0;
for(AbstractCodeMapping m : this.mappings) {
if(!mapping.equals(m) && !m.getFragment1().getLocationInfo().getCodeElementType().equals(CodeElementType.BLOCK) &&
mapping.getFragment1().getLocationInfo().subsumes(m.getFragment1().getLocationInfo()) &&
mapping.getFragment2().getLocationInfo().subsumes(m.getFragment2().getLocationInfo())) {
mappedChildrenSize++;
}
}
ifChangedToElseIf = mappedChildrenSize > 0;
}
if(!mapping.containsReplacement(ReplacementType.COMPOSITE) && !nestedUnderSplitConditional(mapping) && !ifChangedToElseIf) {
AbstractCodeFragment child1 = mapping.getFragment1();
AbstractCodeFragment child2 = mapping.getFragment2();
CompositeStatementObject parent1 = child1.getParent();
CompositeStatementObject parent2 = child2.getParent();
boolean unmatchedParent = false;
while(parent1 != null && parent2 != null) {
if(parent1.getParent() == null || parent2.getParent() == null) {
if(parent1 instanceof TryStatementObject) {
break;
}
if(parent2 instanceof TryStatementObject) {
break;
}
if(parent1.getLocationInfo().getCodeElementType().equals(CodeElementType.FINALLY_BLOCK)) {
break;
}
if(parent2.getLocationInfo().getCodeElementType().equals(CodeElementType.FINALLY_BLOCK)) {
break;
}
if(child1.getAnonymousClassDeclarations().size() > 0 && child2.getAnonymousClassDeclarations().size() > 0) {
break;
}
if(parent1.getLocationInfo().getCodeElementType().equals(CodeElementType.BLOCK) != parent2.getLocationInfo().getCodeElementType().equals(CodeElementType.BLOCK)) {
unmatchedParent = true;
}
break;
}
if(alreadyMatched1(parent1) && alreadyMatched2(parent2) &&
!parent1.getLocationInfo().getCodeElementType().equals(CodeElementType.BLOCK) &&
!parent2.getLocationInfo().getCodeElementType().equals(CodeElementType.BLOCK)) {
if(parent1.getString().equals(parent2.getString())) {
break;
}
else if(containsMapping(parent1.getParent(), parent2)) {
break;
}
else if(containsMapping(parent1, parent2.getParent())) {
break;
}
else if(parent2.getStatements().size() > 0 && containsMapping(parent1.getParent(), parent2.getStatements().get(0))) {
break;
}
else if(parent1.getStatements().size() > 0 && containsMapping(parent1.getStatements().get(0), parent2.getParent())) {
break;
}
}
if(!alreadyMatched1(parent1) || !alreadyMatched2(parent2)) {
int indexOfChildInParent1 = parent1.getStatements().indexOf(child1);
int indexOfChildInParent2 = parent2.getStatements().indexOf(child2);
if(indexOfChildInParent1 != indexOfChildInParent2 &&
!isElseBranch(child1, parent1) && !isElseBranch(child2, parent2) &&
!isTryBlock(child1, parent1) && !isTryBlock(child2, parent2) &&
!isFinallyBlock(child1, parent1) && !isFinallyBlock(child2, parent2) &&
!ifAddingElseIf(parent1.getParent()) && !ifAddingElseIf(parent2.getParent())) {
boolean additionalVariableDeclarationStatements = false;
if(indexOfChildInParent1 > indexOfChildInParent2) {
int referencedVariableDeclarationStatements = 0;
for(int i=0; i 0) {
for(LeafExpression variableReference : child1.getVariables()) {
if(statement.getVariableDeclarations().get(0).getVariableName().equals(variableReference.getString())) {
referencedVariableDeclarationStatements++;
break;
}
}
}
}
if(referencedVariableDeclarationStatements == Math.abs(indexOfChildInParent1 - indexOfChildInParent2)) {
additionalVariableDeclarationStatements = true;
}
}
else if(indexOfChildInParent2 > indexOfChildInParent1) {
int referencedVariableDeclarationStatements = 0;
for(int i=0; i 0) {
for(LeafExpression variableReference : child2.getVariables()) {
if(statement.getVariableDeclarations().get(0).getVariableName().equals(variableReference.getString())) {
referencedVariableDeclarationStatements++;
break;
}
}
}
}
if(referencedVariableDeclarationStatements == Math.abs(indexOfChildInParent1 - indexOfChildInParent2)) {
additionalVariableDeclarationStatements = true;
}
}
if(!additionalVariableDeclarationStatements) {
unmatchedParent = true;
}
}
break;
}
child1 = parent1;
child2 = parent2;
parent1 = parent1.getParent();
parent2 = parent2.getParent();
}
if(unmatchedParent) {
mappingIterator.remove();
if(mapping instanceof LeafMapping) {
LeafMapping leafMapping = (LeafMapping)mapping;
leaves1.add(leafMapping.getFragment1());
leaves2.add(leafMapping.getFragment2());
}
else if(mapping instanceof CompositeStatementObjectMapping) {
CompositeStatementObjectMapping compositeMapping = (CompositeStatementObjectMapping)mapping;
innerNodes1.add((CompositeStatementObject)compositeMapping.getFragment1());
innerNodes2.add((CompositeStatementObject)compositeMapping.getFragment2());
}
}
}
}
}
nonMappedLeavesT1.addAll(leaves1);
nonMappedLeavesT2.addAll(leaves2);
nonMappedInnerNodesT1.addAll(innerNodes1);
nonMappedInnerNodesT2.addAll(innerNodes2);
Set leavesToBeRemovedT1 = new LinkedHashSet<>();
Set leavesToBeRemovedT2 = new LinkedHashSet<>();
for(AbstractCodeFragment statement : getNonMappedLeavesT2()) {
temporaryVariableAssignment(statement, nonMappedLeavesT2);
if(statement.getVariableDeclarations().size() > 0) {
VariableDeclaration declaration = statement.getVariableDeclarations().get(0);
AbstractExpression initializer = declaration.getInitializer();
if(initializer != null && (initializer.getMethodInvocations().size() > 0 || initializer.getCreations().size() > 0)) {
for(AbstractCodeFragment nonMappedLeaf1 : nonMappedLeavesT1) {
boolean matchingVariableDeclaration = false;
List declarations1 = nonMappedLeaf1.getVariableDeclarations();
for(VariableDeclaration declaration1 : declarations1) {
if(declaration1.getVariableName().equals(declaration.getVariableName()) && declaration1.equalType(declaration)) {
matchingVariableDeclaration = true;
break;
}
}
if(!matchingVariableDeclaration && !containsMethodSignatureOfAnonymousClass(nonMappedLeaf1.getString()) &&
!nonMappedLeaf1.getString().endsWith(JAVA.ASSIGNMENT + initializer + JAVA.STATEMENT_TERMINATION) && !nonMappedLeaf1.getString().contains(JAVA.ASSIGNMENT + initializer + ".") &&
nonMappedLeaf1.getString().contains(initializer.getString())) {
UMLOperation inlinedOperation = callToInlinedMethod(nonMappedLeaf1);
boolean matchingInlinedOperationLeaf = false;
if(inlinedOperation != null) {
List inlinedOperationLeaves = inlinedOperation.getBody().getCompositeStatement().getLeaves();
for(AbstractCodeFragment inlinedOperationLeaf : inlinedOperationLeaves) {
if(statement.getString().equals(inlinedOperationLeaf.getString())) {
matchingInlinedOperationLeaf = true;
break;
}
}
}
if(!matchingInlinedOperationLeaf) {
ExtractVariableRefactoring ref = new ExtractVariableRefactoring(declaration, operation1, operation2, parentMapper != null);
ref.addUnmatchedStatementReference(nonMappedLeaf1);
List subExpressions = nonMappedLeaf1.findExpression(initializer.getString());
for(LeafExpression subExpression : subExpressions) {
LeafMapping leafMapping = new LeafMapping(subExpression, initializer, operation1, operation2);
ref.addSubExpressionMapping(leafMapping);
}
refactorings.add(ref);
leavesToBeRemovedT2.add(statement);
}
}
}
}
}
}
nonMappedLeavesT2.removeAll(leavesToBeRemovedT2);
for(AbstractCodeFragment statement : getNonMappedLeavesT1()) {
inlinedVariableAssignment(statement, nonMappedLeavesT2);
if(statement.getVariableDeclarations().size() > 0) {
VariableDeclaration declaration = statement.getVariableDeclarations().get(0);
AbstractExpression initializer = declaration.getInitializer();
if(initializer != null && (initializer.getMethodInvocations().size() > 0 || initializer.getCreations().size() > 0)) {
for(AbstractCodeFragment nonMappedLeaf2 : nonMappedLeavesT2) {
boolean matchingVariableDeclaration = false;
List declarations2 = nonMappedLeaf2.getVariableDeclarations();
for(VariableDeclaration declaration2 : declarations2) {
if(declaration2.getVariableName().equals(declaration.getVariableName()) && declaration2.equalType(declaration)) {
matchingVariableDeclaration = true;
break;
}
}
String initializerAfterRename = null;
if(!matchingVariableDeclaration && !containsMethodSignatureOfAnonymousClass(nonMappedLeaf2.getString()) &&
!nonMappedLeaf2.getString().endsWith(JAVA.ASSIGNMENT + initializer + JAVA.STATEMENT_TERMINATION) && !nonMappedLeaf2.getString().contains(JAVA.ASSIGNMENT + initializer + ".") &&
(nonMappedLeaf2.getString().contains(initializer.getString()) || (initializerAfterRename = matchesWithOverlappingRenameVariable(initializer, nonMappedLeaf2)) != null) &&
existsMappingSubsumingBoth(statement, nonMappedLeaf2)) {
UMLOperation extractedOperation = callToExtractedMethod(nonMappedLeaf2);
boolean matchingExtractedOperationLeaf = false;
if(extractedOperation != null) {
List extractedOperationLeaves = extractedOperation.getBody().getCompositeStatement().getLeaves();
for(AbstractCodeFragment extractedOperationLeaf : extractedOperationLeaves) {
if(statement.getString().equals(extractedOperationLeaf.getString())) {
matchingExtractedOperationLeaf = true;
break;
}
}
}
if(!matchingExtractedOperationLeaf) {
InlineVariableRefactoring ref = new InlineVariableRefactoring(declaration, operation1, operation2, parentMapper != null);
ref.addUnmatchedStatementReference(nonMappedLeaf2);
List subExpressions = nonMappedLeaf2.findExpression(initializerAfterRename != null ? initializerAfterRename : initializer.getString());
for(LeafExpression subExpression : subExpressions) {
LeafMapping leafMapping = new LeafMapping(initializer, subExpression, operation1, operation2);
ref.addSubExpressionMapping(leafMapping);
}
refactorings.add(ref);
leavesToBeRemovedT1.add(statement);
}
}
}
}
}
}
nonMappedLeavesT1.removeAll(leavesToBeRemovedT1);
}
AbstractExpression defaultExpression1 = operation1.getDefaultExpression();
AbstractExpression defaultExpression2 = operation2.getDefaultExpression();
if(defaultExpression1 != null && defaultExpression2 != null) {
List leaves1 = new ArrayList();
leaves1.add(defaultExpression1);
List leaves2 = new ArrayList();
leaves2.add(defaultExpression2);
processLeaves(leaves1, leaves2, new LinkedHashMap(), false);
}
if(operation1.getJavadoc() != null && operation2.getJavadoc() != null) {
UMLJavadocDiff diff = new UMLJavadocDiff(operation1.getJavadoc(), operation2.getJavadoc());
this.javadocDiff = Optional.of(diff);
}
this.commentListDiff = new UMLCommentListDiff(container1.getComments(), container2.getComments());
checkUnmatchedStatementsBeingCommented();
}
private void checkUnmatchedStatementsBeingCommented() {
List uniqueComments1 = commentListDiff.getDeletedComments();
List uniqueComments2 = commentListDiff.getAddedComments();
// check if unmatched statements from left side have been commented
if(uniqueComments2.size() > 0 && nonMappedLeavesT1.size() > 0) {
for(UMLComment comment : uniqueComments2) {
String text = comment.getText();
if(text.startsWith("//")) {
text = text.substring(2);
}
text = text.trim();
ASTNode node = processBlock(text);
if(node != null) {
String nodeAsString = stringify(node);
Set matchingNodes1 = new LinkedHashSet();
for(AbstractCodeFragment leaf1 : nonMappedLeavesT1) {
if(leaf1.getString().equals(nodeAsString)) {
matchingNodes1.add(leaf1);
}
}
if(matchingNodes1.size() == 1) {
commentedCode.add(Pair.of(matchingNodes1.iterator().next(), comment));
}
}
}
}
// check if unmatched statements from right side have been uncommented
if(uniqueComments1.size() > 0 && nonMappedLeavesT2.size() > 0) {
//List
for(UMLComment comment : uniqueComments1) {
String text = comment.getText();
if(text.startsWith("//")) {
text = text.substring(2);
}
text = text.trim();
ASTNode node = processBlock(text);
if(node != null) {
String nodeAsString = stringify(node);
Set matchingNodes2 = new LinkedHashSet();
for(AbstractCodeFragment leaf2 : nonMappedLeavesT2) {
if(leaf2.getString().equals(nodeAsString)) {
matchingNodes2.add(leaf2);
}
}
if(matchingNodes2.size() == 1) {
unCommentedCode.add(Pair.of(comment, matchingNodes2.iterator().next()));
}
}
}
}
}
private boolean existsMappingSubsumingBoth(AbstractCodeFragment nonMappedLeaf1, AbstractCodeFragment nonMappedLeaf2) {
if((nonMappedLeaf1.getParent() != null && nonMappedLeaf1.getParent().getParent() == null) || (nonMappedLeaf2.getParent() != null && nonMappedLeaf2.getParent().getParent() == null)) {
return true;
}
for(AbstractCodeMapping mapping : getMappings()) {
if(mapping.getFragment1().getLocationInfo().subsumes(nonMappedLeaf1.getLocationInfo()) && mapping.getFragment2().getLocationInfo().subsumes(nonMappedLeaf2.getLocationInfo())) {
return true;
}
}
return false;
}
private String matchesWithOverlappingRenameVariable(AbstractExpression initializer, AbstractCodeFragment nonMappedLeaf2) {
for(AbstractCodeMapping mapping : getMappings()) {
if(mapping.getFragment2().getLocationInfo().subsumes(nonMappedLeaf2.getLocationInfo())) {
Set replacements = mapping.getReplacements();
for(Replacement r : replacements) {
if(r.getType().equals(ReplacementType.VARIABLE_NAME) && initializer.getString().contains(r.getBefore())) {
String temp = initializer.getString();
temp = ReplacementUtil.performReplacement(temp, r.getBefore(), r.getAfter());
if(nonMappedLeaf2.getString().contains(temp)) {
return temp;
}
}
}
}
}
return null;
}
private void handleAssertThrowsLambda(List leaves1, List leaves2,
List innerNodes2, List lambdas2, UMLOperation operation2) {
Set lambdaFragments = new LinkedHashSet();
if(lambdas2.size() == 1) {
for(AbstractCodeFragment leaf2 : leaves2) {
if(leaf2.getLambdas().size() > 0) {
lambdaFragments.add(leaf2);
break;
}
}
}
else {
for(AbstractCodeFragment leaf2 : leaves2) {
if(leaf2.getLambdas().size() > 0) {
boolean identicalLeaf1Found = false;
for(AbstractCodeFragment leaf1 : leaves1) {
if(leaf1.getString().equals(leaf2.getString())) {
identicalLeaf1Found = true;
break;
}
}
if(identicalLeaf1Found) {
continue;
}
lambdaFragments.add(leaf2);
}
}
}
for(AbstractCodeFragment lambdaFragment : lambdaFragments) {
expandAnonymousAndLambdas(lambdaFragment, leaves2, innerNodes2, new LinkedHashSet<>(), new LinkedHashSet<>(), anonymousClassList2(), codeFragmentOperationMap2, operation2, true);
}
}
private boolean isTryBlock(AbstractCodeFragment child, CompositeStatementObject parent) {
return parent.getLocationInfo().getCodeElementType().equals(CodeElementType.TRY_STATEMENT) &&
parent.getStatements().indexOf(child) != -1;
}
private boolean isFinallyBlock(AbstractCodeFragment child, CompositeStatementObject parent) {
return parent.getLocationInfo().getCodeElementType().equals(CodeElementType.FINALLY_BLOCK) &&
parent.getStatements().indexOf(child) != -1;
}
private boolean ifAddingElseIf(CompositeStatementObject parent) {
for(AbstractCodeMapping mapping : ifAddingElseIf) {
if(mapping.getFragment1().equals(parent) || mapping.getFragment2().equals(parent)) {
return true;
}
}
return false;
}
private boolean ifAddingElseIf(AbstractCodeMapping mapping) {
if(mapping.getFragment1().getLocationInfo().getCodeElementType().equals(CodeElementType.IF_STATEMENT) &&
mapping.getFragment2().getLocationInfo().getCodeElementType().equals(CodeElementType.IF_STATEMENT)) {
boolean hasElseIfBranch1 = hasElseIfBranch((CompositeStatementObject)mapping.getFragment1());
boolean hasElseIfBranch2 = hasElseIfBranch((CompositeStatementObject)mapping.getFragment2());
return hasElseIfBranch1 != hasElseIfBranch2;
}
return false;
}
private boolean ifBecomingElseIf(AbstractCodeMapping mapping) {
AbstractCodeFragment fragment1 = mapping.getFragment1();
AbstractCodeFragment fragment2 = mapping.getFragment2();
return ifBecomingElseIf(fragment1, fragment2);
}
private boolean ifBecomingElseIf(AbstractCodeFragment fragment1, AbstractCodeFragment fragment2) {
if(fragment1.getLocationInfo().getCodeElementType().equals(CodeElementType.IF_STATEMENT) &&
fragment2.getLocationInfo().getCodeElementType().equals(CodeElementType.IF_STATEMENT)) {
boolean isElseIf1 = isElseIfBranch(fragment1, fragment1.getParent());
boolean isElseIf2 = isElseIfBranch(fragment2, fragment2.getParent());
return isElseIf1 != isElseIf2;
}
return false;
}
private boolean isInvolvedInSplitConditional(AbstractCodeMapping mapping) {
for(Refactoring r : this.refactorings) {
if(r instanceof SplitConditionalRefactoring) {
SplitConditionalRefactoring split = (SplitConditionalRefactoring)r;
if(split.getOriginalConditional().equals(mapping.getFragment1()) && split.getSplitConditionals().contains(mapping.getFragment2())) {
return true;
}
}
}
return false;
}
private boolean isSplitConditionalExpression(AbstractCodeMapping mapping) {
for(Refactoring r : this.refactorings) {
if(r instanceof SplitConditionalRefactoring) {
SplitConditionalRefactoring split = (SplitConditionalRefactoring)r;
if(split.getOriginalConditional() instanceof CompositeStatementObject) {
CompositeStatementObject comp = (CompositeStatementObject)split.getOriginalConditional();
if(comp.getExpressions().contains(mapping.getFragment1())) {
return true;
}
}
}
}
for(AbstractCodeMapping previousMapping : this.mappings) {
for(Refactoring r : previousMapping.getRefactorings()) {
if(r instanceof ExtractVariableRefactoring) {
ExtractVariableRefactoring extract = (ExtractVariableRefactoring)r;
if(mapping.getFragment2().getVariableDeclarations().contains(extract.getVariableDeclaration())) {
return true;
}
}
}
}
return false;
}
private boolean nestedUnderSplitConditional(AbstractCodeMapping mapping) {
for(Refactoring r : this.refactorings) {
if(r instanceof SplitConditionalRefactoring) {
SplitConditionalRefactoring split = (SplitConditionalRefactoring)r;
boolean fragmentSubsumed1 = split.getOriginalConditional().getLocationInfo().subsumes(mapping.getFragment1().getLocationInfo());
boolean fragmentSubsumed2 = false;
for(AbstractCodeFragment conditional2 : split.getSplitConditionals()) {
if(conditional2.getLocationInfo().subsumes(mapping.getFragment2().getLocationInfo())) {
fragmentSubsumed2 = true;
break;
}
}
if(fragmentSubsumed1 && fragmentSubsumed2) {
return true;
}
}
}
return false;
}
public UMLOperationBodyMapper(AbstractCodeFragment fragment1, AbstractCodeFragment fragment2,
VariableDeclarationContainer container1, VariableDeclarationContainer container2,
UMLAbstractClassDiff classDiff, UMLModelDiff modelDiff) throws RefactoringMinerTimedOutException {
this.classDiff = classDiff;
this.modelDiff = modelDiff;
this.container1 = container1;
this.container2 = container2;
this.mappings = new LinkedHashSet();
this.nonMappedLeavesT1 = new ArrayList();
this.nonMappedLeavesT2 = new ArrayList();
this.nonMappedInnerNodesT1 = new ArrayList();
this.nonMappedInnerNodesT2 = new ArrayList();
if(fragment1 != null && fragment2 != null) {
List leaves1 = new ArrayList();
leaves1.add(fragment1);
List leaves2 = new ArrayList();
leaves2.add(fragment2);
processLeaves(leaves1, leaves2, new LinkedHashMap(), false);
}
}
public UMLOperationBodyMapper(UMLAttribute removedAttribute, UMLAttribute addedAttribute, UMLAbstractClassDiff classDiff, UMLModelDiff modelDiff) throws RefactoringMinerTimedOutException {
this.classDiff = classDiff;
this.modelDiff = modelDiff;
this.container1 = removedAttribute;
this.container2 = addedAttribute;
AbstractExpression expression1 = removedAttribute.getVariableDeclaration().getInitializer();
AbstractExpression expression2 = addedAttribute.getVariableDeclaration().getInitializer();
this.mappings = new LinkedHashSet();
this.nonMappedLeavesT1 = new ArrayList();
this.nonMappedLeavesT2 = new ArrayList();
this.nonMappedInnerNodesT1 = new ArrayList();
this.nonMappedInnerNodesT2 = new ArrayList();
if(expression1 != null && expression2 != null) {
List leaves1 = new ArrayList();
leaves1.add(expression1);
List leaves2 = new ArrayList();
leaves2.add(expression2);
processLeaves(leaves1, leaves2, new LinkedHashMap(), false);
}
}
public UMLOperationBodyMapper(UMLInitializer initializer1, UMLInitializer initializer2, UMLAbstractClassDiff classDiff) throws RefactoringMinerTimedOutException {
this.classDiff = classDiff;
this.modelDiff = classDiff != null ? classDiff.getModelDiff() : null;
this.container1 = initializer1;
this.container2 = initializer2;
this.mappings = new LinkedHashSet();
this.nonMappedLeavesT1 = new ArrayList();
this.nonMappedLeavesT2 = new ArrayList();
this.nonMappedInnerNodesT1 = new ArrayList();
this.nonMappedInnerNodesT2 = new ArrayList();
CompositeStatementObject composite1 = initializer1.getBody().getCompositeStatement();
CompositeStatementObject composite2 = initializer2.getBody().getCompositeStatement();
processCompositeStatements(composite1.getLeaves(), composite2.getLeaves(), composite1.getInnerNodes(), composite2.getInnerNodes());
if(initializer1.getJavadoc() != null && initializer2.getJavadoc() != null) {
UMLJavadocDiff diff = new UMLJavadocDiff(initializer1.getJavadoc(), initializer2.getJavadoc());
this.javadocDiff = Optional.of(diff);
}
this.commentListDiff = new UMLCommentListDiff(initializer1.getComments(), initializer2.getComments());
checkUnmatchedStatementsBeingCommented();
}
protected UMLOperationBodyMapper(LambdaExpressionObject lambda1, LambdaExpressionObject lambda2, UMLOperationBodyMapper parentMapper) throws RefactoringMinerTimedOutException {
this.parentMapper = parentMapper;
this.classDiff = parentMapper.classDiff;
this.modelDiff = classDiff != null ? classDiff.getModelDiff() : null;
this.container1 = parentMapper.container1;
this.container2 = parentMapper.container2;
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(), false);
}
else if(lambda1.getBody() != null && lambda2.getBody() != null) {
CompositeStatementObject composite1 = lambda1.getBody().getCompositeStatement();
CompositeStatementObject composite2 = lambda2.getBody().getCompositeStatement();
if(composite1.getStatements().size() == 0 && composite2.getStatements().size() == 0) {
CompositeStatementObjectMapping mapping = createCompositeMapping(composite1, composite2, new LinkedHashMap(), 0);
addMapping(mapping);
}
else {
this.lambdaBodyMapper = true;
processCompositeStatements(composite1.getLeaves(), composite2.getLeaves(), composite1.getInnerNodes(), composite2.getInnerNodes());
}
}
else if(lambda1.getExpression() != null && lambda2.getBody() != null) {
List leaves1 = new ArrayList();
leaves1.add(lambda1.getExpression());
CompositeStatementObject composite2 = lambda2.getBody().getCompositeStatement();
this.lambdaBodyMapper = true;
processCompositeStatements(leaves1, composite2.getLeaves(), Collections.emptyList(), composite2.getInnerNodes());
}
else if(lambda1.getBody() != null && lambda2.getExpression() != null) {
CompositeStatementObject composite1 = lambda1.getBody().getCompositeStatement();
List leaves2 = new ArrayList();
leaves2.add(lambda2.getExpression());
this.lambdaBodyMapper = true;
processCompositeStatements(composite1.getLeaves(), leaves2, composite1.getInnerNodes(), Collections.emptyList());
}
this.commentListDiff = new UMLCommentListDiff(lambda1.getComments(), lambda2.getComments());
checkUnmatchedStatementsBeingCommented();
}
private void processCompositeStatements(List leaves1, List leaves2, List innerNodes1, List innerNodes2)
throws RefactoringMinerTimedOutException {
Set streamAPIStatements1 = statementsWithStreamAPICalls(leaves1);
Set streamAPIStatements2 = statementsWithStreamAPICalls(leaves2);
if(streamAPIStatements1.size() == 0 && streamAPIStatements2.size() > 0) {
for(AbstractCodeFragment streamAPICall : streamAPIStatements2) {
if(streamAPICall.getLambdas().size() > 0) {
expandAnonymousAndLambdas(streamAPICall, leaves2, innerNodes2, new LinkedHashSet<>(), new LinkedHashSet<>(), anonymousClassList2(), codeFragmentOperationMap2, container2, false);
}
}
}
else if(streamAPIStatements1.size() > 0 && streamAPIStatements2.size() == 0) {
for(AbstractCodeFragment streamAPICall : streamAPIStatements1) {
if(streamAPICall.getLambdas().size() > 0) {
expandAnonymousAndLambdas(streamAPICall, leaves1, innerNodes1, new LinkedHashSet<>(), new LinkedHashSet<>(), anonymousClassList1(), codeFragmentOperationMap1, container1, false);
}
}
}
boolean isomorphic = isomorphicCompositeStructure(innerNodes1, innerNodes2);
processLeaves(leaves1, leaves2, new LinkedHashMap(), isomorphic);
processInnerNodes(innerNodes1, innerNodes2, leaves1, leaves2, new LinkedHashMap(), containsCallToExtractedMethod(leaves2));
if(streamAPIStatements1.size() == 0 && streamAPIStatements2.size() > 0) {
processStreamAPIStatements(leaves1, leaves2, innerNodes1, streamAPIStatements2);
}
else if(streamAPIStatements1.size() > 0 && streamAPIStatements2.size() == 0) {
processStreamAPIStatements(leaves1, leaves2, streamAPIStatements1, innerNodes2);
}
nonMappedLeavesT1.addAll(leaves1);
nonMappedLeavesT2.addAll(leaves2);
nonMappedInnerNodesT1.addAll(innerNodes1);
nonMappedInnerNodesT2.addAll(innerNodes2);
for(AbstractCodeFragment statement : getNonMappedLeavesT2()) {
temporaryVariableAssignment(statement, nonMappedLeavesT2);
}
for(AbstractCodeFragment statement : getNonMappedLeavesT1()) {
inlinedVariableAssignment(statement, nonMappedLeavesT2);
}
}
private List anonymousClassList1() {
return container1.getAnonymousClassList();
}
private List anonymousClassList2() {
return container2.getAnonymousClassList();
}
private AbstractCodeFragment containLambdaExpression(List compositeLeaves, AbstractCodeFragment lambdaExpression) {
for(AbstractCodeFragment leaf : compositeLeaves) {
for(LambdaExpressionObject lambda : leaf.getLambdas()) {
if(lambda.getExpression() != null && lambda.getExpression().equals(lambdaExpression)) {
return leaf;
}
}
}
return null;
}
private void collectNestedLambdaExpressions(LambdaExpressionObject parentLambda, List nestedLambdas) {
if(parentLambda.getExpression() != null) {
nestedLambdas.addAll(parentLambda.getExpression().getLambdas());
for(LambdaExpressionObject nestedLambda : parentLambda.getExpression().getLambdas()) {
collectNestedLambdaExpressions(nestedLambda, nestedLambdas);
}
}
if(parentLambda.getBody() != null) {
CompositeStatementObject comp = parentLambda.getBody().getCompositeStatement();
for(AbstractCodeFragment fragment : comp.getLeaves()) {
nestedLambdas.addAll(fragment.getLambdas());
for(LambdaExpressionObject nestedLambda : fragment.getLambdas()) {
collectNestedLambdaExpressions(nestedLambda, nestedLambdas);
}
}
}
}
private boolean nestedLambdaExpressionMatch(List lambdas, AbstractCodeFragment lambdaExpression) {
for(LambdaExpressionObject lambda : lambdas) {
if(lambda.getExpression() != null) {
if(lambda.getExpression().equals(lambdaExpression)) {
return true;
}
else if(nestedLambdaExpressionMatch(lambda.getExpression().getLambdas(), lambdaExpression)) {
return true;
}
}
}
return false;
}
private List nestedLambdaParameters(List lambdas) {
List lambdaParameters = new ArrayList<>();
for(LambdaExpressionObject lambda : lambdas) {
lambdaParameters.addAll(lambda.getParameters());
if(lambda.getExpression() != null) {
lambdaParameters.addAll(nestedLambdaParameters(lambda.getExpression().getLambdas()));
}
}
return lambdaParameters;
}
private void processStreamAPIStatements(List leaves1, List leaves2,
Set streamAPIStatements1, List innerNodes2)
throws RefactoringMinerTimedOutException {
//match expressions in inner nodes from T2 with leaves from T1
List expressionsT2 = new ArrayList();
for(CompositeStatementObject composite : innerNodes2) {
if(composite.getLocationInfo().getCodeElementType().equals(CodeElementType.IF_STATEMENT)) {
for(AbstractExpression expression : composite.getExpressions()) {
expressionsT2.add(expression);
}
}
}
int numberOfMappings = mappings.size();
processLeaves(leaves1, expressionsT2, new LinkedHashMap(), false);
List mappings = new ArrayList<>(this.mappings);
if(numberOfMappings == mappings.size()) {
for(ListIterator innerNodeIterator2 = innerNodes2.listIterator(); innerNodeIterator2.hasNext();) {
CompositeStatementObject composite = innerNodeIterator2.next();
Set additionallyMatchedStatements1 = new LinkedHashSet<>();
Set additionallyMatchedStatements2 = new LinkedHashSet<>();
List compositeLeaves = composite.getLeaves();
for(AbstractCodeMapping mapping : mappings) {
AbstractCodeFragment fragment1 = mapping.getFragment1();
AbstractCodeFragment fragment2 = mapping.getFragment2();
if((composite.getLocationInfo().getCodeElementType().equals(CodeElementType.FOR_STATEMENT) ||
composite.getLocationInfo().getCodeElementType().equals(CodeElementType.ENHANCED_FOR_STATEMENT) ||
composite.getLocationInfo().getCodeElementType().equals(CodeElementType.WHILE_STATEMENT) ||
composite.getLocationInfo().getCodeElementType().equals(CodeElementType.DO_STATEMENT)) &&
(compositeLeaves.contains(fragment2) || containLambdaExpression(compositeLeaves, fragment2) != null)) {
AbstractCodeFragment streamAPICallStatement = null;
List streamAPICalls = null;
for(AbstractCodeFragment leaf1 : streamAPIStatements1) {
if(leaves1.contains(leaf1)) {
boolean matchingLambda = nestedLambdaExpressionMatch(leaf1.getLambdas(), fragment1);
if(matchingLambda) {
streamAPICallStatement = leaf1;
streamAPICalls = streamAPICalls(leaf1);
break;
}
}
}
if(streamAPICallStatement != null && streamAPICalls != null) {
List lambdaParameters = nestedLambdaParameters(streamAPICallStatement.getLambdas());
List leafMappings = new ArrayList();
AbstractCall call1 = fragment1.invocationCoveringEntireFragment();
AbstractCall call2 = fragment2.invocationCoveringEntireFragment();
if(call1 != null && call2 != null) {
LeafMapping leafMapping = new LeafMapping(call1, call2, container1, container2);
leafMappings.add(leafMapping);
}
else {
call1 = fragment1.creationCoveringEntireFragment();
call2 = fragment2.creationCoveringEntireFragment();
if(call1 != null && call2 != null) {
LeafMapping leafMapping = new LeafMapping(call1, call2, container1, container2);
leafMappings.add(leafMapping);
}
else if(fragment1 instanceof AbstractExpression) {
List leafExpressions = fragment2.findExpression(fragment1.getString());
for(LeafExpression leafExpression : leafExpressions) {
LeafMapping leafMapping = new LeafMapping(fragment1, leafExpression, container1, container2);
leafMappings.add(leafMapping);
}
}
}
additionallyMatchedStatements1.add(streamAPICallStatement);
additionallyMatchedStatements2.add(fragment2);
for(AbstractCall streamAPICall : streamAPICalls) {
if(streamAPICall.getName().equals("forEach")) {
if(!additionallyMatchedStatements2.contains(composite)) {
for(AbstractExpression expression : composite.getExpressions()) {
if(expression.getString().equals(streamAPICall.getExpression())) {
List leafExpressions = streamAPICallStatement.findExpression(streamAPICall.getExpression());
for(LeafExpression leafExpression : leafExpressions) {
LeafMapping leafMapping = new LeafMapping(leafExpression, expression, container1, container2);
leafMappings.add(leafMapping);
}
additionallyMatchedStatements2.add(composite);
break;
}
}
}
}
else if(streamAPICall.getName().equals("stream")) {
if(!additionallyMatchedStatements2.contains(composite)) {
for(AbstractExpression expression : composite.getExpressions()) {
if(expression.getString().equals(streamAPICall.getExpression())) {
List leafExpressions = streamAPICallStatement.findExpression(streamAPICall.getExpression());
for(LeafExpression leafExpression : leafExpressions) {
LeafMapping leafMapping = new LeafMapping(leafExpression, expression, container1, container2);
leafMappings.add(leafMapping);
}
additionallyMatchedStatements2.add(composite);
break;
}
for(String argument : streamAPICall.arguments()) {
if(expression.getString().equals(argument)) {
List leafExpressions = streamAPICallStatement.findExpression(argument);
for(LeafExpression leafExpression : leafExpressions) {
LeafMapping leafMapping = new LeafMapping(leafExpression, expression, container1, container2);
leafMappings.add(leafMapping);
}
additionallyMatchedStatements2.add(composite);
break;
}
}
}
}
}
}
CompositeReplacement replacement = new CompositeReplacement(streamAPICallStatement.getString(), composite.getString(), additionallyMatchedStatements1, additionallyMatchedStatements2);
Set replacements = new LinkedHashSet<>();
replacements.add(replacement);
LeafMapping newMapping = createLeafMapping(streamAPICallStatement, composite, new LinkedHashMap(), false);
newMapping.addReplacements(replacements);
TreeSet mappingSet = new TreeSet<>();
mappingSet.add(newMapping);
if(!additionallyMatchedStatements2.contains(composite)) {
additionallyMatchedStatements2.add(composite);
}
for(VariableDeclaration lambdaParameter : lambdaParameters) {
for(VariableDeclaration compositeParameter : composite.getVariableDeclarations()) {
if(lambdaParameter.getVariableName().equals(compositeParameter.getVariableName())) {
Pair pair = Pair.of(lambdaParameter, compositeParameter);
matchedVariables.add(pair);
}
else {
for(Replacement r : mapping.getReplacements()) {
if(r.getBefore().equals(lambdaParameter.getVariableName()) && r.getAfter().equals(compositeParameter.getVariableName())) {
Pair pair = Pair.of(lambdaParameter, compositeParameter);
matchedVariables.add(pair);
break;
}
}
}
}
}
ReplacePipelineWithLoopRefactoring ref = new ReplacePipelineWithLoopRefactoring(additionallyMatchedStatements1, additionallyMatchedStatements2, container1, container2);
for(LeafMapping leafMapping : leafMappings) {
ref.addSubExpressionMapping(leafMapping);
}
newMapping.addRefactoring(ref);
addToMappings(newMapping, mappingSet);
leaves1.remove(newMapping.getFragment1());
}
}
}
if(additionallyMatchedStatements2.contains(composite)) {
innerNodeIterator2.remove();
}
}
}
for(int i = numberOfMappings; i < mappings.size(); i++) {
AbstractCodeMapping mapping = mappings.get(i);
AbstractCodeFragment fragment1 = mapping.getFragment1();
AbstractCodeFragment fragment2 = mapping.getFragment2();
for(ListIterator innerNodeIterator2 = innerNodes2.listIterator(); innerNodeIterator2.hasNext();) {
CompositeStatementObject composite = innerNodeIterator2.next();
if(composite.getExpressions().contains(fragment2)) {
AbstractCodeFragment streamAPICallStatement = null;
List streamAPICalls = null;
for(AbstractCodeFragment leaf1 : streamAPIStatements1) {
if(leaves1.contains(leaf1)) {
boolean matchingLambda = nestedLambdaExpressionMatch(leaf1.getLambdas(), fragment1);
if(matchingLambda) {
streamAPICallStatement = leaf1;
streamAPICalls = streamAPICalls(leaf1);
break;
}
}
}
if(streamAPICallStatement != null && streamAPICalls != null) {
List lambdaParameters = nestedLambdaParameters(streamAPICallStatement.getLambdas());
Set additionallyMatchedStatements1 = new LinkedHashSet<>();
additionallyMatchedStatements1.add(streamAPICallStatement);
Set additionallyMatchedStatements2 = new LinkedHashSet<>();
additionallyMatchedStatements2.add(composite);
for(AbstractCall streamAPICall : streamAPICalls) {
if(streamAPICall.getName().equals("filter")) {
for(AbstractCodeFragment leaf2 : leaves2) {
AbstractCall invocation = leaf2.invocationCoveringEntireFragment();
if(invocation != null && invocation.getName().equals("add")) {
for(String argument : invocation.arguments()) {
if(streamAPICall.arguments().get(0).startsWith(argument + JAVA.LAMBDA_ARROW)) {
additionallyMatchedStatements2.add(leaf2);
break;
}
}
}
}
}
else if(streamAPICall.getName().equals("removeIf")) {
for(AbstractCodeFragment leaf2 : leaves2) {
AbstractCall invocation = leaf2.invocationCoveringEntireFragment();
if(invocation != null && invocation.getExpression() != null) {
if(invocation.getName().equals("next")) {
for(VariableDeclaration variableDeclaration : leaf2.getVariableDeclarations()) {
if(streamAPICall.arguments().get(0).startsWith(variableDeclaration.getVariableName() + JAVA.LAMBDA_ARROW)) {
additionallyMatchedStatements2.add(leaf2);
break;
}
}
}
else if(invocation.getName().equals("remove")) {
additionallyMatchedStatements2.add(leaf2);
for(ListIterator it = innerNodes2.listIterator(); it.hasNext();) {
CompositeStatementObject comp = it.next();
if(comp.getVariableDeclaration(invocation.getExpression()) != null) {
additionallyMatchedStatements2.add(comp);
composite = comp;
break;
}
}
}
}
}
}
else if(streamAPICall.getName().equals("stream")) {
for(CompositeStatementObject comp2 : innerNodes2) {
if(!additionallyMatchedStatements2.contains(comp2)) {
for(AbstractExpression expression : comp2.getExpressions()) {
if(expression.getString().equals(streamAPICall.getExpression())) {
additionallyMatchedStatements2.add(comp2);
break;
}
for(String argument : streamAPICall.arguments()) {
if(expression.getString().equals(argument)) {
additionallyMatchedStatements2.add(comp2);
break;
}
}
}
}
}
}
else if(streamAPICall.getName().equals("forEach")) {
for(CompositeStatementObject comp2 : innerNodes2) {
if(!additionallyMatchedStatements2.contains(comp2)) {
for(AbstractExpression expression : comp2.getExpressions()) {
if(expression.getString().equals(streamAPICall.getExpression())) {
additionallyMatchedStatements2.add(comp2);
break;
}
}
if(comp2.getLocationInfo().getCodeElementType().equals(CodeElementType.FOR_STATEMENT) ||
comp2.getLocationInfo().getCodeElementType().equals(CodeElementType.ENHANCED_FOR_STATEMENT) ||
comp2.getLocationInfo().getCodeElementType().equals(CodeElementType.WHILE_STATEMENT) ||
comp2.getLocationInfo().getCodeElementType().equals(CodeElementType.DO_STATEMENT)) {
List compositeLeaves = comp2.getLeaves();
for(AbstractCodeMapping m : mappings) {
if(!m.equals(mapping)) {
AbstractCodeFragment leaf2 = null;
if(compositeLeaves.contains(m.getFragment2()) || (leaf2 = containLambdaExpression(compositeLeaves, m.getFragment2())) != null) {
if(leaf2 != null && composite.getLocationInfo().subsumes(leaf2.getLocationInfo())) {
additionallyMatchedStatements2.add(comp2);
additionallyMatchedStatements2.add(leaf2);
composite = comp2;
break;
}
else if(composite.getLocationInfo().subsumes(m.getFragment2().getLocationInfo())) {
additionallyMatchedStatements2.add(comp2);
additionallyMatchedStatements2.add(m.getFragment2());
composite = comp2;
break;
}
}
}
}
}
}
}
}
}
CompositeReplacement replacement = new CompositeReplacement(streamAPICallStatement.getString(), composite.getString(), additionallyMatchedStatements1, additionallyMatchedStatements2);
Set replacements = new LinkedHashSet<>();
replacements.add(replacement);
LeafMapping newMapping = createLeafMapping(streamAPICallStatement, composite, new LinkedHashMap(), false);
newMapping.addReplacements(replacements);
TreeSet mappingSet = new TreeSet<>();
mappingSet.add(newMapping);
for(VariableDeclaration lambdaParameter : lambdaParameters) {
for(VariableDeclaration compositeParameter : composite.getVariableDeclarations()) {
if(lambdaParameter.getVariableName().equals(compositeParameter.getVariableName())) {
Pair pair = Pair.of(lambdaParameter, compositeParameter);
matchedVariables.add(pair);
}
else {
for(Replacement r : mapping.getReplacements()) {
if(r.getBefore().equals(lambdaParameter.getVariableName()) && r.getAfter().equals(compositeParameter.getVariableName())) {
Pair pair = Pair.of(lambdaParameter, compositeParameter);
matchedVariables.add(pair);
break;
}
}
}
}
}
ReplacePipelineWithLoopRefactoring ref = new ReplacePipelineWithLoopRefactoring(additionallyMatchedStatements1, additionallyMatchedStatements2, container1, container2);
newMapping.addRefactoring(ref);
addToMappings(newMapping, mappingSet);
leaves1.remove(newMapping.getFragment1());
innerNodeIterator2.remove();
}
}
}
}
}
private void processStreamAPIStatements(List leaves1, List leaves2,
List innerNodes1, Set streamAPIStatements2)
throws RefactoringMinerTimedOutException {
//match expressions in inner nodes from T1 with leaves from T2
List expressionsT1 = new ArrayList();
for(CompositeStatementObject composite : innerNodes1) {
if(composite.getLocationInfo().getCodeElementType().equals(CodeElementType.IF_STATEMENT)) {
for(AbstractExpression expression : composite.getExpressions()) {
expressionsT1.add(expression);
}
}
}
int numberOfMappings = mappings.size();
processLeaves(expressionsT1, leaves2, new LinkedHashMap(), false);
List