1 11 package org.eclipse.jdt.internal.ui.text.correction; 12 13 import java.util.ArrayList ; 14 import java.util.Iterator ; 15 import java.util.List ; 16 17 import org.eclipse.core.runtime.CoreException; 18 19 import org.eclipse.swt.graphics.Image; 20 21 import org.eclipse.jdt.core.ICompilationUnit; 22 import org.eclipse.jdt.core.IJavaProject; 23 import org.eclipse.jdt.core.dom.AST; 24 import org.eclipse.jdt.core.dom.ASTNode; 25 import org.eclipse.jdt.core.dom.ASTVisitor; 26 import org.eclipse.jdt.core.dom.Assignment; 27 import org.eclipse.jdt.core.dom.Block; 28 import org.eclipse.jdt.core.dom.CompilationUnit; 29 import org.eclipse.jdt.core.dom.EnhancedForStatement; 30 import org.eclipse.jdt.core.dom.Expression; 31 import org.eclipse.jdt.core.dom.FieldAccess; 32 import org.eclipse.jdt.core.dom.ForStatement; 33 import org.eclipse.jdt.core.dom.IBinding; 34 import org.eclipse.jdt.core.dom.IMethodBinding; 35 import org.eclipse.jdt.core.dom.ITypeBinding; 36 import org.eclipse.jdt.core.dom.IVariableBinding; 37 import org.eclipse.jdt.core.dom.MethodInvocation; 38 import org.eclipse.jdt.core.dom.Name; 39 import org.eclipse.jdt.core.dom.NullLiteral; 40 import org.eclipse.jdt.core.dom.SimpleName; 41 import org.eclipse.jdt.core.dom.SingleVariableDeclaration; 42 import org.eclipse.jdt.core.dom.Statement; 43 import org.eclipse.jdt.core.dom.VariableDeclarationExpression; 44 import org.eclipse.jdt.core.dom.VariableDeclarationFragment; 45 import org.eclipse.jdt.core.dom.rewrite.ASTRewrite; 46 import org.eclipse.jdt.core.dom.rewrite.ListRewrite; 47 48 import org.eclipse.jdt.internal.corext.codemanipulation.StubUtility; 49 import org.eclipse.jdt.internal.corext.dom.ASTNodes; 50 import org.eclipse.jdt.internal.corext.dom.ScopeAnalyzer; 51 import org.eclipse.jdt.internal.corext.util.JavaModelUtil; 52 53 58 public final class ConvertIterableLoopProposal extends LinkedCorrectionProposal { 59 60 61 private static final String GROUP_ELEMENT= "element"; 63 70 private static ITypeBinding getSuperType(final ITypeBinding binding, final String name) { 71 72 if (binding.isArray() || binding.isPrimitive()) 73 return null; 74 75 if (binding.getQualifiedName().startsWith(name)) 76 return binding; 77 78 final ITypeBinding type= binding.getSuperclass(); 79 if (type != null) { 80 final ITypeBinding result= getSuperType(type, name); 81 if (result != null) 82 return result; 83 } 84 final ITypeBinding[] types= binding.getInterfaces(); 85 for (int index= 0; index < types.length; index++) { 86 final ITypeBinding result= getSuperType(types[index], name); 87 if (result != null) 88 return result; 89 } 90 return null; 91 } 92 93 94 private boolean fAssigned= false; 95 96 97 private final AST fAst; 98 99 100 private IBinding fElement= null; 101 102 103 private Expression fExpression= null; 104 105 106 private IBinding fIterable= null; 107 108 109 private IVariableBinding fIterator= null; 110 111 112 private List fOccurrences= new ArrayList (2); 113 114 115 private final ForStatement fStatement; 116 117 126 public ConvertIterableLoopProposal(final String name, final ICompilationUnit unit, final ForStatement statement, final int relevance, final Image image) { 127 super(name, unit, null, relevance, image); 128 fStatement= statement; 129 fAst= statement.getAST(); 130 } 131 132 private List computeElementNames() { 133 final List names= new ArrayList (); 134 final IJavaProject project= getCompilationUnit().getJavaProject(); 135 String name= GROUP_ELEMENT; 136 final ITypeBinding binding= fIterator.getType(); 137 if (binding != null && binding.isParameterizedType()) 138 name= binding.getTypeArguments()[0].getName(); 139 final List excluded= getExcludedNames(); 140 final String [] suggestions= StubUtility.getLocalNameSuggestions(project, name, 0, (String []) excluded.toArray(new String [excluded.size()])); 141 for (int index= 0; index < suggestions.length; index++) 142 names.add(suggestions[index]); 143 return names; 144 } 145 146 private List getExcludedNames() { 147 final CompilationUnit unit= (CompilationUnit) fStatement.getRoot(); 148 final IBinding[] before= (new ScopeAnalyzer(unit)).getDeclarationsInScope(fStatement.getStartPosition(), ScopeAnalyzer.VARIABLES); 149 final IBinding[] after= (new ScopeAnalyzer(unit)).getDeclarationsAfter(fStatement.getStartPosition() + fStatement.getLength(), ScopeAnalyzer.VARIABLES); 150 final List names= new ArrayList (); 151 for (int index= 0; index < before.length; index++) 152 names.add(before[index].getName()); 153 for (int index= 0; index < after.length; index++) 154 names.add(after[index].getName()); 155 return names; 156 } 157 158 164 private Expression getExpression(final ASTRewrite rewrite) { 165 if (fExpression instanceof MethodInvocation) 166 return (MethodInvocation) rewrite.createMoveTarget(fExpression); 167 return (Expression) ASTNode.copySubtree(rewrite.getAST(), fExpression); 168 } 169 170 176 private ITypeBinding getIterableType(final ITypeBinding iterator) { 177 if (iterator != null) { 178 final ITypeBinding[] bindings= iterator.getTypeArguments(); 179 if (bindings.length > 0) 180 return bindings[0]; 181 } 182 return fAst.resolveWellKnownType("java.lang.Object"); } 184 185 188 protected final ASTRewrite getRewrite() throws CoreException { 189 final ASTRewrite rewrite= ASTRewrite.create(fAst); 190 final EnhancedForStatement statement= fAst.newEnhancedForStatement(); 191 final List names= computeElementNames(); 192 String name= GROUP_ELEMENT; 193 if (fElement != null) { 194 name= fElement.getName(); 195 if (!names.contains(name)) 196 names.add(0, name); 197 } else { 198 if (!names.isEmpty()) 199 name= (String ) names.get(0); 200 } 201 for (final Iterator iterator= names.iterator(); iterator.hasNext();) 202 addLinkedPositionProposal(GROUP_ELEMENT, (String ) iterator.next(), null); 203 final Statement body= fStatement.getBody(); 204 if (body != null) { 205 if (body instanceof Block) { 206 final ListRewrite list= rewrite.getListRewrite(body, Block.STATEMENTS_PROPERTY); 207 for (final Iterator iterator= fOccurrences.iterator(); iterator.hasNext();) { 208 final Statement parent= (Statement) ASTNodes.getParent((ASTNode) iterator.next(), Statement.class); 209 if (parent != null && list.getRewrittenList().contains(parent)) 210 list.remove(parent, null); 211 } 212 final String text= name; 213 body.accept(new ASTVisitor() { 214 215 private boolean replace(final Expression expression) { 216 final SimpleName node= fAst.newSimpleName(text); 217 rewrite.replace(expression, node, null); 218 addLinkedPosition(rewrite.track(node), false, GROUP_ELEMENT); 219 return false; 220 } 221 222 public final boolean visit(final MethodInvocation node) { 223 final IMethodBinding binding= node.resolveMethodBinding(); 224 if (binding != null && binding.getName().equals("next")) { final Expression expression= node.getExpression(); 226 if (expression instanceof Name) { 227 final IBinding result= ((Name) expression).resolveBinding(); 228 if (result != null && result.equals(fIterator)) 229 return replace(node); 230 } else if (expression instanceof MethodInvocation) { 231 final IBinding result= ((MethodInvocation) expression).resolveMethodBinding(); 232 if (result != null && result.equals(fIterator)) 233 return replace(node); 234 } else if (expression instanceof FieldAccess) { 235 final IBinding result= ((FieldAccess) expression).resolveFieldBinding(); 236 if (result != null && result.equals(fIterator)) 237 return replace(node); 238 } 239 } 240 return super.visit(node); 241 } 242 243 public final boolean visit(final SimpleName node) { 244 if (fElement != null) { 245 final IBinding binding= node.resolveBinding(); 246 if (binding != null && binding.equals(fElement)) { 247 final Statement parent= (Statement) ASTNodes.getParent(node, Statement.class); 248 if (parent != null && list.getRewrittenList().contains(parent)) 249 addLinkedPosition(rewrite.track(node), false, GROUP_ELEMENT); 250 } 251 } 252 return false; 253 } 254 }); 255 } 256 statement.setBody((Statement) rewrite.createMoveTarget(body)); 257 } 258 final SingleVariableDeclaration declaration= fAst.newSingleVariableDeclaration(); 259 final SimpleName simple= fAst.newSimpleName(name); 260 addLinkedPosition(rewrite.track(simple), true, GROUP_ELEMENT); 261 declaration.setName(simple); 262 declaration.setType(getImportRewrite().addImport(getIterableType(fIterator.getType()), fAst)); 263 statement.setParameter(declaration); 264 statement.setExpression(getExpression(rewrite)); 265 rewrite.replace(fStatement, statement, null); 266 return rewrite; 267 } 268 269 274 public final boolean isApplicable() { 275 if (JavaModelUtil.is50OrHigher(getCompilationUnit().getJavaProject())) { 276 for (final Iterator outer= fStatement.initializers().iterator(); outer.hasNext();) { 277 final Expression initializer= (Expression) outer.next(); 278 if (initializer instanceof VariableDeclarationExpression) { 279 final VariableDeclarationExpression declaration= (VariableDeclarationExpression) initializer; 280 for (Iterator inner= declaration.fragments().iterator(); inner.hasNext();) { 281 final VariableDeclarationFragment fragment= (VariableDeclarationFragment) inner.next(); 282 fragment.accept(new ASTVisitor() { 283 284 public final boolean visit(final MethodInvocation node) { 285 final IMethodBinding binding= node.resolveMethodBinding(); 286 if (binding != null && binding.getName().equals("iterator")) { final Expression qualifier= node.getExpression(); 288 if (qualifier != null) { 289 final ITypeBinding type= qualifier.resolveTypeBinding(); 290 if (type != null) { 291 final ITypeBinding iterable= getSuperType(type, "java.lang.Iterable"); if (iterable != null) { 293 fExpression= qualifier; 294 if (qualifier instanceof Name) { 295 final Name name= (Name) qualifier; 296 fIterable= name.resolveBinding(); 297 } else if (qualifier instanceof MethodInvocation) { 298 final MethodInvocation invocation= (MethodInvocation) qualifier; 299 fIterable= invocation.resolveMethodBinding(); 300 } else if (qualifier instanceof FieldAccess) { 301 final FieldAccess access= (FieldAccess) qualifier; 302 fIterable= access.resolveFieldBinding(); 303 } 304 } 305 } 306 } 307 } 308 return true; 309 } 310 311 public final boolean visit(final VariableDeclarationFragment node) { 312 final IVariableBinding binding= node.resolveBinding(); 313 if (binding != null) { 314 final ITypeBinding type= binding.getType(); 315 if (type != null) { 316 final ITypeBinding iterator= getSuperType(type, "java.util.Iterator"); if (iterator != null) 318 fIterator= binding; 319 } 320 } 321 return true; 322 } 323 }); 324 } 325 } 326 } 327 final Statement statement= fStatement.getBody(); 328 if (statement != null && fIterator != null) { 329 final ITypeBinding iterable= getIterableType(fIterator.getType()); 330 statement.accept(new ASTVisitor() { 331 332 public final boolean visit(final Assignment node) { 333 return visit(node.getLeftHandSide(), node.getRightHandSide()); 334 } 335 336 private boolean visit(final Expression node) { 337 if (node != null) { 338 final ITypeBinding binding= node.resolveTypeBinding(); 339 if (binding != null && iterable.equals(binding)) { 340 if (node instanceof Name) { 341 final Name name= (Name) node; 342 final IBinding result= name.resolveBinding(); 343 if (result != null) { 344 fOccurrences.add(node); 345 fElement= result; 346 return false; 347 } 348 } else if (node instanceof FieldAccess) { 349 final FieldAccess access= (FieldAccess) node; 350 final IBinding result= access.resolveFieldBinding(); 351 if (result != null) { 352 fOccurrences.add(node); 353 fElement= result; 354 return false; 355 } 356 } 357 } 358 } 359 return true; 360 } 361 362 private boolean visit(final Expression left, final Expression right) { 363 if (right instanceof MethodInvocation) { 364 final MethodInvocation invocation= (MethodInvocation) right; 365 final IMethodBinding binding= invocation.resolveMethodBinding(); 366 if (binding != null && binding.getName().equals("next")) { final Expression expression= invocation.getExpression(); 368 if (expression instanceof Name) { 369 final Name qualifier= (Name) expression; 370 final IBinding result= qualifier.resolveBinding(); 371 if (result != null && result.equals(fIterator)) 372 return visit(left); 373 } else if (expression instanceof MethodInvocation) { 374 final MethodInvocation qualifier= (MethodInvocation) expression; 375 final IBinding result= qualifier.resolveMethodBinding(); 376 if (result != null && result.equals(fIterator)) 377 return visit(left); 378 } else if (expression instanceof FieldAccess) { 379 final FieldAccess qualifier= (FieldAccess) expression; 380 final IBinding result= qualifier.resolveFieldBinding(); 381 if (result != null && result.equals(fIterator)) 382 return visit(left); 383 } 384 } 385 } else if (right instanceof NullLiteral) 386 return visit(left); 387 return true; 388 } 389 390 public final boolean visit(final VariableDeclarationFragment node) { 391 return visit(node.getName(), node.getInitializer()); 392 } 393 }); 394 } 395 final ASTNode root= fStatement.getRoot(); 396 if (root != null) { 397 root.accept(new ASTVisitor() { 398 399 public final boolean visit(final ForStatement node) { 400 return false; 401 } 402 403 public final boolean visit(final SimpleName node) { 404 final IBinding binding= node.resolveBinding(); 405 if (binding != null && binding.equals(fElement)) 406 fAssigned= true; 407 return false; 408 } 409 }); 410 } 411 } 412 return fExpression != null && fIterable != null && fIterator != null && !fAssigned; 413 } 414 } | Popular Tags |