]> git.uio.no Git - ifi-stolz-refaktor.git/blob - software/no.uio.ifi.refaktor/src/no/uio/ifi/refaktor/extractors/Prefix.java
ExtractAndMoveMethodPrefixesExtractor filters out those prefixes that
[ifi-stolz-refaktor.git] / software / no.uio.ifi.refaktor / src / no / uio / ifi / refaktor / extractors / Prefix.java
1 package no.uio.ifi.refaktor.extractors;
2
3 import java.util.Collections;
4 import java.util.Comparator;
5 import java.util.LinkedList;
6 import java.util.List;
7
8 import no.uio.ifi.refaktor.utils.ParseUtils;
9
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;
21
22 public class Prefix {
23
24         private class SubExpressionsFinder extends ASTVisitor {
25
26                 private Expression topExpression;
27                 private LinkedList<Expression> expressions;
28
29                 public SubExpressionsFinder(Expression expression) {
30                         this.topExpression = expression;
31                         this.expressions = new LinkedList<Expression>();
32                         if (expression != null)
33                                 expression.accept(this);
34                 }
35                 
36                 @Override
37                 public void preVisit(ASTNode node) {
38                         if (nodeIsSubExpressionOfTopExpression(node))
39                                 expressions.add((Expression) node);
40                 }
41
42                 private boolean nodeIsSubExpressionOfTopExpression(ASTNode node) {
43                         return node instanceof Expression && node.getStartPosition() == topExpression.getStartPosition();
44                 }
45
46                 public List<Expression> getExpressions() {
47                         return expressions;
48                 }
49
50         }
51
52         private final Expression prefixExpression;
53         private final IDocument document;
54         private final String prefixString;
55         private int count;
56         private final Statement statement;
57
58         /**
59          * Represent a prefix on the base of an Expression.
60          * 
61          * @param expression the Expression that is the base of the prefix.
62          * @param document the IDocument that is the base of the expression.
63          */
64         public Prefix(Expression expression, Statement statement, IDocument document) {
65                 this.prefixExpression = expression;
66                 this.statement = statement;
67                 this.document = document;
68                 this.count = 1;
69
70                 if (expression != null)
71                         prefixString = ParseUtils.getNodeText(expression, document);
72                 else prefixString = "";
73         }
74
75         public void incrementCount() {
76                 count++;
77         }
78
79         @Override
80         public String toString() {
81                 return prefixString;
82         }
83
84         public int getCount() {
85                 return count;
86         }
87
88         /**
89          * Intersect this prefix with another prefix.
90          * 
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.
95          */
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);
102                 
103                 // TODO: statement??
104                 return new Prefix(longestCommonExpressionWith(other), statement, document);
105         }
106
107         private boolean prefixIsEmpty(Prefix prefix) {
108                 return prefix == null || prefix.getPrefixExpression() == null;
109         }
110
111         public Expression longestCommonExpressionWith(Prefix other) {
112                 Expression longestCommonExpression = null;
113                 
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;
121                                         }
122                                         break;
123                                 }
124                         }
125                 }
126                 return longestCommonExpression;
127         }
128         
129         private List<Expression> getSubExpressions(Expression expression) {
130                 return new SubExpressionsFinder(expression).getExpressions();
131         }
132
133         public boolean equals(Object other) {
134                 if (this == other)
135                         return true;
136                 if (other == null || !(other instanceof Prefix))
137                         return false;
138                 
139                 Expression otherPrefixExpression = ((Prefix) other).getPrefixExpression();
140                 
141                 if (prefixExpression == null && otherPrefixExpression == null)
142                         return true;
143                 else if (prefixExpression == null || otherPrefixExpression == null)
144                         return false;
145                 return expressionsMatch(prefixExpression, otherPrefixExpression);
146         }
147
148         private boolean expressionsMatch(Expression a, Expression b) {
149                 if (a == null || b == null)
150                         return false;
151                 return a.subtreeMatch(new ASTMatcher(), b);
152         }
153
154         private Expression getPrefixExpression() {
155                 return prefixExpression;
156         }
157
158         
159         /**
160          * @return the list of possible sub-prefixes, including a copy of this one.
161          */
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;
167         }
168
169         public int length() {
170                 return prefixExpression.getLength();
171         }
172
173         public int startPosition() {
174                 return prefixExpression.getStartPosition();
175         }
176
177         public String getPackageName() {
178                 return getCompilationUnit().getPackage().getName().getFullyQualifiedName();
179         }
180
181         public String getSimpleTypeName() {
182                 List<?> types = getCompilationUnit().types();
183                 if (types.isEmpty())
184                         return null;
185                 Object first = types.get(0);
186                 assert first instanceof AbstractTypeDeclaration;
187                 AbstractTypeDeclaration absTypeDecl = (AbstractTypeDeclaration) first;
188                 return absTypeDecl.getName().getFullyQualifiedName();
189         }
190         
191         private CompilationUnit getCompilationUnit() {
192                 ASTNode root = prefixExpression.getRoot();
193                 assert root instanceof CompilationUnit;
194                 return (CompilationUnit) root;
195         }
196
197         public int statementStartPosition() {
198                 return statement.getStartPosition();
199         }
200
201         public int statementLength() {
202                 return statement.getLength();
203         }
204
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;
213         }
214
215         public Expression getFirstExpression() {
216                 List<Expression> subExpressions = getSubExpressions(prefixExpression);
217                 Collections.sort(subExpressions, new Comparator<Expression>() {
218                         @Override
219                         public int compare(Expression e1, Expression e2) {
220                                 if (e1.getLength() < e2.getLength())
221                                         return -1;
222                                 else if (e1.getLength() > e2.getLength())
223                                         return 1;
224                                 else
225                                         return 0;
226                         }
227                 });
228                 return subExpressions.get(0);
229         }
230
231 }