1 package no.uio.ifi.refaktor.extractors;
3 import java.util.Collections;
4 import java.util.Comparator;
5 import java.util.LinkedList;
8 import no.uio.ifi.refaktor.utils.ParseUtils;
10 import org.eclipse.jdt.core.dom.ASTMatcher;
11 import org.eclipse.jdt.core.dom.ASTNode;
12 import org.eclipse.jdt.core.dom.ASTVisitor;
13 import org.eclipse.jdt.core.dom.AbstractTypeDeclaration;
14 import org.eclipse.jdt.core.dom.CompilationUnit;
15 import org.eclipse.jdt.core.dom.Expression;
16 import org.eclipse.jdt.core.dom.IBinding;
17 import org.eclipse.jdt.core.dom.IVariableBinding;
18 import org.eclipse.jdt.core.dom.Name;
19 import org.eclipse.jdt.core.dom.Statement;
20 import org.eclipse.jface.text.IDocument;
24 private class SubExpressionsFinder extends ASTVisitor {
26 private Expression topExpression;
27 private LinkedList<Expression> expressions;
29 public SubExpressionsFinder(Expression expression) {
30 this.topExpression = expression;
31 this.expressions = new LinkedList<Expression>();
32 if (expression != null)
33 expression.accept(this);
37 public void preVisit(ASTNode node) {
38 if (nodeIsSubExpressionOfTopExpression(node))
39 expressions.add((Expression) node);
42 private boolean nodeIsSubExpressionOfTopExpression(ASTNode node) {
43 return node instanceof Expression && node.getStartPosition() == topExpression.getStartPosition();
46 public List<Expression> getExpressions() {
52 private final Expression prefixExpression;
53 private final IDocument document;
54 private final String prefixString;
56 private final Statement statement;
59 * Represent a prefix on the base of an Expression.
61 * @param expression the Expression that is the base of the prefix.
62 * @param document the IDocument that is the base of the expression.
64 public Prefix(Expression expression, Statement statement, IDocument document) {
65 this.prefixExpression = expression;
66 this.statement = statement;
67 this.document = document;
70 if (expression != null)
71 prefixString = ParseUtils.getNodeText(expression, document);
72 else prefixString = "";
75 public void incrementCount() {
80 public String toString() {
84 public int getCount() {
89 * Intersect this prefix with another prefix.
91 * @param other the prefix to intersect with this one.
92 * @return If the Prefix is empty, the null-prefix will be returned.
93 * If other is equal to this, a copy of this will be returned,
94 * or else the longest common prefix of other and this is returned.
96 public Prefix intersectWith(Prefix other) {
97 if (prefixIsEmpty(other))
98 return new Prefix(null, null, document);
99 if (this.equals(other))
100 // TODO: return this?
101 return new Prefix(prefixExpression, statement, document);
104 return new Prefix(longestCommonExpressionWith(other), statement, document);
107 private boolean prefixIsEmpty(Prefix prefix) {
108 return prefix == null || prefix.getPrefixExpression() == null;
111 public Expression longestCommonExpressionWith(Prefix other) {
112 Expression longestCommonExpression = null;
114 for (Expression thisExp: getSubExpressions(prefixExpression)) {
115 for (Expression otherExp: getSubExpressions(other.getPrefixExpression())) {
116 if (expressionsMatch(otherExp, thisExp)) {
117 if (longestCommonExpression == null) {
118 longestCommonExpression = thisExp;
119 } else if (thisExp.getLength() > longestCommonExpression.getLength()) {
120 longestCommonExpression = thisExp;
126 return longestCommonExpression;
129 private List<Expression> getSubExpressions(Expression expression) {
130 return new SubExpressionsFinder(expression).getExpressions();
133 public boolean equals(Object other) {
136 if (other == null || !(other instanceof Prefix))
139 Expression otherPrefixExpression = ((Prefix) other).getPrefixExpression();
141 if (prefixExpression == null && otherPrefixExpression == null)
143 else if (prefixExpression == null || otherPrefixExpression == null)
145 return expressionsMatch(prefixExpression, otherPrefixExpression);
148 private boolean expressionsMatch(Expression a, Expression b) {
149 if (a == null || b == null)
151 return a.subtreeMatch(new ASTMatcher(), b);
154 private Expression getPrefixExpression() {
155 return prefixExpression;
160 * @return the list of possible sub-prefixes, including a copy of this one.
162 public List<Prefix> getSubPrefixes() {
163 List<Prefix> possiblePrefixes = new LinkedList<Prefix>();
164 for (Expression exp: getSubExpressions(prefixExpression))
165 possiblePrefixes.add(new Prefix(exp, statement, document));
166 return possiblePrefixes;
169 public int length() {
170 return prefixExpression.getLength();
173 public int startPosition() {
174 return prefixExpression.getStartPosition();
177 public String getPackageName() {
178 return getCompilationUnit().getPackage().getName().getFullyQualifiedName();
181 public String getSimpleTypeName() {
182 List<?> types = getCompilationUnit().types();
185 Object first = types.get(0);
186 assert first instanceof AbstractTypeDeclaration;
187 AbstractTypeDeclaration absTypeDecl = (AbstractTypeDeclaration) first;
188 return absTypeDecl.getName().getFullyQualifiedName();
191 private CompilationUnit getCompilationUnit() {
192 ASTNode root = prefixExpression.getRoot();
193 assert root instanceof CompilationUnit;
194 return (CompilationUnit) root;
197 public int statementStartPosition() {
198 return statement.getStartPosition();
201 public int statementLength() {
202 return statement.getLength();
205 public IVariableBinding getVariableBindingOfFirstExpression() {
206 Expression firstExpression = getFirstExpression();
207 assert firstExpression instanceof Name;
208 Name name = (Name) firstExpression;
209 IBinding binding = name.resolveBinding();
210 assert binding != null;
211 assert binding instanceof IVariableBinding;
212 return (IVariableBinding) binding;
215 public Expression getFirstExpression() {
216 List<Expression> subExpressions = getSubExpressions(prefixExpression);
217 Collections.sort(subExpressions, new Comparator<Expression>() {
219 public int compare(Expression e1, Expression e2) {
220 if (e1.getLength() < e2.getLength())
222 else if (e1.getLength() > e2.getLength())
228 return subExpressions.get(0);