1 11 package org.eclipse.jdt.internal.corext.refactoring.code; 12 13 import java.util.ArrayList ; 14 import java.util.HashMap ; 15 import java.util.Iterator ; 16 import java.util.List ; 17 import java.util.Map ; 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 class SnippetFinder extends GenericVisitor { 40 41 public static class Match { 42 private List fNodes; 43 private Map fLocalMappings; 44 45 public Match() { 46 fNodes= new ArrayList (10); 47 fLocalMappings= new HashMap (); 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 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 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 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 fResult= new ArrayList (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 iter = finder.fResult.iterator(); iter.hasNext();) { 154 Match match = (Match)iter.next(); 155 ASTNode[] nodes= match.getNodes(); 156 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 |