gr.uom.java.xmi.diff.InlineOperationDetection Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of refactoring-miner Show documentation
Show all versions of refactoring-miner Show documentation
RefactoringMiner is a library/API written in Java that can detect refactorings applied in the history of a Java project.
package gr.uom.java.xmi.diff;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.refactoringminer.api.RefactoringMinerTimedOutException;
import gr.uom.java.xmi.UMLAnonymousClass;
import gr.uom.java.xmi.UMLOperation;
import gr.uom.java.xmi.UMLType;
import gr.uom.java.xmi.decomposition.AbstractCodeMapping;
import gr.uom.java.xmi.decomposition.OperationInvocation;
import gr.uom.java.xmi.decomposition.StatementObject;
import gr.uom.java.xmi.decomposition.UMLOperationBodyMapper;
public class InlineOperationDetection {
private UMLOperationBodyMapper mapper;
private List removedOperations;
private UMLClassBaseDiff classDiff;
private UMLModelDiff modelDiff;
private List operationInvocations;
private Map callTreeMap = new LinkedHashMap();
public InlineOperationDetection(UMLOperationBodyMapper mapper, List removedOperations, UMLClassBaseDiff classDiff, UMLModelDiff modelDiff) {
this.mapper = mapper;
this.removedOperations = removedOperations;
this.classDiff = classDiff;
this.modelDiff = modelDiff;
this.operationInvocations = getInvocationsInTargetOperationBeforeInline(mapper);
}
public List check(UMLOperation removedOperation) throws RefactoringMinerTimedOutException {
List refactorings = new ArrayList();
if(!mapper.getNonMappedLeavesT2().isEmpty() || !mapper.getNonMappedInnerNodesT2().isEmpty() ||
!mapper.getReplacementsInvolvingMethodInvocation().isEmpty()) {
List removedOperationInvocations = matchingInvocations(removedOperation, operationInvocations, mapper.getOperation1().variableTypeMap());
if(removedOperationInvocations.size() > 0 && !invocationMatchesWithAddedOperation(removedOperationInvocations.get(0), mapper.getOperation1().variableTypeMap(), mapper.getOperation2().getAllOperationInvocations())) {
OperationInvocation removedOperationInvocation = removedOperationInvocations.get(0);
CallTreeNode root = new CallTreeNode(mapper.getOperation1(), removedOperation, removedOperationInvocation);
CallTree callTree = null;
if(callTreeMap.containsKey(root)) {
callTree = callTreeMap.get(root);
}
else {
callTree = new CallTree(root);
generateCallTree(removedOperation, root, callTree);
callTreeMap.put(root, callTree);
}
UMLOperationBodyMapper operationBodyMapper = createMapperForInlinedMethod(mapper, removedOperation, removedOperationInvocation);
List additionalExactMatches = new ArrayList();
List nodesInBreadthFirstOrder = callTree.getNodesInBreadthFirstOrder();
for(int i=1; i nestedMatchingInvocations = matchingInvocations(node.getInvokedOperation(), node.getOriginalOperation().getAllOperationInvocations(), node.getOriginalOperation().variableTypeMap());
InlineOperationRefactoring nestedRefactoring = new InlineOperationRefactoring(nestedMapper, mapper.getOperation1(), nestedMatchingInvocations);
refactorings.add(nestedRefactoring);
operationBodyMapper.addChildMapper(nestedMapper);
}
}
}
if(inlineMatchCondition(operationBodyMapper)) {
InlineOperationRefactoring inlineOperationRefactoring = new InlineOperationRefactoring(operationBodyMapper, mapper.getOperation1(), removedOperationInvocations);
refactorings.add(inlineOperationRefactoring);
}
}
}
return refactorings;
}
private List matchingInvocations(UMLOperation removedOperation, List operationInvocations, Map variableTypeMap) {
List removedOperationInvocations = new ArrayList();
for(OperationInvocation invocation : operationInvocations) {
if(invocation.matchesOperation(removedOperation, variableTypeMap, modelDiff)) {
removedOperationInvocations.add(invocation);
}
}
return removedOperationInvocations;
}
private UMLOperationBodyMapper createMapperForInlinedMethod(UMLOperationBodyMapper mapper,
UMLOperation removedOperation, OperationInvocation removedOperationInvocation) throws RefactoringMinerTimedOutException {
List arguments = removedOperationInvocation.getArguments();
List parameters = removedOperation.getParameterNameList();
Map parameterToArgumentMap = new LinkedHashMap();
//special handling for methods with varargs parameter for which no argument is passed in the matching invocation
int size = Math.min(arguments.size(), parameters.size());
for(int i=0; i invocations = operation.getAllOperationInvocations();
for(UMLOperation removedOperation : removedOperations) {
for(OperationInvocation invocation : invocations) {
if(invocation.matchesOperation(removedOperation, operation.variableTypeMap(), modelDiff)) {
if(!callTree.contains(removedOperation)) {
CallTreeNode node = new CallTreeNode(operation, removedOperation, invocation);
parent.addChild(node);
generateCallTree(removedOperation, node, callTree);
}
}
}
}
}
private List getInvocationsInTargetOperationBeforeInline(UMLOperationBodyMapper mapper) {
List operationInvocations = mapper.getOperation1().getAllOperationInvocations();
for(StatementObject statement : mapper.getNonMappedLeavesT1()) {
ExtractOperationDetection.addStatementInvocations(operationInvocations, statement);
for(UMLAnonymousClass anonymousClass : classDiff.getRemovedAnonymousClasses()) {
if(statement.getLocationInfo().subsumes(anonymousClass.getLocationInfo())) {
for(UMLOperation anonymousOperation : anonymousClass.getOperations()) {
for(OperationInvocation anonymousInvocation : anonymousOperation.getAllOperationInvocations()) {
if(!ExtractOperationDetection.containsInvocation(operationInvocations, anonymousInvocation)) {
operationInvocations.add(anonymousInvocation);
}
}
}
}
}
}
return operationInvocations;
}
private boolean inlineMatchCondition(UMLOperationBodyMapper operationBodyMapper) {
int delegateStatements = 0;
for(StatementObject statement : operationBodyMapper.getNonMappedLeavesT1()) {
OperationInvocation invocation = statement.invocationCoveringEntireFragment();
if(invocation != null && invocation.matchesOperation(operationBodyMapper.getOperation1())) {
delegateStatements++;
}
}
int mappings = operationBodyMapper.mappingsWithoutBlocks();
int nonMappedElementsT1 = operationBodyMapper.nonMappedElementsT1()-delegateStatements;
List exactMatchList = operationBodyMapper.getExactMatches();
int exactMatches = exactMatchList.size();
return mappings > 0 && (mappings > nonMappedElementsT1 ||
(exactMatches == 1 && !exactMatchList.get(0).getFragment1().throwsNewException() && nonMappedElementsT1-exactMatches < 10) ||
(exactMatches > 1 && nonMappedElementsT1-exactMatches < 20));
}
private boolean invocationMatchesWithAddedOperation(OperationInvocation removedOperationInvocation, Map variableTypeMap, List operationInvocationsInNewMethod) {
if(operationInvocationsInNewMethod.contains(removedOperationInvocation)) {
for(UMLOperation addedOperation : classDiff.getAddedOperations()) {
if(removedOperationInvocation.matchesOperation(addedOperation, variableTypeMap, modelDiff)) {
return true;
}
}
}
return false;
}
}