1 11 package org.eclipse.jdt.internal.ui.search; 12 13 import java.util.ArrayList ; 14 import java.util.Arrays ; 15 import java.util.Collections ; 16 import java.util.List ; 17 18 import org.eclipse.jdt.core.IJavaElement; 19 import org.eclipse.jdt.core.ISourceReference; 20 import org.eclipse.jdt.core.JavaModelException; 21 import org.eclipse.jdt.core.ToolFactory; 22 import org.eclipse.jdt.core.compiler.IScanner; 23 import org.eclipse.jdt.core.compiler.InvalidInputException; 24 import org.eclipse.jdt.core.dom.AST; 25 import org.eclipse.jdt.core.dom.ASTNode; 26 import org.eclipse.jdt.core.dom.ASTVisitor; 27 import org.eclipse.jdt.core.dom.Block; 28 import org.eclipse.jdt.core.dom.BreakStatement; 29 import org.eclipse.jdt.core.dom.CompilationUnit; 30 import org.eclipse.jdt.core.dom.ContinueStatement; 31 import org.eclipse.jdt.core.dom.DoStatement; 32 import org.eclipse.jdt.core.dom.EnhancedForStatement; 33 import org.eclipse.jdt.core.dom.ForStatement; 34 import org.eclipse.jdt.core.dom.Initializer; 35 import org.eclipse.jdt.core.dom.LabeledStatement; 36 import org.eclipse.jdt.core.dom.MethodDeclaration; 37 import org.eclipse.jdt.core.dom.SimpleName; 38 import org.eclipse.jdt.core.dom.SwitchStatement; 39 import org.eclipse.jdt.core.dom.WhileStatement; 40 41 import org.eclipse.jdt.internal.corext.dom.ASTNodes; 42 import org.eclipse.jdt.internal.corext.dom.NodeFinder; 43 44 import org.eclipse.jdt.internal.ui.JavaPlugin; 45 46 55 public class BreakContinueTargetFinder extends ASTVisitor { 56 private ASTNode fSelected; 57 private boolean fIsBreak; 58 private SimpleName fLabel; 59 private String fContents; private static final Class [] STOPPERS= {MethodDeclaration.class, Initializer.class}; 61 private static final Class [] BREAKTARGETS= {ForStatement.class, EnhancedForStatement.class, WhileStatement.class, DoStatement.class, SwitchStatement.class}; 62 private static final Class [] CONTINUETARGETS= {ForStatement.class, EnhancedForStatement.class, WhileStatement.class, DoStatement.class}; 63 private static final int BRACE_LENGTH= 1; 64 65 68 public String initialize(CompilationUnit root, int offset, int length) { 69 return initialize(root, NodeFinder.perform(root, offset, length)); 70 } 71 72 75 public String initialize(CompilationUnit root, ASTNode node) { 76 ASTNode controlNode= getBreakOrContinueNode(node); 77 if (controlNode != null){ 78 fContents= getContents(root); 79 if (fContents == null) 80 return SearchMessages.BreakContinueTargetFinder_cannot_highlight; 81 82 fSelected= controlNode; 83 fIsBreak= fSelected instanceof BreakStatement; 84 fLabel= getLabel(); 85 return null; 86 } else { 87 return SearchMessages.BreakContinueTargetFinder_no_break_or_continue_selected; 88 } 89 } 90 91 92 private String getContents(CompilationUnit root) { 93 try { 94 IJavaElement rootElem= root.getJavaElement(); 95 if ((rootElem instanceof ISourceReference)) 96 return ((ISourceReference)rootElem).getSource(); 97 else 98 return null; 99 } catch (JavaModelException e) { 100 102 104 JavaPlugin.log(e); 105 return null; 106 } 107 } 108 109 private ASTNode getBreakOrContinueNode(ASTNode selectedNode) { 111 if (selectedNode instanceof BreakStatement) 112 return selectedNode; 113 if (selectedNode instanceof ContinueStatement) 114 return selectedNode; 115 if (selectedNode instanceof SimpleName && selectedNode.getParent() instanceof BreakStatement) 116 return selectedNode.getParent(); 117 if (selectedNode instanceof SimpleName && selectedNode.getParent() instanceof ContinueStatement) 118 return selectedNode.getParent(); 119 return null; 120 } 121 122 public List perform() { 123 return getNodesToHighlight(); 124 } 125 126 private SimpleName getLabel() { 127 if (fIsBreak){ 128 BreakStatement bs= (BreakStatement) fSelected; 129 return bs.getLabel(); 130 } else { 131 ContinueStatement cs= (ContinueStatement) fSelected; 132 return cs.getLabel(); 133 } 134 } 135 136 private List getNodesToHighlight() { 137 ASTNode targetNode= findTargetNode(fSelected); 138 if (!isEnclosingStatement(targetNode)) 139 return Collections.EMPTY_LIST; 140 141 List list= new ArrayList (); 142 ASTNode node= makeFakeNodeForFirstToken(targetNode); 143 if (node != null) 144 list.add(node); 145 146 if (fIsBreak) { 147 node= makeFakeNodeForClosingBrace(targetNode); 148 if (node != null) 149 list.add(node); 150 } 151 152 return list; 153 154 } 155 156 private boolean isEnclosingStatement(ASTNode targetNode) { 157 return (targetNode != null) && !(targetNode instanceof MethodDeclaration) && !(targetNode instanceof Initializer); 158 } 159 160 private ASTNode findTargetNode(ASTNode node) { 161 do { 162 node= node.getParent(); 163 } while (keepWalkingUp(node)); 164 return node; 165 } 166 167 private ASTNode makeFakeNodeForFirstToken(ASTNode node) { 168 try { 169 int length= getLengthOfFirstTokenOf(node); 170 if (length < 1) 171 return node; return makeFakeNode(node.getStartPosition(), length, node.getAST()); 173 } catch (InvalidInputException e) { 174 return node; } 176 } 177 178 private SimpleName makeFakeNode(int start, int length, AST ast) { 179 String fakeName= makeStringOfLength(length); 180 SimpleName name= ast.newSimpleName(fakeName); 181 name.setSourceRange(start, length); 182 return name; 183 } 184 185 private ASTNode makeFakeNodeForClosingBrace(ASTNode targetNode) { 186 ASTNode maybeBlock= getOptionalBlock(targetNode); 187 if (maybeBlock == null) 188 return null; 189 190 192 return makeFakeNode(ASTNodes.getExclusiveEnd(maybeBlock)-BRACE_LENGTH, BRACE_LENGTH, targetNode.getAST()); 193 } 194 195 199 private ASTNode getOptionalBlock(ASTNode targetNode) { 200 final ASTNode[] maybeBlock= new ASTNode[1]; 201 targetNode.accept(new ASTVisitor(){ 202 public boolean visit(ForStatement node) { 203 if (node.getBody() instanceof Block) 204 maybeBlock[0]= node.getBody(); 205 return false; 206 } 207 public boolean visit(EnhancedForStatement node) { 208 if (node.getBody() instanceof Block) 209 maybeBlock[0]= node.getBody(); 210 return false; 211 } 212 public boolean visit(WhileStatement node) { 213 if (node.getBody() instanceof Block) 214 maybeBlock[0]= node.getBody(); 215 return false; 216 } 217 public boolean visit(DoStatement node) { 218 if (node.getBody() instanceof Block) 219 maybeBlock[0]= node.getBody(); 220 return false; 221 } 222 public boolean visit(SwitchStatement node) { 223 maybeBlock[0]= node; 224 return false; 225 } 226 }); 227 return maybeBlock[0]; 228 } 229 230 private static String makeStringOfLength(int length) { 231 char[] chars= new char[length]; 232 Arrays.fill(chars, 'x'); 233 return new String (chars); 234 } 235 236 private int getLengthOfFirstTokenOf(ASTNode node) throws InvalidInputException { 238 IScanner scanner= ToolFactory.createScanner(true, true, false, true); 239 scanner.setSource(getSource(node).toCharArray()); 240 scanner.getNextToken(); 241 return scanner.getRawTokenSource().length; 242 } 243 244 private String getSource(ASTNode node) { 245 return fContents.substring(node.getStartPosition(), ASTNodes.getInclusiveEnd(node)); 246 } 247 248 private boolean keepWalkingUp(ASTNode node) { 249 if (node == null) 250 return false; 251 if (isAnyInstanceOf(STOPPERS, node)) 252 return false; 253 if (fLabel != null && LabeledStatement.class.isInstance(node)){ 254 LabeledStatement ls= (LabeledStatement)node; 255 return ! areEqualLabels(ls.getLabel(), fLabel); 256 } 257 if (fLabel == null && fIsBreak && isAnyInstanceOf(BREAKTARGETS, node)) 258 return false; 259 if (fLabel == null && !fIsBreak && isAnyInstanceOf(CONTINUETARGETS, node)) 260 return false; 261 return true; 262 } 263 264 private static boolean areEqualLabels(SimpleName labelToMatch, SimpleName labelSelected) { 267 return labelSelected.getIdentifier().equals(labelToMatch.getIdentifier()); 268 } 269 270 private static boolean isAnyInstanceOf(Class [] continueTargets, ASTNode node) { 271 for (int i= 0; i < continueTargets.length; i++) { 272 if (continueTargets[i].isInstance(node)) 273 return true; 274 } 275 return false; 276 } 277 } 278 | Popular Tags |