]> git.uio.no Git - ifi-stolz-refaktor.git/blame - software/no.uio.ifi.refaktor/src/no/uio/ifi/refaktor/extractors/Prefix.java
Adding some JavaDoc and cleaning up a bit.
[ifi-stolz-refaktor.git] / software / no.uio.ifi.refaktor / src / no / uio / ifi / refaktor / extractors / Prefix.java
CommitLineData
67073f0a
EK
1package no.uio.ifi.refaktor.extractors;
2
2c782b57
VS
3import java.util.Collections;
4import java.util.Comparator;
3db313c8
EK
5import java.util.LinkedList;
6import java.util.List;
7
8import no.uio.ifi.refaktor.utils.ParseUtils;
9
10import org.eclipse.jdt.core.dom.ASTMatcher;
11import org.eclipse.jdt.core.dom.ASTNode;
12import org.eclipse.jdt.core.dom.ASTVisitor;
4c03afae
EK
13import org.eclipse.jdt.core.dom.AbstractTypeDeclaration;
14import org.eclipse.jdt.core.dom.CompilationUnit;
3db313c8 15import org.eclipse.jdt.core.dom.Expression;
0311e2cb
EK
16import org.eclipse.jdt.core.dom.IBinding;
17import org.eclipse.jdt.core.dom.IVariableBinding;
18import org.eclipse.jdt.core.dom.Name;
3db313c8
EK
19import org.eclipse.jface.text.IDocument;
20
7a978020
EK
21/**
22 * A class for representing a prefix of an Expression/Statement.
23 *
24 * It has an Expression member for the prefix.
25 */
67073f0a
EK
26public class Prefix {
27
3db313c8
EK
28 private class SubExpressionsFinder extends ASTVisitor {
29
30 private Expression topExpression;
31 private LinkedList<Expression> expressions;
32
33 public SubExpressionsFinder(Expression expression) {
34 this.topExpression = expression;
35 this.expressions = new LinkedList<Expression>();
36 if (expression != null)
37 expression.accept(this);
38 }
adbe9243 39
3db313c8
EK
40 @Override
41 public void preVisit(ASTNode node) {
6d7256a3 42 if (nodeIsSubExpressionOfTopExpression(node))
3db313c8
EK
43 expressions.add((Expression) node);
44 }
45
6d7256a3
EK
46 private boolean nodeIsSubExpressionOfTopExpression(ASTNode node) {
47 return node instanceof Expression && node.getStartPosition() == topExpression.getStartPosition();
48 }
49
3db313c8
EK
50 public List<Expression> getExpressions() {
51 return expressions;
52 }
53
54 }
55
56 private final Expression prefixExpression;
2c782b57 57 private final IDocument document;
3db313c8 58 private final String prefixString;
67073f0a 59 private int count;
adbe9243 60 private PrefixSet possiblePrefixes;
67073f0a 61
6d7256a3
EK
62 /**
63 * Represent a prefix on the base of an Expression.
64 *
65 * @param expression the Expression that is the base of the prefix.
7a978020
EK
66 * @param document the IDocument that is the base of the source code
67 * that contains the expression.
6d7256a3 68 */
7a978020 69 public Prefix(Expression expression, IDocument document) {
3db313c8
EK
70 this.prefixExpression = expression;
71 this.document = document;
67073f0a 72 this.count = 1;
3db313c8
EK
73
74 if (expression != null)
75 prefixString = ParseUtils.getNodeText(expression, document);
76 else prefixString = "";
67073f0a
EK
77 }
78
79 public void incrementCount() {
80 count++;
81 }
82
3db313c8
EK
83 @Override
84 public String toString() {
087a79bf
EK
85 return getPrefixString();
86 }
87
88 public String getPrefixString() {
3db313c8 89 return prefixString;
67073f0a
EK
90 }
91
92 public int getCount() {
93 return count;
94 }
3db313c8 95
6d7256a3
EK
96 /**
97 * Intersect this prefix with another prefix.
98 *
99 * @param other the prefix to intersect with this one.
100 * @return If the Prefix is empty, the null-prefix will be returned.
101 * If other is equal to this, a copy of this will be returned,
102 * or else the longest common prefix of other and this is returned.
103 */
3db313c8 104 public Prefix intersectWith(Prefix other) {
6d7256a3 105 if (prefixIsEmpty(other))
7a978020 106 return new Prefix(null, document);
3db313c8 107 if (this.equals(other))
6d7256a3 108 // TODO: return this?
7a978020 109 return new Prefix(prefixExpression, document);
adbe9243 110
0311e2cb 111 // TODO: statement??
7a978020 112 return new Prefix(longestCommonExpressionWith(other), document);
6d7256a3
EK
113 }
114
115 private boolean prefixIsEmpty(Prefix prefix) {
116 return prefix == null || prefix.getPrefixExpression() == null;
117 }
118
64970e7f 119 public Expression longestCommonExpressionWith(Prefix other) {
3db313c8 120 Expression longestCommonExpression = null;
adbe9243 121
3db313c8
EK
122 for (Expression thisExp: getSubExpressions(prefixExpression)) {
123 for (Expression otherExp: getSubExpressions(other.getPrefixExpression())) {
124 if (expressionsMatch(otherExp, thisExp)) {
125 if (longestCommonExpression == null) {
126 longestCommonExpression = thisExp;
127 } else if (thisExp.getLength() > longestCommonExpression.getLength()) {
128 longestCommonExpression = thisExp;
129 }
130 break;
131 }
132 }
133 }
6d7256a3 134 return longestCommonExpression;
3db313c8 135 }
adbe9243 136
3db313c8 137 private List<Expression> getSubExpressions(Expression expression) {
6d7256a3 138 return new SubExpressionsFinder(expression).getExpressions();
3db313c8 139 }
adbe9243 140
087a79bf
EK
141 @Override
142 public int hashCode() {
143 return getPrefixString().hashCode();
144 }
3db313c8 145
087a79bf 146 @Override
3db313c8
EK
147 public boolean equals(Object other) {
148 if (this == other)
149 return true;
150 if (other == null || !(other instanceof Prefix))
151 return false;
087a79bf
EK
152 return hasExpressionEqualTo((Prefix) other);
153 }
154
155 private boolean hasExpressionEqualTo(Prefix other) {
156 Expression otherPrefixExpression = other.getPrefixExpression();
adbe9243 157
3db313c8
EK
158 if (prefixExpression == null && otherPrefixExpression == null)
159 return true;
087a79bf 160 if (prefixExpression == null || otherPrefixExpression == null)
3db313c8
EK
161 return false;
162 return expressionsMatch(prefixExpression, otherPrefixExpression);
163 }
164
165 private boolean expressionsMatch(Expression a, Expression b) {
166 if (a == null || b == null)
167 return false;
168 return a.subtreeMatch(new ASTMatcher(), b);
169 }
170
171 private Expression getPrefixExpression() {
172 return prefixExpression;
173 }
adbe9243 174
6d7256a3
EK
175 /**
176 * @return the list of possible sub-prefixes, including a copy of this one.
177 */
0d284c26 178 public PrefixSet getSubPrefixes() {
adbe9243
EK
179 if (possiblePrefixes == null) {
180 possiblePrefixes = new PrefixSet();
181 for (Expression exp: getSubExpressions(prefixExpression))
7a978020 182 possiblePrefixes.add(new Prefix(exp, document));
adbe9243 183 }
3db313c8
EK
184 return possiblePrefixes;
185 }
4c03afae
EK
186
187 public int length() {
188 return prefixExpression.getLength();
189 }
190
191 public int startPosition() {
192 return prefixExpression.getStartPosition();
193 }
194
195 public String getPackageName() {
196 return getCompilationUnit().getPackage().getName().getFullyQualifiedName();
197 }
198
199 public String getSimpleTypeName() {
200 List<?> types = getCompilationUnit().types();
201 if (types.isEmpty())
202 return null;
203 Object first = types.get(0);
204 assert first instanceof AbstractTypeDeclaration;
205 AbstractTypeDeclaration absTypeDecl = (AbstractTypeDeclaration) first;
206 return absTypeDecl.getName().getFullyQualifiedName();
207 }
adbe9243 208
4c03afae
EK
209 private CompilationUnit getCompilationUnit() {
210 ASTNode root = prefixExpression.getRoot();
211 assert root instanceof CompilationUnit;
212 return (CompilationUnit) root;
213 }
214
2c782b57
VS
215 public IVariableBinding getVariableBindingOfFirstExpression() {
216 Expression firstExpression = getFirstExpression();
217 assert firstExpression instanceof Name;
adbe9243 218 IBinding binding = ((Name) firstExpression).resolveBinding();
0311e2cb
EK
219 assert binding != null;
220 assert binding instanceof IVariableBinding;
221 return (IVariableBinding) binding;
222 }
223
adbe9243 224 private Expression getFirstExpression() {
2c782b57
VS
225 List<Expression> subExpressions = getSubExpressions(prefixExpression);
226 Collections.sort(subExpressions, new Comparator<Expression>() {
227 @Override
228 public int compare(Expression e1, Expression e2) {
229 if (e1.getLength() < e2.getLength())
230 return -1;
231 else if (e1.getLength() > e2.getLength())
232 return 1;
233 else
234 return 0;
235 }
236 });
237 return subExpressions.get(0);
238 }
239
7a978020
EK
240 /**
241 * Tests if this prefix encloses another prefix.
242 *
243 * Example: "a.b.c" encloses "a.b"
244 * @param other
245 * @return
246 */
247 public boolean encloses(Prefix other) {
486b6bc4 248 return getSubPrefixes().contains(other);
062df6c3
EK
249 }
250
4c537a5a 251}