package no.uio.ifi.refaktor.extractors; import java.util.Collections; import java.util.Comparator; import java.util.LinkedList; import java.util.List; import no.uio.ifi.refaktor.utils.ParseUtils; import org.eclipse.jdt.core.dom.ASTMatcher; import org.eclipse.jdt.core.dom.ASTNode; import org.eclipse.jdt.core.dom.ASTVisitor; import org.eclipse.jdt.core.dom.AbstractTypeDeclaration; import org.eclipse.jdt.core.dom.CompilationUnit; import org.eclipse.jdt.core.dom.Expression; import org.eclipse.jdt.core.dom.IBinding; import org.eclipse.jdt.core.dom.IVariableBinding; import org.eclipse.jdt.core.dom.Name; import org.eclipse.jdt.core.dom.Statement; import org.eclipse.jface.text.IDocument; public class Prefix { private class SubExpressionsFinder extends ASTVisitor { private Expression topExpression; private LinkedList expressions; public SubExpressionsFinder(Expression expression) { this.topExpression = expression; this.expressions = new LinkedList(); if (expression != null) expression.accept(this); } @Override public void preVisit(ASTNode node) { if (nodeIsSubExpressionOfTopExpression(node)) expressions.add((Expression) node); } private boolean nodeIsSubExpressionOfTopExpression(ASTNode node) { return node instanceof Expression && node.getStartPosition() == topExpression.getStartPosition(); } public List getExpressions() { return expressions; } } private final Expression prefixExpression; private final IDocument document; private final String prefixString; private int count; private final Statement statement; /** * Represent a prefix on the base of an Expression. * * @param expression the Expression that is the base of the prefix. * @param document the IDocument that is the base of the expression. */ public Prefix(Expression expression, Statement statement, IDocument document) { this.prefixExpression = expression; this.statement = statement; this.document = document; this.count = 1; if (expression != null) prefixString = ParseUtils.getNodeText(expression, document); else prefixString = ""; } public void incrementCount() { count++; } @Override public String toString() { return prefixString; } public int getCount() { return count; } /** * Intersect this prefix with another prefix. * * @param other the prefix to intersect with this one. * @return If the Prefix is empty, the null-prefix will be returned. * If other is equal to this, a copy of this will be returned, * or else the longest common prefix of other and this is returned. */ public Prefix intersectWith(Prefix other) { if (prefixIsEmpty(other)) return new Prefix(null, null, document); if (this.equals(other)) // TODO: return this? return new Prefix(prefixExpression, statement, document); // TODO: statement?? return new Prefix(longestCommonExpressionWith(other), statement, document); } private boolean prefixIsEmpty(Prefix prefix) { return prefix == null || prefix.getPrefixExpression() == null; } public Expression longestCommonExpressionWith(Prefix other) { Expression longestCommonExpression = null; for (Expression thisExp: getSubExpressions(prefixExpression)) { for (Expression otherExp: getSubExpressions(other.getPrefixExpression())) { if (expressionsMatch(otherExp, thisExp)) { if (longestCommonExpression == null) { longestCommonExpression = thisExp; } else if (thisExp.getLength() > longestCommonExpression.getLength()) { longestCommonExpression = thisExp; } break; } } } return longestCommonExpression; } private List getSubExpressions(Expression expression) { return new SubExpressionsFinder(expression).getExpressions(); } public boolean equals(Object other) { if (this == other) return true; if (other == null || !(other instanceof Prefix)) return false; Expression otherPrefixExpression = ((Prefix) other).getPrefixExpression(); if (prefixExpression == null && otherPrefixExpression == null) return true; else if (prefixExpression == null || otherPrefixExpression == null) return false; return expressionsMatch(prefixExpression, otherPrefixExpression); } private boolean expressionsMatch(Expression a, Expression b) { if (a == null || b == null) return false; return a.subtreeMatch(new ASTMatcher(), b); } private Expression getPrefixExpression() { return prefixExpression; } /** * @return the list of possible sub-prefixes, including a copy of this one. */ public List getSubPrefixes() { List possiblePrefixes = new LinkedList(); for (Expression exp: getSubExpressions(prefixExpression)) possiblePrefixes.add(new Prefix(exp, statement, document)); return possiblePrefixes; } public int length() { return prefixExpression.getLength(); } public int startPosition() { return prefixExpression.getStartPosition(); } public String getPackageName() { return getCompilationUnit().getPackage().getName().getFullyQualifiedName(); } public String getSimpleTypeName() { List types = getCompilationUnit().types(); if (types.isEmpty()) return null; Object first = types.get(0); assert first instanceof AbstractTypeDeclaration; AbstractTypeDeclaration absTypeDecl = (AbstractTypeDeclaration) first; return absTypeDecl.getName().getFullyQualifiedName(); } private CompilationUnit getCompilationUnit() { ASTNode root = prefixExpression.getRoot(); assert root instanceof CompilationUnit; return (CompilationUnit) root; } public int statementStartPosition() { return statement.getStartPosition(); } public int statementLength() { return statement.getLength(); } public IVariableBinding getVariableBindingOfFirstExpression() { Expression firstExpression = getFirstExpression(); assert firstExpression instanceof Name; Name name = (Name) firstExpression; IBinding binding = name.resolveBinding(); assert binding != null; assert binding instanceof IVariableBinding; return (IVariableBinding) binding; } public Expression getFirstExpression() { List subExpressions = getSubExpressions(prefixExpression); Collections.sort(subExpressions, new Comparator() { @Override public int compare(Expression e1, Expression e2) { if (e1.getLength() < e2.getLength()) return -1; else if (e1.getLength() > e2.getLength()) return 1; else return 0; } }); return subExpressions.get(0); } }