package gr.uom.java.ast.decomposition.matching; import gr.uom.java.ast.decomposition.AbstractExpression; import java.util.ArrayList; import java.util.List; import org.eclipse.jdt.core.dom.ASTNode; import org.eclipse.jdt.core.dom.Assignment; import org.eclipse.jdt.core.dom.Block; import org.eclipse.jdt.core.dom.Expression; import org.eclipse.jdt.core.dom.FieldAccess; import org.eclipse.jdt.core.dom.IBinding; import org.eclipse.jdt.core.dom.ITypeBinding; import org.eclipse.jdt.core.dom.IVariableBinding; import org.eclipse.jdt.core.dom.IfStatement; import org.eclipse.jdt.core.dom.MethodDeclaration; import org.eclipse.jdt.core.dom.QualifiedName; import org.eclipse.jdt.core.dom.SimpleName; import org.eclipse.jdt.core.dom.TryStatement; import org.eclipse.jdt.core.dom.Type; public class ASTNodeDifference { private AbstractExpression expression1; private AbstractExpression expression2; private List<Difference> differences; private BindingSignaturePair bindingSignaturePair; public ASTNodeDifference(AbstractExpression e1, AbstractExpression e2) { this.expression1=e1; this.expression2=e2; this.bindingSignaturePair = new BindingSignaturePair(e1, e2); this.differences = new ArrayList<Difference>(); } public List<Difference> getDifferences() { return differences; } public AbstractExpression getExpression1() { return expression1; } public AbstractExpression getExpression2() { return expression2; } public BindingSignaturePair getBindingSignaturePair() { return bindingSignaturePair; } public void addDifference(Difference diff) { differences.add(diff); } public boolean containsDifferenceType(DifferenceType type) { for(Difference difference : differences) { if(difference.getType().equals(type)) return true; } return false; } public boolean containsOnlyDifferenceType(DifferenceType type) { for(Difference difference : differences) { if(!difference.getType().equals(type)) return false; } if(!differences.isEmpty()) return true; return false; } public boolean isParameterizable() { for(Difference difference : differences) { if(typeMismatch(difference)) return false; } return true; } private boolean typeMismatch(Difference diff) { if(diff.getType().equals(DifferenceType.AST_TYPE_MISMATCH) || (diff.getType().equals(DifferenceType.VARIABLE_TYPE_MISMATCH) && isVariableTypeMismatch()) || (diff.getType().equals(DifferenceType.OPERATOR_MISMATCH) && isExpressionOfIfStatementNestedAtLevelZero()) || diff.getType().equals(DifferenceType.ANONYMOUS_CLASS_DECLARATION_MISMATCH)) return true; return false; } private boolean isVariableTypeMismatch() { if(isQualifierOfQualifiedName() || isExpressionOfFieldAccess()) return false; return true; } private boolean isExpressionOfIfStatementNestedAtLevelZero() { if(expression1.getExpression().getParent() instanceof IfStatement && expression2.getExpression().getParent() instanceof IfStatement) { IfStatement if1 = (IfStatement)expression1.getExpression().getParent(); IfStatement if2 = (IfStatement)expression2.getExpression().getParent(); boolean noElsePart = if1.getElseStatement() == null && if2.getElseStatement() == null; ASTNode parent1 = if1.getParent(); while(parent1 instanceof Block) { parent1 = parent1.getParent(); } ASTNode parent2 = if2.getParent(); while(parent2 instanceof Block) { parent2 = parent2.getParent(); } if(parent1 instanceof MethodDeclaration && parent2 instanceof MethodDeclaration) { return noElsePart; } if(parent1 instanceof TryStatement && parent2 instanceof TryStatement) { TryStatement try1 = (TryStatement)parent1; TryStatement try2 = (TryStatement)parent2; parent1 = try1.getParent(); while(parent1 instanceof Block) { parent1 = parent1.getParent(); } parent2 = try2.getParent(); while(parent2 instanceof Block) { parent2 = parent2.getParent(); } if(parent1 instanceof MethodDeclaration && parent2 instanceof MethodDeclaration) { return noElsePart; } } } return false; } private boolean isQualifierOfQualifiedName() { Expression exp1 = expression1.getExpression(); Expression exp2 = expression2.getExpression(); ASTNode node1 = exp1.getParent(); ASTNode node2 = exp2.getParent(); if(node1 instanceof QualifiedName && node2 instanceof QualifiedName) { QualifiedName qual1 = (QualifiedName)node1; QualifiedName qual2 = (QualifiedName)node2; if(qual1.getQualifier().equals(exp1) && qual2.getQualifier().equals(exp2)) return true; } return false; } private boolean isExpressionOfFieldAccess() { Expression exp1 = expression1.getExpression(); Expression exp2 = expression2.getExpression(); ASTNode node1 = exp1.getParent(); ASTNode node2 = exp2.getParent(); if(node1 instanceof FieldAccess && node2 instanceof FieldAccess) { FieldAccess fieldAccess1 = (FieldAccess)node1; FieldAccess fieldAccess2 = (FieldAccess)node2; if(fieldAccess1.getExpression().equals(exp1) && fieldAccess2.getExpression().equals(exp2)) return true; } return false; } public boolean isEmpty() { return differences.isEmpty(); } public boolean isParentNodeDifferenceOf(ASTNodeDifference nodeDifference) { Expression thisExpression1 = expression1.getExpression(); Expression thisExpression2 = expression2.getExpression(); thisExpression1 = getParentExpressionOfMethodNameOrTypeName(thisExpression1); thisExpression2 = getParentExpressionOfMethodNameOrTypeName(thisExpression2); Expression otherExpression1 = nodeDifference.expression1.getExpression(); Expression otherExpression2 = nodeDifference.expression2.getExpression(); if(isParent(thisExpression1, otherExpression1) && isParent(thisExpression2, otherExpression2)) return true; return false; } private boolean isParent(Expression parent, ASTNode child) { if(child.getParent().equals(parent)) return true; else if(child.getParent() instanceof Expression) { return isParent(parent, (Expression)child.getParent()); } else if(child.getParent() instanceof Type) { return isParent(parent, (Type)child.getParent()); } else { return false; } } public boolean isLeftHandSideOfAssignment() { Expression exp1 = expression1.getExpression(); Expression exp2 = expression2.getExpression(); ASTNode node1 = exp1.getParent(); ASTNode node2 = exp2.getParent(); if(node1 instanceof Assignment && node2 instanceof Assignment) { Assignment assignment1 = (Assignment)node1; Assignment assignment2 = (Assignment)node2; if(assignment1.getLeftHandSide().equals(exp1) && assignment2.getLeftHandSide().equals(exp2)) { return true; } } return false; } public static Expression getParentExpressionOfMethodNameOrTypeName(Expression expression) { if(expression instanceof SimpleName) { SimpleName simpleName = (SimpleName)expression; IBinding binding = simpleName.resolveBinding(); if(binding != null) { if(binding.getKind() == IBinding.METHOD) { if(expression.getParent() instanceof Expression) { return (Expression)expression.getParent(); } } if(binding.getKind() == IBinding.TYPE) { if(expression.getParent() instanceof Type) { Type type = (Type)expression.getParent(); if(type.getParent() instanceof Expression) { return (Expression)type.getParent(); } } } if(binding.getKind() == ITypeBinding.VARIABLE) { if(expression.getParent() instanceof QualifiedName) { QualifiedName fieldAccess = (QualifiedName)expression.getParent(); SimpleName fieldName = fieldAccess.getName(); IBinding fieldNameBinding = fieldName.resolveBinding(); if(fieldNameBinding.getKind() == IBinding.VARIABLE) { IVariableBinding fieldNameVariableBinding = (IVariableBinding)fieldNameBinding; if(fieldAccess.getQualifier().equals(expression) && fieldNameVariableBinding.isField()) { return fieldAccess; } } } } } } else if(expression instanceof QualifiedName) { QualifiedName qualifiedName = (QualifiedName)expression; IBinding binding = qualifiedName.resolveBinding(); if(binding != null) { if(binding.getKind() == IBinding.TYPE) { if(qualifiedName.getParent() instanceof Type) { Type type = (Type)qualifiedName.getParent(); if(type.getParent() instanceof Expression) { return (Expression)type.getParent(); } } } } } return expression; } public int getWeight() { return bindingSignaturePair.getWeight(); } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((differences == null) ? 0 : differences.hashCode()); result = prime * result + ((expression1 == null) ? 0 : expression1.hashCode()); result = prime * result + ((expression2 == null) ? 0 : expression2.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; ASTNodeDifference other = (ASTNodeDifference) obj; if (differences == null) { if (other.differences != null) return false; } else if (!differences.equals(other.differences)) return false; if (expression1 == null) { if (other.expression1 != null) return false; } else if (!expression1.equals(other.expression1)) return false; if (expression2 == null) { if (other.expression2 != null) return false; } else if (!expression2.equals(other.expression2)) return false; return true; } public String toString() { StringBuilder sb = new StringBuilder(); for(Difference difference : differences) { sb.append(difference.toString()).append("\n"); } return sb.toString(); } }