KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > corext > refactoring > code > SnippetFinder


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.jdt.internal.corext.refactoring.code;
12
13 import java.util.ArrayList JavaDoc;
14 import java.util.HashMap JavaDoc;
15 import java.util.Iterator JavaDoc;
16 import java.util.List JavaDoc;
17 import java.util.Map JavaDoc;
18
19 import org.eclipse.core.runtime.Assert;
20
21 import org.eclipse.jdt.core.dom.ASTMatcher;
22 import org.eclipse.jdt.core.dom.ASTNode;
23 import org.eclipse.jdt.core.dom.AbstractTypeDeclaration;
24 import org.eclipse.jdt.core.dom.AnnotationTypeDeclaration;
25 import org.eclipse.jdt.core.dom.AnonymousClassDeclaration;
26 import org.eclipse.jdt.core.dom.Assignment;
27 import org.eclipse.jdt.core.dom.EnumDeclaration;
28 import org.eclipse.jdt.core.dom.IBinding;
29 import org.eclipse.jdt.core.dom.IVariableBinding;
30 import org.eclipse.jdt.core.dom.MethodDeclaration;
31 import org.eclipse.jdt.core.dom.SimpleName;
32 import org.eclipse.jdt.core.dom.TypeDeclaration;
33
34 import org.eclipse.jdt.internal.corext.dom.ASTNodes;
35 import org.eclipse.jdt.internal.corext.dom.Bindings;
36 import org.eclipse.jdt.internal.corext.dom.GenericVisitor;
37
38
39 /* package */ class SnippetFinder extends GenericVisitor {
40     
41     public static class Match {
42         private List JavaDoc fNodes;
43         private Map JavaDoc fLocalMappings;
44         
45         public Match() {
46             fNodes= new ArrayList JavaDoc(10);
47             fLocalMappings= new HashMap JavaDoc();
48         }
49         public void add(ASTNode node) {
50             fNodes.add(node);
51         }
52         public boolean hasCorrectNesting(ASTNode node) {
53             if (fNodes.size() == 0)
54                 return true;
55             ASTNode parent= node.getParent();
56             if(((ASTNode)fNodes.get(0)).getParent() != parent)
57                 return false;
58             // Here we know that we have two elements. In this case the
59
// parent must be a block or a switch statement. Otherwise a
60
// snippet like "if (true) foo(); else foo();" would match
61
// the pattern "foo(); foo();"
62
int nodeType= parent.getNodeType();
63             return nodeType == ASTNode.BLOCK || nodeType == ASTNode.SWITCH_STATEMENT;
64         }
65         public ASTNode[] getNodes() {
66             return (ASTNode[])fNodes.toArray(new ASTNode[fNodes.size()]);
67         }
68         public void addLocal(IVariableBinding org, SimpleName local) {
69             fLocalMappings.put(org, local);
70         }
71         public SimpleName getMappedName(IVariableBinding org) {
72             return (SimpleName)fLocalMappings.get(org);
73         }
74         public IVariableBinding getMappedBinding(IVariableBinding org) {
75             SimpleName name= (SimpleName) fLocalMappings.get(org);
76             return ASTNodes.getVariableBinding(name);
77         }
78         public boolean isEmpty() {
79             return fNodes.isEmpty() && fLocalMappings.isEmpty();
80         }
81         /**
82          * Tests if the whole duplicate is the full body of a method. If so
83          * don't replace it since we would replace a method body with a new
84          * method body which doesn't make to much sense.
85          *
86          * @return whether the duplicte is the whole method body
87          */

88         public boolean isMethodBody() {
89             ASTNode first= (ASTNode)fNodes.get(0);
90             if (first.getParent() == null)
91                 return false;
92             ASTNode candidate= first.getParent().getParent();
93             if (candidate == null || candidate.getNodeType() != ASTNode.METHOD_DECLARATION)
94                 return false;
95             MethodDeclaration method= (MethodDeclaration)candidate;
96             return method.getBody().statements().size() == fNodes.size();
97         }
98         public MethodDeclaration getEnclosingMethod() {
99             ASTNode first= (ASTNode)fNodes.get(0);
100             return (MethodDeclaration)ASTNodes.getParent(first, ASTNode.METHOD_DECLARATION);
101         }
102     }
103     
104     private class Matcher extends ASTMatcher {
105         public boolean match(SimpleName candidate, Object JavaDoc s) {
106             if (!(s instanceof SimpleName))
107                 return false;
108                 
109             SimpleName snippet= (SimpleName)s;
110             if (candidate.isDeclaration() != snippet.isDeclaration())
111                 return false;
112             
113             IBinding cb= candidate.resolveBinding();
114             IBinding sb= snippet.resolveBinding();
115             if (cb == null || sb == null)
116                 return false;
117             IVariableBinding vcb= ASTNodes.getVariableBinding(candidate);
118             IVariableBinding vsb= ASTNodes.getVariableBinding(snippet);
119             if (vcb == null || vsb == null)
120                 return Bindings.equals(cb, sb);
121             if (!vcb.isField() && !vsb.isField() && Bindings.equals(vcb.getType(), vsb.getType())) {
122                 SimpleName mapped= fMatch.getMappedName(vsb);
123                 if (mapped != null) {
124                     IVariableBinding mappedBinding= ASTNodes.getVariableBinding(mapped);
125                     if (!Bindings.equals(vcb, mappedBinding))
126                         return false;
127                 }
128                 fMatch.addLocal(vsb, candidate);
129                 return true;
130             }
131             return Bindings.equals(cb, sb);
132         }
133     }
134
135     private List JavaDoc fResult= new ArrayList JavaDoc(2);
136     private Match fMatch;
137     private ASTNode[] fSnippet;
138     private int fIndex;
139     private Matcher fMatcher;
140     private int fTypes;
141     
142     private SnippetFinder(ASTNode[] snippet) {
143         super(true);
144         fSnippet= snippet;
145         fMatcher= new Matcher();
146         reset();
147     }
148     
149     public static Match[] perform(ASTNode start, ASTNode[] snippet) {
150         Assert.isTrue(start instanceof AbstractTypeDeclaration || start instanceof AnonymousClassDeclaration);
151         SnippetFinder finder= new SnippetFinder(snippet);
152         start.accept(finder);
153         for (Iterator JavaDoc iter = finder.fResult.iterator(); iter.hasNext();) {
154             Match match = (Match)iter.next();
155             ASTNode[] nodes= match.getNodes();
156             // doesn't match if the candidate is the left hand side of an
157
// assignment and the snippet consists of a single node.
158
// Otherwise y= i; i= z; results in y= e(); e()= z;
159
if (nodes.length == 1 && isLeftHandSideOfAssignment(nodes[0])) {
160                 iter.remove();
161             }
162         }
163         return (Match[])finder.fResult.toArray(new Match[finder.fResult.size()]);
164     }
165     
166     private static boolean isLeftHandSideOfAssignment(ASTNode node) {
167         ASTNode parent= node.getParent();
168         return parent != null && parent.getNodeType() == ASTNode.ASSIGNMENT && ((Assignment)parent).getLeftHandSide() == node;
169     }
170     
171     public boolean visit(TypeDeclaration node) {
172         if (++fTypes > 1)
173             return false;
174         return super.visit(node);
175     }
176     
177     public void endVisit(TypeDeclaration node) {
178         --fTypes;
179         super.endVisit(node);
180     }
181     
182     public boolean visit(EnumDeclaration node) {
183         if (++fTypes > 1)
184             return false;
185         return super.visit(node);
186     }
187     
188     public void endVisit(EnumDeclaration node) {
189         --fTypes;
190         super.endVisit(node);
191     }
192     
193     public boolean visit(AnnotationTypeDeclaration node) {
194         if (++fTypes > 1)
195             return false;
196         return super.visit(node);
197     }
198     
199     public void endVisit(AnnotationTypeDeclaration node) {
200         --fTypes;
201         super.endVisit(node);
202     }
203     
204     protected boolean visitNode(ASTNode node) {
205         if (matches(node)) {
206             return false;
207         } else if (!isResetted()){
208             reset();
209             if (matches(node))
210                 return false;
211         }
212         return true;
213     }
214     
215     private boolean matches(ASTNode node) {
216         if (isSnippetNode(node))
217             return false;
218         if (node.subtreeMatch(fMatcher, fSnippet[fIndex]) && fMatch.hasCorrectNesting(node)) {
219             fMatch.add(node);
220             fIndex++;
221             if (fIndex == fSnippet.length) {
222                 fResult.add(fMatch);
223                 reset();
224             }
225             return true;
226         }
227         return false;
228     }
229
230     private boolean isResetted() {
231         return fIndex == 0 && fMatch.isEmpty();
232     }
233
234     private void reset() {
235         fIndex= 0;
236         fMatch= new Match();
237     }
238     
239     private boolean isSnippetNode(ASTNode node) {
240         for (int i= 0; i < fSnippet.length; i++) {
241             if (node == fSnippet[i])
242                 return true;
243         }
244         return false;
245     }
246 }
247
Popular Tags