1 package no.uio.ifi.refaktor.prefix;
3 import java.util.Collections;
4 import java.util.Comparator;
5 import java.util.LinkedList;
8 import no.uio.ifi.refaktor.analyze.collectors.LongestCommonPrefixCollector;
9 import no.uio.ifi.refaktor.utils.ParseUtils;
11 import org.eclipse.jdt.core.dom.ASTMatcher;
12 import org.eclipse.jdt.core.dom.ASTNode;
13 import org.eclipse.jdt.core.dom.ASTVisitor;
14 import org.eclipse.jdt.core.dom.Expression;
15 import org.eclipse.jdt.core.dom.IBinding;
16 import org.eclipse.jdt.core.dom.IVariableBinding;
17 import org.eclipse.jdt.core.dom.Name;
20 * A class for representing a prefix of an Expression/Statement.
22 * It has an Expression member for the prefix.
26 private class SubExpressionsFinder extends ASTVisitor {
28 private int topExpressionStartPosition;
29 private final LinkedList<Expression> expressions;
31 public SubExpressionsFinder(Expression expression) {
32 topExpressionStartPosition = expression.getStartPosition();
33 this.expressions = new LinkedList<Expression>();
34 if (expression != null)
35 expression.accept(this);
38 public List<Expression> getExpressions() {
43 public void preVisit(ASTNode node) {
44 if (nodeIsSubExpressionOfTopExpression(node))
45 expressions.add((Expression) node);
48 private boolean nodeIsSubExpressionOfTopExpression(ASTNode node) {
49 return node instanceof Expression && node.getStartPosition() == topExpressionStartPosition;
53 private final Expression prefixExpression;
55 private PrefixSet subPrefixes;
57 private final Object lazyToString = new Object() {
58 private String string;
61 public String toString() {
63 string = ParseUtils.getNodeText(prefixExpression);
69 * Represent a prefix on the base of an Expression.
71 * @param expression the Expression that is the base of the prefix.
73 public Prefix(Expression expression) {
74 assert expression != null;
75 this.prefixExpression = expression;
79 public int getCount() {
83 public void incrementCount() {
88 public String toString() {
89 return lazyToString.toString();
93 * Intersect this prefix with another prefix.
95 * @param other the prefix to intersect with this one.
96 * @return If other is equal to this, a copy of this will be returned,
97 * or else the longest common prefix of other and this is returned.
99 public Prefix intersectWith(Prefix other) {
100 return other.generated_2853864130712417478(this);
103 private Expression longestCommonExpressionWith(Prefix other) {
104 Expression longestCommonExpression = null;
106 for (Expression thisExp: getSubExpressions(prefixExpression)) {
107 longestCommonExpression = other.generated_4200363536186052423(this,
108 longestCommonExpression, thisExp);
110 return longestCommonExpression;
113 private List<Expression> getSubExpressions(Expression expression) {
114 return new SubExpressionsFinder(expression).getExpressions();
118 public int hashCode() {
120 Proven to be effective.
121 Adding information about prefixExpression.resolveTypeBinding().getKey().hashCode()
122 made things slightly worse.
124 More than 20 times more effective than (the cached version of)
125 toString().hashCode() when analyzing org.eclipse.jdt.ui.
127 return prefixExpression.getLength();
131 public boolean equals(Object other) {
134 if (other == null || !(other instanceof Prefix))
136 Prefix otherPrefix = (Prefix) other;
137 return otherPrefix.generated_436244330295722658(this);
140 private boolean hasExpressionMatching(Prefix other) {
141 return other.generated_7899053605141751224(this);
144 private boolean hasVariableBindingEqualTo(Prefix other) {
145 return getVariableBindingOfFirstExpression().isEqualTo(other.getVariableBindingOfFirstExpression());
148 private boolean expressionsMatch(Expression a, Expression b) {
149 return a.subtreeMatch(new ASTMatcher(), b);
152 public int length() {
153 return prefixExpression.getLength();
156 public IVariableBinding getVariableBindingOfFirstExpression() {
157 IBinding binding = resolveBindingOfFirstExpression();
158 assert binding instanceof IVariableBinding;
159 return (IVariableBinding) binding;
162 private IBinding resolveBindingOfFirstExpression() {
163 Expression firstExpression = getFirstExpression();
164 assert firstExpression instanceof Name;
165 return ((Name) firstExpression).resolveBinding();
168 private Expression getFirstExpression() {
169 List<Expression> subExpressions = getSubExpressions(prefixExpression);
170 Collections.sort(subExpressions, new Comparator<Expression>() {
172 public int compare(Expression e1, Expression e2) {
173 if (e1.getLength() < e2.getLength())
175 else if (e1.getLength() > e2.getLength())
181 return subExpressions.get(0);
185 * Tests if this prefix has the other prefix as its sub-prefix.
187 * Example: "a.b" is sub-prefix of "a.b.c", as is "a.b.c".
189 * @param other The prefix to test.
190 * @return true if other is prefix of this prefix, else false.
192 public boolean hasSubPrefix(Prefix other) {
193 return getSubPrefixes().contains(other);
197 * @return the list of possible sub-prefixes, including a copy of this one.
199 public PrefixSet getSubPrefixes() {
200 if (subPrefixes == null) {
201 subPrefixes = new PrefixSet();
202 for (Expression exp: getSubExpressions(prefixExpression))
203 subPrefixes.add(new Prefix(exp));
208 public boolean firstExpressionIsBoundToVariable() {
209 return resolveBindingOfFirstExpression() instanceof IVariableBinding;
212 public int getNumberOfSegments() {
213 return getSubPrefixes().size();
216 public boolean generated_825955664987272076() {
217 return getNumberOfSegments() == 1 && getCount() == 1;
220 public int generated_3478548225149205143(Prefix p1) {
221 if (p1.getCount() > getCount()) {
223 } else if (p1.getCount() < getCount()) {
225 } else if (p1.length() > length()) {
227 } else if (p1.length() < length()) {
233 public void generated_7609478919728457568(LongestCommonPrefixCollector longestcommonprefixcollector) {
234 if (longestcommonprefixcollector.longestCommonPrefix == null) {
235 longestcommonprefixcollector.longestCommonPrefix = this;
237 longestcommonprefixcollector.longestCommonPrefix = longestcommonprefixcollector.longestCommonPrefix.intersectWith(this);
241 public void generated_7681675865424797515(PrefixSet prefixset) {
242 if (!prefixset.contains(this))
243 prefixset.prefixes.put(this, this);
246 public void generated_1397335264344119528(PrefixSet prefixset) {
247 assert prefixset.get(this) != null : this;
250 public void generated_57330167832506990(PrefixSet prefixset) {
251 Prefix prefixFromMap = prefixset.get(this);
252 if (prefixFromMap != null) {
253 prefixFromMap.incrementCount();
259 public String generated_797445745298232673(String str) {
260 str += toString() + " (" + getCount() + ")\n";
264 public void generated_9031955363082597180(PrefixSet prefixSet, Prefix p) {
266 prefixSet.remove(this);
269 public Prefix generated_2853864130712417478(Prefix prefix) {
270 if (prefix.equals(this))
271 return new Prefix(prefix.prefixExpression);
273 return new Prefix(prefix.longestCommonExpressionWith(this));
276 public Expression generated_4200363536186052423(Prefix prefix, Expression longestCommonExpression, Expression thisExp) {
277 for (Expression otherExp: prefix.getSubExpressions(prefixExpression)) {
278 if (prefix.expressionsMatch(otherExp, thisExp)) {
279 if (longestCommonExpression == null) {
280 longestCommonExpression = thisExp;
281 } else if (thisExp.getLength() > longestCommonExpression.getLength()) {
282 longestCommonExpression = thisExp;
287 return longestCommonExpression;
290 public boolean generated_436244330295722658(Prefix prefix) {
291 if (!prefix.hasExpressionMatching(this))
293 return prefix.hasVariableBindingEqualTo(this);
296 public boolean generated_7899053605141751224(Prefix prefix) {
297 return prefix.expressionsMatch(prefix.prefixExpression, prefixExpression);