Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
gr.uom.java.xmi.diff.MappingOptimizer Maven / Gradle / Ivy
package gr.uom.java.xmi.diff;
import static gr.uom.java.xmi.Constants.JAVA;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import org.refactoringminer.api.Refactoring;
import gr.uom.java.xmi.LocationInfo.CodeElementType;
import gr.uom.java.xmi.decomposition.AbstractCall;
import gr.uom.java.xmi.decomposition.AbstractCodeFragment;
import gr.uom.java.xmi.decomposition.AbstractCodeMapping;
import gr.uom.java.xmi.decomposition.AbstractExpression;
import gr.uom.java.xmi.decomposition.CompositeStatementObject;
import gr.uom.java.xmi.decomposition.CompositeStatementObjectMapping;
import gr.uom.java.xmi.decomposition.LeafMapping;
import gr.uom.java.xmi.decomposition.UMLOperationBodyMapper;
import gr.uom.java.xmi.decomposition.VariableDeclaration;
import gr.uom.java.xmi.decomposition.AbstractCall.StatementCoverageType;
import gr.uom.java.xmi.decomposition.replacement.Replacement;
public class MappingOptimizer {
private UMLAbstractClassDiff classDiff;
public MappingOptimizer(UMLAbstractClassDiff classDiff) {
this.classDiff = classDiff;
}
public void optimizeDuplicateMappingsForMoveCode(List moveCodeMappers, List refactorings) {
if(moveCodeMappers.size() > 1) {
Map> oneToManyMappings = new HashMap<>();
Map> oneToManyMappers = new HashMap<>();
for(UMLOperationBodyMapper moveCodeMapper : moveCodeMappers) {
for(AbstractCodeMapping mapping : moveCodeMapper.getMappings()) {
AbstractCodeFragment fragmentContainingExpression = null;
if(oneToManyMappings.containsKey(mapping.getFragment2())) {
oneToManyMappings.get(mapping.getFragment2()).add(mapping);
oneToManyMappers.get(mapping.getFragment2()).add(moveCodeMapper);
}
else if(mapping.getFragment2() instanceof AbstractExpression &&
(fragmentContainingExpression = findFragmentContainingExpression(oneToManyMappings.keySet(), (AbstractExpression)mapping.getFragment2())) != null) {
oneToManyMappings.get(fragmentContainingExpression).add(mapping);
oneToManyMappers.get(fragmentContainingExpression).add(moveCodeMapper);
}
else {
List mappings = new ArrayList<>();
List mappers = new ArrayList<>();
mappings.add(mapping);
mappers.add(moveCodeMapper);
oneToManyMappings.put(mapping.getFragment2(), mappings);
oneToManyMappers.put(mapping.getFragment2(), mappers);
}
}
}
optimizeDuplicateMappings(oneToManyMappings, oneToManyMappers, refactorings);
}
}
private AbstractCodeFragment findFragmentContainingExpression(Set fragments, AbstractExpression expression) {
for(AbstractCodeFragment fragment : fragments) {
if(fragment instanceof CompositeStatementObject) {
CompositeStatementObject comp = (CompositeStatementObject)fragment;
if(comp.getExpressions().contains(expression)) {
return fragment;
}
}
}
return null;
}
public void optimizeDuplicateMappingsForInline(UMLOperationBodyMapper parentMapper, Collection refactorings) {
if(parentMapper.getChildMappers().size() > 0) {
Map> oneToManyMappings = new HashMap<>();
Map> oneToManyMappers = new HashMap<>();
for(UMLOperationBodyMapper childMapper : parentMapper.getChildMappers()) {
for(AbstractCodeMapping mapping : childMapper.getMappings()) {
AbstractCodeFragment fragmentContainingExpression = null;
if(oneToManyMappings.containsKey(mapping.getFragment2())) {
oneToManyMappings.get(mapping.getFragment2()).add(mapping);
oneToManyMappers.get(mapping.getFragment2()).add(childMapper);
}
else if(mapping.getFragment2() instanceof AbstractExpression &&
(fragmentContainingExpression = findFragmentContainingExpression(oneToManyMappings.keySet(), (AbstractExpression)mapping.getFragment2())) != null) {
oneToManyMappings.get(fragmentContainingExpression).add(mapping);
oneToManyMappers.get(fragmentContainingExpression).add(childMapper);
}
else {
List mappings = new ArrayList<>();
List mappers = new ArrayList<>();
mappings.add(mapping);
mappers.add(childMapper);
oneToManyMappings.put(mapping.getFragment2(), mappings);
oneToManyMappers.put(mapping.getFragment2(), mappers);
}
}
}
for(AbstractCodeMapping mapping : parentMapper.getMappings()) {
if(oneToManyMappings.containsKey(mapping.getFragment2())) {
oneToManyMappings.get(mapping.getFragment2()).add(mapping);
oneToManyMappers.get(mapping.getFragment2()).add(parentMapper);
}
else {
List mappings = new ArrayList<>();
List mappers = new ArrayList<>();
mappings.add(mapping);
mappers.add(parentMapper);
oneToManyMappings.put(mapping.getFragment2(), mappings);
oneToManyMappers.put(mapping.getFragment2(), mappers);
}
}
optimizeDuplicateMappings(oneToManyMappings, oneToManyMappers, refactorings);
}
}
private boolean subexpressionOverlap(List mappings, AbstractCodeMapping newMapping) {
for(AbstractCodeMapping previousMapping : mappings) {
AbstractCodeFragment previousFragment2 = previousMapping.getFragment2();
AbstractCodeFragment newFragment2 = newMapping.getFragment2();
if(previousFragment2.getString().startsWith(JAVA.RETURN_SPACE) && previousFragment2.getString().endsWith(JAVA.STATEMENT_TERMINATION) &&
newFragment2.getString().startsWith(JAVA.RETURN_SPACE) && newFragment2.getString().endsWith(JAVA.STATEMENT_TERMINATION)) {
String previousReturnExpression = previousFragment2.getString().substring(JAVA.RETURN_SPACE.length(), previousFragment2.getString().length()-JAVA.STATEMENT_TERMINATION.length());
String newReturnExpression = newFragment2.getString().substring(JAVA.RETURN_SPACE.length(), newFragment2.getString().length()-JAVA.STATEMENT_TERMINATION.length());
if(previousReturnExpression.contains("(" + newReturnExpression + ")") || newReturnExpression.contains("(" + previousReturnExpression + ")")) {
return true;
}
}
}
return false;
}
public void optimizeDuplicateMappingsForExtract(UMLOperationBodyMapper parentMapper, Collection refactorings) {
if(parentMapper.getChildMappers().size() > 0) {
Map> oneToManyMappings = new HashMap<>();
Map> oneToManyMappers = new HashMap<>();
for(UMLOperationBodyMapper childMapper : parentMapper.getChildMappers()) {
for(AbstractCodeMapping mapping : childMapper.getMappings()) {
AbstractCodeFragment fragmentContainingExpression = null;
if(oneToManyMappings.containsKey(mapping.getFragment1())) {
if(!subexpressionOverlap(oneToManyMappings.get(mapping.getFragment1()), mapping)) {
oneToManyMappings.get(mapping.getFragment1()).add(mapping);
oneToManyMappers.get(mapping.getFragment1()).add(childMapper);
}
}
else if(mapping.getFragment1() instanceof AbstractExpression &&
(fragmentContainingExpression = findFragmentContainingExpression(oneToManyMappings.keySet(), (AbstractExpression)mapping.getFragment1())) != null) {
oneToManyMappings.get(fragmentContainingExpression).add(mapping);
oneToManyMappers.get(fragmentContainingExpression).add(childMapper);
}
else {
List mappings = new ArrayList<>();
List mappers = new ArrayList<>();
mappings.add(mapping);
mappers.add(childMapper);
oneToManyMappings.put(mapping.getFragment1(), mappings);
oneToManyMappers.put(mapping.getFragment1(), mappers);
}
}
}
for(AbstractCodeMapping mapping : parentMapper.getMappings()) {
if(oneToManyMappings.containsKey(mapping.getFragment1())) {
oneToManyMappings.get(mapping.getFragment1()).add(mapping);
oneToManyMappers.get(mapping.getFragment1()).add(parentMapper);
}
else {
List mappings = new ArrayList<>();
List mappers = new ArrayList<>();
mappings.add(mapping);
mappers.add(parentMapper);
oneToManyMappings.put(mapping.getFragment1(), mappings);
oneToManyMappers.put(mapping.getFragment1(), mappers);
}
}
optimizeDuplicateMappings(oneToManyMappings, oneToManyMappers, refactorings);
}
}
private void optimizeDuplicateMappings(Map> oneToManyMappings,
Map> oneToManyMappers, Collection refactorings) {
for(Iterator it = oneToManyMappers.keySet().iterator(); it.hasNext();) {
AbstractCodeFragment fragment = it.next();
if(oneToManyMappings.get(fragment).size() == 1) {
oneToManyMappings.remove(fragment);
}
}
//sort oneToManyMappings keys to put first composite statements, then blocks, then leaf statements
TreeSet sortedKeys = new TreeSet<>(new CodeFragmentComparator());
sortedKeys.addAll(oneToManyMappings.keySet());
Set updatedMappers = new LinkedHashSet<>();
for(AbstractCodeFragment fragment : sortedKeys) {
List mappings = oneToManyMappings.get(fragment);
List mappers = oneToManyMappers.get(fragment);
Iterator mappingIterator = mappings.iterator();
Iterator mapperIterator = mappers.iterator();
List callsExtractedInlinedMethod = new ArrayList<>();
List parentMappingFound = new ArrayList<>();
List parentIsContainerBody = new ArrayList<>();
List nestedMapper = new ArrayList<>();
List identical = new ArrayList<>();
List identicalStatementsForCompositeMappings = new ArrayList<>();
List exactMappingsNestedUnderCompositeExcludingBlocks = new ArrayList<>();
List nonMappedNodes = new ArrayList<>();
List replacementTypeCount = new ArrayList<>();
List replacementCoversEntireStatement = new ArrayList<>();
List extractInlineOverlappingRefactoring = new ArrayList<>();
List parentMappers = new ArrayList<>();
List editDistances = new ArrayList<>();
//check if mappings are the same references
Set mappingsAsSet = new LinkedHashSet<>();
mappingsAsSet.addAll(mappings);
Set mappersAsSet = new LinkedHashSet<>();
mappersAsSet.addAll(mappers);
if(mappingsAsSet.size() == 1 || (mappersAsSet.size() == 1 && mappersAsSet.iterator().next().getParentMapper() == null)) {
continue;
}
while(mappingIterator.hasNext()) {
AbstractCodeMapping mapping = mappingIterator.next();
UMLOperationBodyMapper mapper = mapperIterator.next();
if(mapping instanceof CompositeStatementObjectMapping) {
CompositeStatementObject comp1 = (CompositeStatementObject)mapping.getFragment1();
CompositeStatementObject comp2 = (CompositeStatementObject)mapping.getFragment2();
List stringRepresentation1 = comp1.stringRepresentation();
List stringRepresentation2 = comp2.stringRepresentation();
int minSize = Math.min(stringRepresentation1.size(), stringRepresentation2.size());
int identicalStatements = 0;
for(int i=0; i indicesToBeRemoved = new LinkedHashSet<>();
if(callsExtractedInlinedMethod.contains(true) && callsExtractedInlinedMethod.contains(false)) {
for(int i=0; i 1) {
if(parentMappingFound.contains(true)) {
for(int i=0; i identicalStatementsForCompositeMappings.get(indexOfTrueParentMapping)) {
skip = true;
}
if(mappings.get(i).getFragment1().getLocationInfo().getCodeElementType().equals(CodeElementType.IF_STATEMENT) &&
mappings.get(i).getFragment2().getLocationInfo().getCodeElementType().equals(CodeElementType.IF_STATEMENT)) {
String condition = mappings.get(i).getFragment2().getString().substring(3, mappings.get(i).getFragment2().getString().length()-1);
String conditionOfTrueParentMapping = mappings.get(indexOfTrueParentMapping).getFragment2().getString().substring(3, mappings.get(indexOfTrueParentMapping).getFragment2().getString().length()-1);
if(mappings.get(i).getFragment1().getString().contains(condition) && mappings.get(indexOfTrueParentMapping).getFragment1().getString().contains(conditionOfTrueParentMapping)) {
splitConditional = true;
}
}
}
if(parentIsContainerBody.get(i) == true && editDistances.get(i).equals(editDistances.get(parentMappingFound.indexOf(true))) &&
!mappings.get(i).getFragment1().getString().startsWith(JAVA.RETURN_SPACE) && !mappings.get(i).getFragment2().getString().startsWith(JAVA.RETURN_SPACE)) {
skip = true;
}
if(parentIsContainerBody.get(i) == true && mappings.get(i).getFragment1().getAnonymousClassDeclarations().size() > 0 && mappings.get(i).getFragment2().getAnonymousClassDeclarations().size() > 0) {
skip = true;
anonymousClassDeclarationMatch = true;
}
List fragment2VariableDeclarations = mappings.get(i).getFragment2().getVariableDeclarations();
if(parentIsContainerBody.get(i) == true && fragment2VariableDeclarations.size() > 0 &&
mappings.get(parentMappingFound.indexOf(true)).getFragment2().getString().startsWith(fragment2VariableDeclarations.get(0).getVariableName() + JAVA.ASSIGNMENT)) {
skip = true;
splitDeclaration = true;
}
if(!skip) {
indicesToBeRemoved.add(i);
}
}
}
if(!anonymousClassDeclarationMatch && !splitConditional && !splitDeclaration)
determineIndicesToBeRemoved(nestedMapper, identical, exactMappingsNestedUnderCompositeExcludingBlocks, replacementTypeCount, replacementCoversEntireStatement, extractInlineOverlappingRefactoring, indicesToBeRemoved, editDistances);
}
else if(parentIsContainerBody.contains(true)) {
boolean splitConditional = false;
boolean splitDeclaration = false;
for(int i=0; i identicalStatementsForCompositeMappings.get(indexOfTrueParentIsContainerBody)) {
skip = true;
}
if(mappings.get(i).getFragment1().getLocationInfo().getCodeElementType().equals(CodeElementType.IF_STATEMENT) &&
mappings.get(i).getFragment2().getLocationInfo().getCodeElementType().equals(CodeElementType.IF_STATEMENT)) {
String condition = mappings.get(i).getFragment2().getString().substring(3, mappings.get(i).getFragment2().getString().length()-1);
String conditionOfTrueParentIsContainerBody = mappings.get(indexOfTrueParentIsContainerBody).getFragment2().getString().substring(3, mappings.get(indexOfTrueParentIsContainerBody).getFragment2().getString().length()-1);
if(mappings.get(i).getFragment1().getString().contains(condition) && mappings.get(indexOfTrueParentIsContainerBody).getFragment1().getString().contains(conditionOfTrueParentIsContainerBody)) {
splitConditional = true;
}
}
}
List fragment2VariableDeclarations = mappings.get(parentIsContainerBody.indexOf(true)).getFragment2().getVariableDeclarations();
if(fragment2VariableDeclarations.size() > 0 &&
mappings.get(i).getFragment2().getString().startsWith(fragment2VariableDeclarations.get(0).getVariableName() + JAVA.ASSIGNMENT)) {
skip = true;
splitDeclaration = true;
}
if(!skip) {
indicesToBeRemoved.add(i);
}
}
}
if(!splitConditional && !splitDeclaration)
determineIndicesToBeRemoved(nestedMapper, identical, exactMappingsNestedUnderCompositeExcludingBlocks, replacementTypeCount, replacementCoversEntireStatement, extractInlineOverlappingRefactoring, indicesToBeRemoved, editDistances);
}
else {
determineIndicesToBeRemoved(nestedMapper, identical, exactMappingsNestedUnderCompositeExcludingBlocks, replacementTypeCount, replacementCoversEntireStatement, extractInlineOverlappingRefactoring, indicesToBeRemoved, editDistances);
}
if(indicesToBeRemoved.isEmpty() && matchingParentMappers(parentMappers) == parentMappers.size()) {
int minimum = nonMappedNodes.get(0);
for(int i=1; i minimum) {
indicesToBeRemoved.add(i);
}
}
}
mappingIterator = mappings.iterator();
mapperIterator = mappers.iterator();
int index = 0;
boolean atLeastOneMappingCallsExtractedOrInlinedMethodWithVariableDeclarationOrThrow =
atLeastOneMappingCallsExtractedOrInlinedMethodWithVariableDeclarationOrThrow(mappings, mappers);
while(mappingIterator.hasNext()) {
AbstractCodeMapping mapping = mappingIterator.next();
UMLOperationBodyMapper mapper = mapperIterator.next();
if(indicesToBeRemoved.contains(index)) {
if(!atLeastOneMappingCallsExtractedOrInlinedMethodWithVariableDeclarationOrThrow) {
mapper.removeMapping(mapping);
for(LeafMapping leafMapping : mapping.getSubExpressionMappings()) {
mapper.removeMapping(leafMapping);
}
if(mapping instanceof LeafMapping) {
if(!mapper.getNonMappedLeavesT1().contains(mapping.getFragment1())) {
mapper.getNonMappedLeavesT1().add(mapping.getFragment1());
}
if(!mapper.getNonMappedLeavesT2().contains(mapping.getFragment2())) {
mapper.getNonMappedLeavesT2().add(mapping.getFragment2());
}
}
else if(mapping instanceof CompositeStatementObjectMapping) {
if(!mapper.getNonMappedInnerNodesT1().contains(mapping.getFragment1())) {
mapper.getNonMappedInnerNodesT1().add((CompositeStatementObject) mapping.getFragment1());
}
if(!mapper.getNonMappedInnerNodesT2().contains(mapping.getFragment2())) {
mapper.getNonMappedInnerNodesT2().add((CompositeStatementObject) mapping.getFragment2());
}
}
//remove refactorings based on mapping
Set refactoringsToBeRemoved = new LinkedHashSet();
Set refactoringsAfterPostProcessing = mapper.getRefactoringsAfterPostProcessing();
for(Refactoring r : refactoringsAfterPostProcessing) {
if(r instanceof ReferenceBasedRefactoring) {
ReferenceBasedRefactoring referenceBased = (ReferenceBasedRefactoring)r;
Set references = referenceBased.getReferences();
if(references.contains(mapping)) {
refactoringsToBeRemoved.add(r);
}
}
}
refactoringsAfterPostProcessing.removeAll(refactoringsToBeRemoved);
updatedMappers.add(mapper);
}
}
index++;
}
}
Set refactoringsToBeRemoved = new LinkedHashSet<>();
for(Refactoring ref : refactorings) {
if(ref instanceof ExtractOperationRefactoring) {
ExtractOperationRefactoring refactoring = (ExtractOperationRefactoring)ref;
if(updatedMappers.contains(refactoring.getBodyMapper())) {
if(refactoring.getBodyMapper().getMappings().size() == 0) {
refactoringsToBeRemoved.add(refactoring);
}
else {
refactoring.updateMapperInfo();
}
}
}
else if(ref instanceof InlineOperationRefactoring) {
InlineOperationRefactoring refactoring = (InlineOperationRefactoring)ref;
if(updatedMappers.contains(refactoring.getBodyMapper())) {
if(refactoring.getBodyMapper().getMappings().size() == 0) {
refactoringsToBeRemoved.add(refactoring);
}
else {
refactoring.updateMapperInfo();
}
}
}
else if(ref instanceof MoveCodeRefactoring) {
MoveCodeRefactoring refactoring = (MoveCodeRefactoring)ref;
if(updatedMappers.contains(refactoring.getBodyMapper())) {
if(refactoring.getBodyMapper().getMappings().size() == 0) {
refactoringsToBeRemoved.add(refactoring);
}
else {
refactoring.updateMapperInfo();
}
}
}
}
refactorings.removeAll(refactoringsToBeRemoved);
}
private boolean callToExtractedInlinedMethodIsArgument(AbstractCodeMapping mapping, UMLOperationBodyMapper mapper) {
if(mapper.getOperationInvocation() != null) {
AbstractCodeFragment fragment1 = mapping.getFragment1();
for(AbstractCall call : fragment1.getCreations()) {
if(call.arguments().contains(mapper.getOperationInvocation().actualString())) {
return true;
}
}
for(AbstractCall call : fragment1.getMethodInvocations()) {
if(call.arguments().contains(mapper.getOperationInvocation().actualString())) {
return true;
}
}
AbstractCodeFragment fragment2 = mapping.getFragment2();
for(AbstractCall call : fragment2.getCreations()) {
if(call.arguments().contains(mapper.getOperationInvocation().actualString())) {
return true;
}
}
for(AbstractCall call : fragment2.getMethodInvocations()) {
if(call.arguments().contains(mapper.getOperationInvocation().actualString())) {
return true;
}
}
}
return false;
}
private boolean atLeastOneMappingCallsExtractedOrInlinedMethodWithVariableDeclarationOrThrow(List mappings, List mappers) {
Set operationInvocations = new LinkedHashSet<>();
for(UMLOperationBodyMapper mapper : mappers) {
if(mapper.getOperationInvocation() != null) {
operationInvocations.add(mapper.getOperationInvocation());
}
}
int matches = 0;
boolean identicalMapping = false;
for(AbstractCodeMapping mapping : mappings) {
if(mapping.getFragment1().getString().equals(mapping.getFragment2().getString())) {
identicalMapping = true;
}
for(AbstractCall operationInvocation : operationInvocations) {
if(callsExtractedOrInlinedMethodWithVariableDeclarationOrThrow(mapping, operationInvocation)) {
matches++;
}
}
}
if(matches == operationInvocations.size() && !identicalMapping) {
return true;
}
return false;
}
private boolean callsExtractedOrInlinedMethodWithVariableDeclarationOrThrow(AbstractCodeMapping mapping, AbstractCall operationInvocation) {
if(operationInvocation != null) {
if(stringBasedInvocationMatch(mapping.getFragment1(), operationInvocation)) {
return true;
}
if(stringBasedInvocationMatch(mapping.getFragment2(), operationInvocation)) {
return true;
}
}
return false;
}
private boolean stringBasedInvocationMatch(AbstractCodeFragment callFragment, AbstractCall operationInvocation) {
AbstractCall invocation = callFragment.invocationCoveringEntireFragment();
if(invocation == null) {
invocation = callFragment.fieldAssignmentInvocationCoveringEntireStatement(classDiff);
if(invocation != null && invocation.actualString().equals(operationInvocation.actualString())) {
return true;
}
}
if(invocation == null && callFragment.getVariableDeclarations().size() > 0) {
for(AbstractCall call : callFragment.getMethodInvocations()) {
if(call.actualString().equals(operationInvocation.actualString())) {
return true;
}
}
}
if(invocation != null && invocation.actualString().equals(operationInvocation.actualString())) {
if(invocation.getCoverage().equals(StatementCoverageType.VARIABLE_DECLARATION_INITIALIZER_CALL)) {
return true;
}
String expression = invocation.getExpression();
if(expression != null && !expression.equals("this")) {
return true;
}
}
if(invocation != null) {
for(String argument : invocation.arguments()) {
if(argument.contains(operationInvocation.actualString())) {
return true;
}
}
if(invocation.getExpression() != null && invocation.getExpression().equals(operationInvocation.actualString())) {
return true;
}
}
AbstractCall creation = callFragment.creationCoveringEntireFragment();
if(creation != null && creation.actualString().contains(operationInvocation.actualString())) {
return true;
}
return false;
}
private int matchingParentMappers(List parentMappers) {
int matchingParentMappers = 1;
for(int i=1; i nestedMapper, List identical,
List exactMappingsNestedUnderCompositeExcludingBlocks,
List replacementTypeCount, List replacementCoversEntireStatement,
List extractInlineOverlappingRefactoring, Set indicesToBeRemoved, List editDistances) {
if(indicesToBeRemoved.isEmpty()) {
if(nestedMapper.contains(false)) {
double editDistanceFalseNestedMapper = editDistances.get(nestedMapper.indexOf(false));
for(int i=0; i editDistanceFalseNestedMapper) {
indicesToBeRemoved.add(i);
}
}
}
if(identical.contains(true)) {
for(int i=0; i minimum && !extractInlineOverlappingRefactoring.get(i) == true) {
indicesToBeRemoved.add(i);
}
}
}
if(indicesToBeRemoved.isEmpty()) {
double minimumEditDistance = editDistances.get(0);
for(int i=1; i minimumEditDistance) {
indicesToBeRemoved.add(i);
}
}
}
}
}
}
}