All Downloads are FREE. Search and download functionalities are using the official Maven repository.

gr.uom.java.xmi.diff.InlineOperationDetection Maven / Gradle / Ivy

Go to download

RefactoringMiner is a library/API written in Java that can detect refactorings applied in the history of a Java project.

There is a newer version: 3.0.9
Show newest version
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;
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy