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

gr.uom.java.xmi.decomposition.AbstractCall Maven / Gradle / Ivy

package gr.uom.java.xmi.decomposition;

import static gr.uom.java.xmi.Constants.JAVA;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.CompilationUnit;

import gr.uom.java.xmi.LeafType;
import gr.uom.java.xmi.LocationInfo.CodeElementType;
import gr.uom.java.xmi.VariableDeclarationContainer;
import static gr.uom.java.xmi.decomposition.StringBasedHeuristics.SPLIT_CONCAT_STRING_PATTERN;
import gr.uom.java.xmi.decomposition.replacement.CompositeReplacement;
import gr.uom.java.xmi.decomposition.replacement.MergeVariableReplacement;
import gr.uom.java.xmi.decomposition.replacement.MethodInvocationReplacement;
import gr.uom.java.xmi.decomposition.replacement.Replacement;
import gr.uom.java.xmi.decomposition.replacement.VariableReplacementWithMethodInvocation;
import gr.uom.java.xmi.decomposition.replacement.VariableReplacementWithMethodInvocation.Direction;
import gr.uom.java.xmi.decomposition.replacement.Replacement.ReplacementType;
import gr.uom.java.xmi.diff.UMLAbstractClassDiff;
import gr.uom.java.xmi.diff.UMLModelDiff;

public abstract class AbstractCall extends LeafExpression {
	protected int numberOfArguments;
	protected String expression;
	protected List arguments;
	protected StatementCoverageType coverage = StatementCoverageType.NONE;
	private static final List logNames = List.of("trace", "debug", "info", "warn", "error", "fatal", "log");
	private static final List logGuardNames = List.of("isDebugEnabled", "isEnabled", "isErrorEnabled", "isFatalEnabled", "isInfoEnabled", "isTraceEnabled", "isWarnEnabled");

	public AbstractCall(CompilationUnit cu, String filePath, ASTNode expression, CodeElementType codeElementType, VariableDeclarationContainer container) {
		super(cu, filePath, expression, codeElementType, container);
	}

	protected AbstractCall() {
		
	}

	public LeafExpression asLeafExpression() {
		return new LeafExpression(getString(), getLocationInfo());
	}

	public String getExpression() {
		return expression;
	}

	public List arguments() {
		return arguments;
	}

	public StatementCoverageType getCoverage() {
		return coverage;
	}

	public boolean isSuperCall() {
		if(expression != null && expression.equals("super")) {
			return true;
		}
		if(getName().equals("super")) {
			return true;
		}
		return false;
	}

	public abstract boolean identicalName(AbstractCall call);
	public abstract String getName();
	public abstract double normalizedNameDistance(AbstractCall call);
	public abstract AbstractCall update(String oldExpression, String newExpression);
	
	public boolean matchesOperation(VariableDeclarationContainer operation, VariableDeclarationContainer callerOperation,
			UMLAbstractClassDiff classDiff, UMLModelDiff modelDiff) {
		if(this instanceof OperationInvocation) {
			return ((OperationInvocation)this).matchesOperation(operation, callerOperation, classDiff, modelDiff);
		}
		else if(this instanceof MethodReference) {
			MethodReference methodReference = (MethodReference)this;
			return methodReference.getName().equals(operation.getName());
		}
		return false;
	}

	public boolean compatibleExpression(AbstractCall other) {
		if(this instanceof OperationInvocation && other instanceof OperationInvocation) {
			return ((OperationInvocation)this).compatibleExpression((OperationInvocation)other);
		}
		else {
			if(this.expression != null && other.expression != null) {
				return this.expression.equals(other.expression);
			}
			return false;
		}
	}

	public boolean differentExpressionNameAndArguments(AbstractCall other) {
		boolean differentExpression = false;
		if(this.expression == null && other.expression != null)
			differentExpression = true;
		if(this.expression != null && other.expression == null)
			differentExpression = true;
		if(this.expression != null && other.expression != null)
			differentExpression = !this.expression.equals(other.expression) &&
			!this.expression.startsWith(other.expression) && !other.expression.startsWith(this.expression);
		boolean differentName = !this.getName().equals(other.getName());
		Set argumentIntersection = new LinkedHashSet(this.arguments);
		argumentIntersection.retainAll(other.arguments);
		boolean argumentFoundInExpression = false;
		if(this.expression != null) {
			for(String argument : other.arguments) {
				if(this.expression.contains(argument)) {
					argumentFoundInExpression = true;
				}
			}
		}
		if(other.expression != null) {
			for(String argument : this.arguments) {
				if(other.expression.contains(argument)) {
					argumentFoundInExpression = true;
				}
			}
		}
		boolean differentArguments = !this.arguments.equals(other.arguments) &&
				argumentIntersection.isEmpty() && !argumentFoundInExpression;
		return differentExpression && differentName && differentArguments;
	}

	public String actualString() {
		StringBuilder sb = new StringBuilder();
		if(expression != null) {
			sb.append(expression).append(".");
		}
		sb.append(getName());
		sb.append("(");
		int size = arguments.size();
		if(size > 0) {
			for(int i=0; i replacements, Map parameterToArgumentMap) {
		return identicalExpression(call) ||
		identicalExpressionAfterTypeReplacements(call, replacements, parameterToArgumentMap) ||
		identicalExpressionAfterArgumentAddition(call, replacements);
	}

	public boolean identicalExpression(AbstractCall call) {
		return (getExpression() != null && call.getExpression() != null &&
				getExpression().equals(call.getExpression())) ||
				(getExpression() == null && call.getExpression() == null);
	}

	private boolean identicalExpressionAfterArgumentAddition(AbstractCall call, Set replacements) {
		if(getExpression() != null && call.getExpression() != null) {
			int methodInvocationReplacements = 0;
			int argumentAdditionReplacements = 0;
			for(Replacement replacement : replacements) {
				if(replacement instanceof MethodInvocationReplacement) {
					if(getExpression().contains(replacement.getBefore()) && call.getExpression().contains(replacement.getAfter())) {
						methodInvocationReplacements++;
						MethodInvocationReplacement r = (MethodInvocationReplacement)replacement;
						AbstractCall callBefore = r.getInvokedOperationBefore();
						AbstractCall callAfter = r.getInvokedOperationAfter();
						Set argumentIntersection = callBefore.argumentIntersection(callAfter);
						if(argumentIntersection.size() > 0 &&
								argumentIntersection.size() == Math.min(new LinkedHashSet<>(callBefore.arguments()).size(), new LinkedHashSet<>(callAfter.arguments()).size()) &&
								callBefore.arguments().size() != callAfter.arguments().size()) {
							argumentAdditionReplacements++;
						}
					}
				}
			}
			if(methodInvocationReplacements == argumentAdditionReplacements && methodInvocationReplacements > 0) {
				return true;
			}
		}
		return false;
	}

	private boolean identicalExpressionAfterTypeReplacements(AbstractCall call, Set replacements, Map parameterToArgumentMap) {
		if(getExpression() != null && call.getExpression() != null) {
			String expression1 = getExpression();
			String expression2 = call.getExpression();
			String expression1AfterReplacements = new String(expression1);
			for(Replacement replacement : replacements) {
				if(replacement.getType().equals(ReplacementType.TYPE) ||
						//allow only class names corresponding to static calls
						(replacement.getType().equals(ReplacementType.VARIABLE_NAME) && expressionCondition(expression1, expression2, parameterToArgumentMap))) {
					if(replacement.getBefore().equals(expression1) && (replacement.getAfter().equals(expression2) ||
							(parameterToArgumentMap.containsKey(expression2) && replacement.getAfter().equals(parameterToArgumentMap.get(expression2))))) {
						return true;
					}
					expression1AfterReplacements = ReplacementUtil.performReplacement(expression1AfterReplacements, expression2, replacement.getBefore(), replacement.getAfter());
				}
				else if(replacement instanceof MethodInvocationReplacement) {
					MethodInvocationReplacement methodInvocationReplacement = (MethodInvocationReplacement)replacement;
					AbstractCall before = methodInvocationReplacement.getInvokedOperationBefore();
					AbstractCall after = methodInvocationReplacement.getInvokedOperationAfter();
					if(before.identicalExpression(after) && before.equalArguments(after) && before.arguments.size() > 0) {
						if(expression1.equals(replacement.getBefore()) && expression2.equals(replacement.getAfter())) {
							return true;
						}
					}
				}
				else if(replacement instanceof VariableReplacementWithMethodInvocation) {
					VariableReplacementWithMethodInvocation methodInvocationReplacement = (VariableReplacementWithMethodInvocation)replacement;
					AbstractCall invokedOperation = methodInvocationReplacement.getInvokedOperation();
					if(invokedOperation.actualString().contains("(")) {
						String subString = invokedOperation.actualString().substring(0, invokedOperation.actualString().indexOf("("));
						if(replacement.getBefore().startsWith(subString) && replacement.getAfter().startsWith(subString)) {
							if(replacement.getBefore().equals(expression1) && (replacement.getAfter().equals(expression2) ||
									(parameterToArgumentMap.containsKey(expression2) && replacement.getAfter().equals(parameterToArgumentMap.get(expression2))))) {
								return true;
							}
						}
					}
				}
			}
			if(expression1AfterReplacements.equals(expression2)) {
				return true;
			}
		}
		return false;
	}

	private boolean expressionCondition(String expression1, String expression2, Map parameterToArgumentMap) {
		if(Character.isUpperCase(expression1.charAt(0)) && Character.isUpperCase(expression2.charAt(0))) {
			return true;
		}
		else if(Character.isUpperCase(expression1.charAt(0)) && !Character.isUpperCase(expression2.charAt(0)) && parameterToArgumentMap.containsKey(expression2)) {
			return true;
		}
		return false;
	}

	public boolean staticInvokerExpressionReplaced(AbstractCall call, Set replacements) {
		if(getExpression() != null && call.getExpression() != null) {
			String expression1 = getExpression();
			String expression2 = call.getExpression();
			for(Replacement replacement : replacements) {
				if(replacement.getBefore().equals(expression1) && replacement.getAfter().equals(expression2)) {
					if(Character.isUpperCase(expression1.charAt(0)) && Character.isUpperCase(expression2.charAt(0))) {
						return true;
					}
				}
			}
		}
		return false;
	}

	public boolean equalArgumentsExceptForAnonymousClassArguments(AbstractCall call) {
		List arguments1 = arguments();
		List arguments2 = call.arguments();
		if(arguments1.size() != arguments2.size())
			return false;
		int anonymousClassArguments1 = 0;
		int anonymousClassArguments2 = 0; 
		for(int i=0; i 0;
	}

	public boolean equalArgumentsExceptForStringLiterals(AbstractCall call) {
		List arguments1 = arguments();
		List arguments2 = call.arguments();
		if(arguments1.size() != arguments2.size())
			return false;
		int stringLiterals1 = 0;
		int stringLiterals2 = 0;
		for(int i=0; i 0;
	}

	public boolean isStringLiteral(String argument) {
		return (argument.startsWith("\"") && argument.endsWith("\"")) ||
				(argument.contains("(\"") && argument.endsWith("\")"));
	}

	public boolean equalArguments(AbstractCall call) {
		if(this instanceof MethodReference && call instanceof MethodReference) {
			if(!this.identicalName(call)) {
				return false;
			}
		}
		return arguments().equals(call.arguments());
	}

	public boolean reorderedArguments(AbstractCall call) {
		return arguments().size() > 1 && arguments().size() == call.arguments().size() &&
				!arguments().equals(call.arguments()) && arguments().containsAll(call.arguments());
	}

	public boolean identicalOrReplacedArguments(AbstractCall call, Set replacements, List lambdaMappers) {
		List arguments1 = arguments();
		List arguments2 = call.arguments();
		if(arguments1.size() != arguments2.size())
			return false;
		if(this instanceof MethodReference && call instanceof MethodReference) {
			if(!this.identicalName(call)) {
				return false;
			}
		}
		for(int i=0; i arguments1 = arguments();
		List arguments2 = call.arguments();
		if(arguments1.size() != arguments2.size())
			return false;
		for(int i=0; i tokens1 = new LinkedHashSet(Arrays.asList(SPLIT_CONCAT_STRING_PATTERN.split(argument1)));
				Set tokens2 = new LinkedHashSet(Arrays.asList(SPLIT_CONCAT_STRING_PATTERN.split(argument2)));
				Set intersection = new LinkedHashSet(tokens1);
				intersection.retainAll(tokens2);
				int size = intersection.size();
				int threshold = Math.max(tokens1.size(), tokens2.size()) - size;
				if(size > 0 && size >= threshold) {
					argumentConcatenated = true;
				}
			}
			if(!argument1.equals(argument2) && !argumentConcatenated)
				return false;
		}
		return true;
	}

	public boolean identicalOrWrappedArguments(AbstractCall call) {
		List arguments1 = arguments();
		List arguments2 = call.arguments();
		if(arguments1.size() != arguments2.size())
			return false;
		for(int i=0; i replacements) {
		int replacedArguments = 0;
		List arguments1 = arguments();
		List arguments2 = call.arguments();
		if(arguments1.size() == arguments2.size()) {
			for(int i=0; i 0 && replacedArguments == arguments1.size();
	}

	public boolean allArgumentsReplaced(AbstractCall call, Set replacements, Map parameterToArgumentMap) {
		int replacedArguments = 0;
		List arguments1 = arguments();
		List arguments2 = call.arguments();
		if(arguments1.size() == arguments2.size()) {
			for(int i=0; i 0 && replacedArguments == arguments1.size();
	}

	public boolean renamedWithIdenticalExpressionAndArguments(AbstractCall call, Set replacements, Map parameterToArgumentMap, double distance,
			List lambdaMappers, boolean matchPairOfRemovedAddedOperationsWithIdenticalBody, boolean argumentsWithVariableDeclarationMapping) {
		boolean identicalOrReplacedArguments = identicalOrReplacedArguments(call, replacements, lambdaMappers);
		boolean allArgumentsReplaced = allArgumentsReplaced(call, replacements);
		return ((getExpression() != null && call.getExpression() != null) || matchPairOfRemovedAddedOperationsWithIdenticalBody) &&
				identicalExpression(call, replacements, parameterToArgumentMap) &&
				!identicalName(call) &&
				(equalArguments(call) || reorderedArguments(call) || (allArgumentsReplaced && compatibleName(call, distance)) || (identicalOrReplacedArguments && !allArgumentsReplaced) || argumentsWithVariableDeclarationMapping);
	}

	public boolean variableDeclarationInitializersRenamedWithIdenticalArguments(AbstractCall call) {
		return this.coverage.equals(StatementCoverageType.VARIABLE_DECLARATION_INITIALIZER_CALL) &&
				call.coverage.equals(StatementCoverageType.VARIABLE_DECLARATION_INITIALIZER_CALL) &&
				getExpression() != null && call.getExpression() != null &&
				!identicalName(call) && (equalArguments(call) || reorderedArguments(call) || this.arguments().size() == 0 || call.arguments().size() == 0);
	}

	public boolean renamedWithDifferentExpressionAndIdenticalArguments(AbstractCall call, Set replacements, Map parameterToArgumentMap) {
		boolean expressionBecomesArgument = false;
		int commonTokens = 0;
		if(this.getExpression() != null && call.getExpression() == null && call.arguments().contains(this.getExpression())) {
			expressionBecomesArgument = true;
			String[] tokens1 = LeafType.CAMEL_CASE_SPLIT_PATTERN.split(this.getName());
			String[] tokens2 = LeafType.CAMEL_CASE_SPLIT_PATTERN.split(call.getName());
			for(String token1 : tokens1) {
				for(String token2 : tokens2) {
					if(token1.equals(token2)) {
						commonTokens++;
					}
				}
			}
		}
		else if(this.getExpression() == null && call.getExpression() != null && this.arguments().contains(call.getExpression())) {
			expressionBecomesArgument = true;
			String[] tokens1 = LeafType.CAMEL_CASE_SPLIT_PATTERN.split(this.getName());
			String[] tokens2 = LeafType.CAMEL_CASE_SPLIT_PATTERN.split(call.getName());
			for(String token1 : tokens1) {
				for(String token2 : tokens2) {
					if(token1.equals(token2)) {
						commonTokens++;
					}
				}
			}
		}
		return (oneNameContainsTheOther(call) || (expressionBecomesArgument && commonTokens > 1)) &&
				this.arguments.size() > 0 && call.arguments.size() > 0 && (equalArguments(call) || reorderedArguments(call) ||
				argumentIntersectionSize(call, replacements, parameterToArgumentMap) == Math.min(this.arguments.size(), call.arguments.size())) &&
				((this.getExpression() == null && call.getExpression() != null) || (call.getExpression() == null && this.getExpression() != null));
	}

	public boolean renamedWithNoExpressionAndArgumentIntersection(AbstractCall call, Set replacements, Map parameterToArgumentMap, boolean possiblyRenamedBasedOnClassDiff) {
		int argumentIntersectionSize = argumentIntersection(call).size();
		return (oneNameContainsTheOther(call) || (possiblyRenamedBasedOnClassDiff && (equalArguments(call) || commonTokens(call)))) &&
				(this.getExpression() == null && call.getExpression() == null) &&
				this.arguments.size() > 0 && call.arguments.size() > 0 &&
				(argumentIntersectionSize >= Math.floor(Math.min(this.arguments.size(), call.arguments.size())/2) ||
				(argumentIntersectionSize > 0 && this.getName().equals("super") && call.getName().equals("super")) ||
				argumentIntersectionSize(call, replacements, parameterToArgumentMap) == Math.min(this.arguments.size(), call.arguments.size()));
	}

	private boolean oneNameContainsTheOther(AbstractCall call) {
		return this.getName().contains(call.getName()) || call.getName().contains(this.getName());
	}

	public boolean renamedWithIdenticalArgumentsAndNoExpression(AbstractCall call, double distance, List lambdaMappers) {
		boolean allExactLambdaMappers = lambdaMappers.size() > 0;
		for(UMLOperationBodyMapper lambdaMapper : lambdaMappers) {
			if(!lambdaMapper.allMappingsAreExactMatches()) {
				allExactLambdaMappers = false;
				break;
			}
		}
		return getExpression() == null && call.getExpression() == null &&
				!identicalName(call) &&
				(compatibleName(call, distance) || allExactLambdaMappers) &&
				(equalArguments(call) || reorderedArguments(call));
	}

	public boolean renamedWithIdenticalExpressionAndDifferentArguments(AbstractCall call, Set replacements, Map parameterToArgumentMap, double distance, List lambdaMappers) {
		boolean allExactLambdaMappers = lambdaMappers.size() > 0;
		for(UMLOperationBodyMapper lambdaMapper : lambdaMappers) {
			if(!lambdaMapper.allMappingsAreExactMatches()) {
				allExactLambdaMappers = false;
				break;
			}
		}
		return getExpression() != null && call.getExpression() != null &&
				identicalExpression(call, replacements, parameterToArgumentMap) &&
				(normalizedNameDistance(call) <= distance || allExactLambdaMappers || (this.methodNameContainsArgumentName() && call.methodNameContainsArgumentName()) || argumentIntersectionContainsClassInstanceCreation(call)) &&
				!equalArguments(call) &&
				!this.argumentContainsAnonymousClassDeclaration() && !call.argumentContainsAnonymousClassDeclaration();
	}

	private boolean compatibleName(AbstractCall call, double distance) {
		if(normalizedNameDistance(call) <= distance) {
			return true;
		}
		return compatibleName(call);
	}

	private boolean commonTokens(AbstractCall call) {
		String[] tokens1 = LeafType.CAMEL_CASE_SPLIT_PATTERN.split(this.getName());
		String[] tokens2 = LeafType.CAMEL_CASE_SPLIT_PATTERN.split(call.getName());
		int commonTokens = 0;
		for(String token1 : tokens1) {
			for(String token2 : tokens2) {
				if(token1.equals(token2)) {
					commonTokens++;
				}
			}
		}
		if(commonTokens == Math.min(tokens1.length, tokens2.length)) {
			return true;
		}
		return false;
	}

	public boolean compatibleName(AbstractCall call) {
		if(commonTokens(call)) {
			return true;
		}
		if(this.loggerExpression() && call.loggerExpression() && this.getExpression().equals(call.getExpression())) {
			if(this.matchesLogName() && call.matchesLogName()) {
				if(this.arguments().size() == call.arguments().size() && this.arguments().size() == 1) {
					String argument1 = this.arguments().get(0);
					String argument2 = call.arguments().get(0);
					List words1 = extractWords(argument1);
					List words2 = extractWords(argument2);
					int commonWords = 0;
					if(words1.size() <= words2.size()) {
						int index = 0;
						for(String word1 : words1) {
							if(words2.contains(word1)) {
								commonWords++;
							}
							if(word1.equals(words2.get(index) + "ing") || words2.get(index).equals(word1 + "ing")) {
								commonWords++;
							}
							index++;
						}
					}
					else {
						int index = 0;
						for(String word2 : words2) {
							if(words1.contains(word2)) {
								commonWords++;
							}
							if(word2.equals(words1.get(index) + "ing") || words1.get(index).equals(word2 + "ing")) {
								commonWords++;
							}
							index++;
						}
					}
					if(commonWords >= Math.max(words1.size(), words2.size())/2) {
						return true;
					}
				}
			}
		}
		return false;
	}

	private static List extractWords(String argument) {
		String[] initialWords = argument.split("\\s");
		List finalWords = new ArrayList<>();
		for(String word : initialWords) {
			//remove " : . , from the beginning and end of the string
			String w = word.replaceAll("^\"|\"$", "").replaceAll("^\\.|\\.$", "").replaceAll("^\\:|\\:$", "").replaceAll("^\\,|\\,$", "");
			if(!w.equals("+") && !w.equals("")) {
				finalWords.add(w);
			}
		}
		return finalWords;
	}

	private boolean argumentIntersectionContainsClassInstanceCreation(AbstractCall call) {
		for(String argument : argumentIntersection(call)) {
			if(argument.startsWith("new ")) {
				return true;
			}
		}
		return false;
	}

	private boolean argumentContainsAnonymousClassDeclaration() {
		for(String argument : arguments) {
			if(argument.contains("{\n")) {
				return true;
			}
		}
		return false;
	}

	public boolean methodNameContainsArgumentName() {
		for(String argument : arguments) {
			if(getName().toLowerCase().endsWith(argument.toLowerCase())) {
				return true;
			}
		}
		return false;
	}

	private boolean onlyArgumentsChanged(AbstractCall call, Set replacements, Map parameterToArgumentMap) {
		return identicalExpression(call, replacements, parameterToArgumentMap) &&
				identicalName(call) &&
				!equalArguments(call) &&
				arguments().size() != call.arguments().size();
	}

	public boolean identicalWithOnlyChangesInAnonymousClassArguments(AbstractCall call, Set replacements, Map parameterToArgumentMap) {
		return identicalExpression(call, replacements, parameterToArgumentMap) &&
				identicalName(call) && !equalArguments(call) &&
				arguments().size() == call.arguments().size() &&
				equalArgumentsExceptForAnonymousClassArguments(call);
	}

	public boolean identicalWithMergedArguments(AbstractCall call, Set replacements, Map parameterToArgumentMap) {
		if(onlyArgumentsChanged(call, replacements, parameterToArgumentMap)) {
			List updatedArguments1 = new ArrayList(this.arguments);
			Map> commonVariableReplacementMap = new LinkedHashMap>();
			for(Replacement replacement : replacements) {
				if(replacement.getType().equals(ReplacementType.VARIABLE_NAME)) {
					String key = replacement.getAfter();
					if(commonVariableReplacementMap.containsKey(key)) {
						commonVariableReplacementMap.get(key).add(replacement);
						int index = updatedArguments1.indexOf(replacement.getBefore());
						if(index != -1) {
							updatedArguments1.remove(index);
						}
					}
					else {
						Set r = new LinkedHashSet();
						r.add(replacement);
						commonVariableReplacementMap.put(key, r);
						int index = updatedArguments1.indexOf(replacement.getBefore());
						if(index != -1) {
							updatedArguments1.remove(index);
							updatedArguments1.add(index, key);
						}
					}
				}
			}
			if(updatedArguments1.equals(call.arguments)) {
				for(String key : commonVariableReplacementMap.keySet()) {
					Set r = commonVariableReplacementMap.get(key);
					if(r.size() > 1) {
						replacements.removeAll(r);
						Set mergedVariables = new LinkedHashSet();
						for(Replacement replacement : r) {
							mergedVariables.add(replacement.getBefore());
						}
						MergeVariableReplacement merge = new MergeVariableReplacement(mergedVariables, key);
						replacements.add(merge);
					}
				}
				return true;
			}
		}
		return false;
	}

	public boolean identicalWithDifferentNumberOfArguments(AbstractCall call, Set replacements, Map parameterToArgumentMap) {
		if(onlyArgumentsChanged(call, replacements, parameterToArgumentMap)) {
			int argumentIntersectionSize = argumentIntersectionSize(call, replacements, parameterToArgumentMap);
			if(argumentIntersectionSize > 0 || arguments().size() == 0 || call.arguments().size() == 0) {
				return true;
			}
		}
		return false;
	}

	public boolean inlinedStatementBecomesAdditionalArgument(AbstractCall call, Set replacements, List statements) {
		if(identicalName(call) && this.arguments.size() < call.arguments.size() && this.argumentIntersection(call).size() > 0) {
			int matchedArguments = 0;
			Set additionallyMatchedStatements1 = new LinkedHashSet<>();
			for(String arg : call.arguments) {
				if(this.arguments.contains(arg)) {
					matchedArguments++;
				}
				else {
					for(AbstractCodeFragment statement : statements) {
						if(statement.getVariableDeclarations().size() > 0) {
							VariableDeclaration variableDeclaration = statement.getVariableDeclarations().get(0);
							if(variableDeclaration.getInitializer() != null) {
								if(arg.equals(variableDeclaration.getInitializer().getExpression())) {
									matchedArguments++;
									additionallyMatchedStatements1.add(statement);
									break;
								}
							}
						}
					}
				}
			}
			if(matchedArguments == call.arguments.size()) {
				if(additionallyMatchedStatements1.size() > 0) {
					CompositeReplacement r = new CompositeReplacement(this.actualString(), call.actualString(), additionallyMatchedStatements1, Collections.emptySet());
					replacements.add(r);
				}
				return true;
			}
		}
		return false;
	}

	public boolean identicalWithInlinedStatements(AbstractCall call, Set replacements, Map parameterToArgumentMap, List statements) {
		if(identicalExpression(call, replacements, parameterToArgumentMap) && identicalName(call)) {
			if(this.arguments.size() == call.arguments.size()) {
				Set newReplacements = new LinkedHashSet();
				Set additionallyMatchedStatements1 = new LinkedHashSet<>();
				for(int i=0; i 0) {
								VariableDeclaration variableDeclaration = statement.getVariableDeclarations().get(0);
								if(variableDeclaration.getVariableName().equals(arg1) && variableDeclaration.getInitializer() != null) {
									AbstractCall statementCall = variableDeclaration.getInitializer().invocationCoveringEntireFragment();
									if(variableDeclaration.getInitializer().getExpression().equals(arg2)) {
										matchingInlineFound = true;
										if(statementCall != null) {
											Replacement r = new VariableReplacementWithMethodInvocation(arg1, variableDeclaration.getInitializer().getExpression(), statementCall, Direction.VARIABLE_TO_INVOCATION);
											newReplacements.add(r);
										}
										else {
											Replacement r = new Replacement(arg1, variableDeclaration.getInitializer().getExpression(), ReplacementType.VARIABLE_NAME);
											newReplacements.add(r);
										}
										additionallyMatchedStatements1.add(statement);
										break;
									}
									if(statementCall != null) {
										String actualString = statementCall.actualString();
										if(arg2.contains(actualString) || actualString.contains(arg2)) {
											matchingInlineFound = true;
											Replacement r = new VariableReplacementWithMethodInvocation(arg1, variableDeclaration.getInitializer().getExpression(), statementCall, Direction.VARIABLE_TO_INVOCATION);
											newReplacements.add(r);
											additionallyMatchedStatements1.add(statement);
											break;
										}
										if(actualString.contains(".") && arg2.contains(".") &&
												actualString.substring(actualString.indexOf(".")).equals(arg2.substring(arg2.indexOf(".")))) {
											matchingInlineFound = true;
											Replacement r = new VariableReplacementWithMethodInvocation(arg1, variableDeclaration.getInitializer().getExpression(), statementCall, Direction.VARIABLE_TO_INVOCATION);
											newReplacements.add(r);
											additionallyMatchedStatements1.add(statement);
											String invoker = actualString.substring(0, actualString.indexOf("."));
											if(invoker.equals(statementCall.getExpression())) {
												String arg2Invoker = arg2.substring(0, arg2.indexOf("."));
												Replacement rename = new Replacement(invoker, arg2Invoker, ReplacementType.VARIABLE_NAME);
												newReplacements.add(rename);
											}
											break;
										}
									}
								}
							}
						}
						if(!matchingInlineFound) {
							return false;
						}
					}
				}
				for(Replacement r : newReplacements) {
					if(!replacements.contains(r)) {
						replacements.add(r);
					}
				}
				if(additionallyMatchedStatements1.size() > 0) {
					CompositeReplacement r = new CompositeReplacement(this.actualString(), call.actualString(), additionallyMatchedStatements1, Collections.emptySet());
					replacements.add(r);
				}
				return true;
			}
		}
		return false;
	}

	public boolean identicalWithExpressionArgumentSwap(AbstractCall call) {
		if(getExpression() != null && call.getExpression() != null && (identicalName(call) || oneNameContainsTheOther(call))) {
			int argumentIndex1 = arguments().indexOf(call.getExpression());
			int argumentIndex2 = call.arguments().indexOf(getExpression());
			if(argumentIndex1 != -1 && argumentIndex2 != -1 && argumentIndex1 == argumentIndex2) {
				Set argumentIntersection = argumentIntersection(call);
				if(argumentIntersection.size() == arguments().size()-1 && argumentIntersection.size() == call.arguments().size()-1) {
					return true;
				}
			}
		}
		return false;
	}

	public boolean identical(AbstractCall call, Set replacements, Map parameterToArgumentMap, List lambdaMappers) {
		return identicalExpression(call, replacements, parameterToArgumentMap) &&
				identicalName(call) &&
				(equalArguments(call) || onlyLambdaArgumentsDiffer(call, lambdaMappers));
	}

	private boolean onlyLambdaArgumentsDiffer(AbstractCall call, List lambdaMappers) {
		if(lambdaMappers.size() > 0) {
			List arguments1 = arguments();
			List arguments2 = call.arguments();
			if(arguments1.size() == arguments2.size()) {
				for(int i=0; i 0 && lambdaMapper.nonMappedElementsT2() > 0 &&
									!lambdaMapper.containsCallToExtractedMethod() && !lambdaMapper.containsCallToInlinedMethod()) {
								return false;
							}
						}
					}
					else if(!argument1.equals(argument2)) {
						return false;
					}
				}
				return true;
			}
		}
		return false;
	}

	public Set argumentIntersection(AbstractCall call) {
		List args1 = preprocessArguments(arguments());
		List args2 = preprocessArguments(call.arguments());
		Set argumentIntersection = new LinkedHashSet(args1);
		argumentIntersection.retainAll(args2);
		return argumentIntersection;
	}

	private List preprocessArguments(List arguments) {
		List args = new ArrayList();
		for(String arg : arguments) {
			if(arg.contains("\n")) {
				args.add(arg.substring(0, arg.indexOf("\n")));
			}
			else {
				args.add(arg);
			}
		}
		return args;
	}

	private int argumentIntersectionSize(AbstractCall call, Set replacements, Map parameterToArgumentMap) {
		Set argumentIntersection = argumentIntersection(call);
		int argumentIntersectionSize = argumentIntersection.size();
		for(String parameter : parameterToArgumentMap.keySet()) {
			String argument = parameterToArgumentMap.get(parameter);
			if(arguments().contains(argument) &&
					call.arguments().contains(parameter)) {
				argumentIntersectionSize++;
			}
		}
		for(Replacement r : replacements) {
			int index1 = arguments().indexOf(r.getBefore());
			int index2 = call.arguments().indexOf(r.getAfter());
			if(index1 == -1 && arguments().contains(r.getBefore() + ".length")) {
				index1 = arguments().indexOf(r.getBefore() + ".length");
			}
			if(index2 == -1 && call.arguments().contains(r.getAfter() + ".length")) {
				index2 = call.arguments().indexOf(r.getAfter() + ".length");
			}
			if(index1 != -1 && index2 != -1) {
				if(arguments().size() == call.arguments().size()) {
					if(index1 == index2) {
						argumentIntersectionSize++;
					}
				}
				else {
					argumentIntersectionSize++;
				}
			}
		}
		return argumentIntersectionSize;
	}

	private int argumentIsStatement(String statement) {
		if(statement.endsWith(JAVA.STATEMENT_TERMINATION)) {
			int index = 0;
			for(String argument : arguments()) {
				if(argument.equals("true") || argument.equals("false") || argument.equals("null")) {
					return -1;
				}
				if(equalsIgnoringExtraParenthesis(argument, statement.substring(0, statement.length()-JAVA.STATEMENT_TERMINATION.length()))) {
					return index;
				}
				index++;
			}
		}
		return -1;
	}

	private int argumentIsExpression(String expression) {
		if(!expression.endsWith(JAVA.STATEMENT_TERMINATION)) {
			//statement is actually an expression
			int index = 0;
			for(String argument : arguments()) {
				if(argument.equals("true") || argument.equals("false") || argument.equals("null")) {
					return -1;
				}
				if(equalsIgnoringExtraParenthesis(argument, expression)) {
					return index;
				}
				index++;
			}
		}
		return -1;
	}

	private int argumentIsReturned(String statement) {
		if(statement.startsWith(JAVA.RETURN_SPACE)) {
			int index = 0;
			for(String argument : arguments()) {
				if(argument.equals("true") || argument.equals("false") || argument.equals("null")) {
					return -1;
				}
				if(equalsIgnoringExtraParenthesis(argument, statement.substring(JAVA.RETURN_SPACE.length(), statement.length()-JAVA.STATEMENT_TERMINATION.length()))) {
					return index;
				}
				index++;
			}
		}
		return -1;
	}

	public Replacement makeReplacementForReturnedArgument(String statement) {
		int index = -1;
		if((index = argumentIsReturned(statement)) != -1 && ((arguments().size() <= 2 && (index == 0 || this.getName().equals("assertThrows"))) || (statement.contains(" ? ") && statement.contains(" : ")))) {
			String arg = statement.substring(JAVA.RETURN_SPACE.length(), statement.length()-JAVA.STATEMENT_TERMINATION.length());
			return new Replacement(arguments().get(index), arg,
					ReplacementType.ARGUMENT_REPLACED_WITH_RETURN_EXPRESSION);
		}
		else if((index = argumentIsStatement(statement)) != -1 && ((arguments().size() <= 2 && (index == 0 || this.getName().equals("assertThrows"))) || (statement.contains(" ? ") && statement.contains(" : ")))) {
			String arg = statement.substring(0, statement.length()-JAVA.STATEMENT_TERMINATION.length());
			return new Replacement(arguments().get(index), arg,
					ReplacementType.ARGUMENT_REPLACED_WITH_STATEMENT);
		}
		else if((index = argumentIsExpression(statement)) != -1 && ((arguments().size() <= 2 && (index == 0 || this.getName().equals("assertThrows"))) || (statement.contains(" ? ") && statement.contains(" : ")))) {
			return new Replacement(arguments().get(index), statement,
					ReplacementType.ARGUMENT_REPLACED_WITH_EXPRESSION);
		}
		return null;
	}

	public Replacement makeReplacementForWrappedCall(String statement) {
		int index = -1;
		if((index = argumentIsReturned(statement)) != -1 && ((arguments().size() <= 2 && (index == 0 || this.getName().equals("assertThrows"))) || (statement.contains(" ? ") && statement.contains(" : ")))) {
			String arg = statement.substring(JAVA.RETURN_SPACE.length(), statement.length()-JAVA.STATEMENT_TERMINATION.length());
			return new Replacement(arg, arguments().get(index),
					ReplacementType.ARGUMENT_REPLACED_WITH_RETURN_EXPRESSION);
		}
		else if((index = argumentIsStatement(statement)) != -1 && ((arguments().size() <= 2 && (index == 0 || this.getName().equals("assertThrows"))) || (statement.contains(" ? ") && statement.contains(" : ")))) {
			String arg = statement.substring(0, statement.length()-JAVA.STATEMENT_TERMINATION.length());
			return new Replacement(arg, arguments().get(index),
					ReplacementType.ARGUMENT_REPLACED_WITH_STATEMENT);
		}
		else if((index = argumentIsExpression(statement)) != -1 && ((arguments().size() <= 2 && (index == 0 || this.getName().equals("assertThrows"))) || (statement.contains(" ? ") && statement.contains(" : ")))) {
			return new Replacement(statement, arguments().get(index),
					ReplacementType.ARGUMENT_REPLACED_WITH_EXPRESSION);
		}
		return null;
	}

	public Replacement makeReplacementForWrappedLambda(String statement) {
		if(argumentIsLambdaStatement(statement) && (arguments().size() == 1 || (statement.contains(" ? ") && statement.contains(" : ")))) {
			return new Replacement(statement.substring(0, statement.length()-JAVA.STATEMENT_TERMINATION.length()), arguments().get(0),
					ReplacementType.ARGUMENT_REPLACED_WITH_EXPRESSION);
		}
		return null;
	}

	private boolean argumentIsLambdaStatement(String statement) {
		if(statement.endsWith(JAVA.STATEMENT_TERMINATION)) {
			for(String argument : arguments()) {
				if(equalsIgnoringLambdaArrow(argument, statement.substring(0, statement.length()-JAVA.STATEMENT_TERMINATION.length()))) {
					return true;
				}
			}
		}
		return false;
	}

	private int argumentIsAssigned(String statement) {
		if(statement.contains(JAVA.ASSIGNMENT) && statement.endsWith(JAVA.STATEMENT_TERMINATION)) {
			int index = 0;
			for(String argument : arguments()) {
				if(equalsIgnoringExtraParenthesis(argument, statement.substring(statement.indexOf(JAVA.ASSIGNMENT)+1, statement.length()-JAVA.STATEMENT_TERMINATION.length()))) {
					return index;
				}
				index++;
			}
		}
		return -1;
	}

	private boolean expressionIsAssigned(String statement) {
		if(statement.contains(JAVA.ASSIGNMENT) && statement.endsWith(JAVA.STATEMENT_TERMINATION) && expression != null) {
			if(equalsIgnoringExtraParenthesis(expression, statement.substring(statement.indexOf(JAVA.ASSIGNMENT)+1, statement.length()-JAVA.STATEMENT_TERMINATION.length()))) {
				return true;
			}
		}
		return false;
	}

	public Replacement makeReplacementForAssignedArgument(String statement) {
		int index = argumentIsAssigned(statement);
		if(index >= 0 && (arguments().size() == 1 || (statement.contains(" ? ") && statement.contains(" : ")))) {
			return new Replacement(statement.substring(statement.indexOf(JAVA.ASSIGNMENT)+1, statement.length()-JAVA.STATEMENT_TERMINATION.length()),
					arguments().get(index), ReplacementType.ARGUMENT_REPLACED_WITH_RIGHT_HAND_SIDE_OF_ASSIGNMENT_EXPRESSION);
		}
		return null;
	}

	public Replacement makeReplacementForAssignedExpression(String statement) {
		if(expressionIsAssigned(statement)) {
			return new Replacement(statement.substring(statement.indexOf(JAVA.ASSIGNMENT)+1, statement.length()-JAVA.STATEMENT_TERMINATION.length()),
					expression, ReplacementType.EXPRESSION_REPLACED_WITH_RIGHT_HAND_SIDE_OF_ASSIGNMENT_EXPRESSION);
		}
		return null;
	}

	private static boolean equalsIgnoringExtraParenthesis(String s1, String s2) {
		if(s1.equals(s2))
			return true;
		String parenthesizedS1 = "("+s1+")";
		if(parenthesizedS1.equals(s2))
			return true;
		String parenthesizedS2 = "("+s2+")";
		if(parenthesizedS2.equals(s1))
			return true;
		if(s1.contains(".<") && !s2.contains(".<")) {
			String s1WithoutGenerics = s1.substring(0, s1.indexOf(".<") + 1) + s1.substring(s1.indexOf(">") + 1, s1.length());
			if(s1WithoutGenerics.equals(s2))
				return true;
		}
		if(s2.contains(".<") && !s1.contains(".<")) {
			String s2WithoutGenerics = s2.substring(0, s2.indexOf(".<") + 1) + s2.substring(s2.indexOf(">") + 1, s2.length());
			if(s2WithoutGenerics.equals(s1))
				return true;
		}
		if(s1.contains(JAVA.METHOD_REFERENCE) && !s2.contains(JAVA.METHOD_REFERENCE)) {
			String methodReferenceName = s1.substring(s1.indexOf(JAVA.METHOD_REFERENCE) + 2, s1.length());
			if(s2.endsWith(methodReferenceName + "()")) {
				return true;
			}
		}
		if(s2.contains(JAVA.METHOD_REFERENCE) && !s1.contains(JAVA.METHOD_REFERENCE)) {
			String methodReferenceName = s2.substring(s2.indexOf(JAVA.METHOD_REFERENCE) + 2, s2.length());
			if(s1.endsWith(methodReferenceName + "()")) {
				return true;
			}
		}
		return false;
	}

	private static boolean equalsIgnoringLambdaArrow(String s1, String s2) {
		if(s1.equals(s2))
			return true;
		String arrowS1 = "() -> " + s1;
		if(arrowS1.equals(s2))
			return true;
		String arrowS2 = "() -> " + s2;
		if(arrowS2.equals(s1))
			return true;
		return false;
	}

	protected void update(AbstractCall newCall, String oldExpression, String newExpression) {
		newCall.numberOfArguments = this.numberOfArguments;
		if(this.expression != null && this.expression.equals(oldExpression)) {
			newCall.expression = newExpression;
		}
		else {
			newCall.expression = this.expression;
		}
		newCall.arguments = new ArrayList();
		for(String argument : this.arguments) {
			newCall.arguments.add(
				ReplacementUtil.performReplacement(argument, oldExpression, newExpression));
		}
	}
	public Set callChainIntersection(AbstractCall call) {
		if(this instanceof OperationInvocation && call instanceof OperationInvocation) {
			return ((OperationInvocation)this).callChainIntersection((OperationInvocation)call);
		}
		return Collections.emptySet();
	}

	public boolean isAssertion() {
		return getName().startsWith("assert") || getName().equals("fail");
	}

	public enum StatementCoverageType {
		NONE, ONLY_CALL, RETURN_CALL, THROW_CALL, CAST_CALL, VARIABLE_DECLARATION_INITIALIZER_CALL;
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy