1 11 package org.eclipse.jdt.internal.corext.fix; 12 13 import java.util.ArrayList ; 14 import java.util.HashSet ; 15 import java.util.Hashtable ; 16 import java.util.Iterator ; 17 import java.util.List ; 18 import java.util.ListIterator ; 19 import java.util.Map ; 20 21 import org.eclipse.text.edits.TextEditGroup; 22 23 import org.eclipse.core.runtime.CoreException; 24 25 import org.eclipse.jdt.core.compiler.IProblem; 26 import org.eclipse.jdt.core.dom.ASTNode; 27 import org.eclipse.jdt.core.dom.ASTVisitor; 28 import org.eclipse.jdt.core.dom.Assignment; 29 import org.eclipse.jdt.core.dom.Block; 30 import org.eclipse.jdt.core.dom.CastExpression; 31 import org.eclipse.jdt.core.dom.ClassInstanceCreation; 32 import org.eclipse.jdt.core.dom.CompilationUnit; 33 import org.eclipse.jdt.core.dom.EnhancedForStatement; 34 import org.eclipse.jdt.core.dom.Expression; 35 import org.eclipse.jdt.core.dom.ExpressionStatement; 36 import org.eclipse.jdt.core.dom.FieldAccess; 37 import org.eclipse.jdt.core.dom.FieldDeclaration; 38 import org.eclipse.jdt.core.dom.IBinding; 39 import org.eclipse.jdt.core.dom.IMethodBinding; 40 import org.eclipse.jdt.core.dom.ITypeBinding; 41 import org.eclipse.jdt.core.dom.IVariableBinding; 42 import org.eclipse.jdt.core.dom.ImportDeclaration; 43 import org.eclipse.jdt.core.dom.Javadoc; 44 import org.eclipse.jdt.core.dom.MethodDeclaration; 45 import org.eclipse.jdt.core.dom.MethodInvocation; 46 import org.eclipse.jdt.core.dom.ParenthesizedExpression; 47 import org.eclipse.jdt.core.dom.PostfixExpression; 48 import org.eclipse.jdt.core.dom.PrefixExpression; 49 import org.eclipse.jdt.core.dom.QualifiedName; 50 import org.eclipse.jdt.core.dom.SimpleName; 51 import org.eclipse.jdt.core.dom.SingleVariableDeclaration; 52 import org.eclipse.jdt.core.dom.SuperMethodInvocation; 53 import org.eclipse.jdt.core.dom.TagElement; 54 import org.eclipse.jdt.core.dom.Type; 55 import org.eclipse.jdt.core.dom.TypeDeclarationStatement; 56 import org.eclipse.jdt.core.dom.VariableDeclarationExpression; 57 import org.eclipse.jdt.core.dom.VariableDeclarationFragment; 58 import org.eclipse.jdt.core.dom.VariableDeclarationStatement; 59 import org.eclipse.jdt.core.dom.rewrite.ASTRewrite; 60 import org.eclipse.jdt.core.dom.rewrite.ListRewrite; 61 62 import org.eclipse.jdt.internal.corext.dom.ASTNodes; 63 import org.eclipse.jdt.internal.corext.dom.LinkedNodeFinder; 64 import org.eclipse.jdt.internal.corext.dom.NodeFinder; 65 import org.eclipse.jdt.internal.corext.refactoring.structure.CompilationUnitRewrite; 66 import org.eclipse.jdt.internal.corext.util.Messages; 67 68 import org.eclipse.jdt.ui.text.java.IProblemLocation; 69 70 import org.eclipse.jdt.internal.ui.fix.UnusedCodeCleanUp; 71 import org.eclipse.jdt.internal.ui.text.correction.JavadocTagsSubProcessor; 72 import org.eclipse.jdt.internal.ui.text.correction.ProblemLocation; 73 74 77 public class UnusedCodeFix extends AbstractFix { 78 79 private static class SideEffectFinder extends ASTVisitor { 80 81 private final ArrayList fSideEffectNodes; 82 83 public SideEffectFinder(ArrayList res) { 84 fSideEffectNodes= res; 85 } 86 87 public boolean visit(Assignment node) { 88 fSideEffectNodes.add(node); 89 return false; 90 } 91 92 public boolean visit(PostfixExpression node) { 93 fSideEffectNodes.add(node); 94 return false; 95 } 96 97 public boolean visit(PrefixExpression node) { 98 Object operator= node.getOperator(); 99 if (operator == PrefixExpression.Operator.INCREMENT || operator == PrefixExpression.Operator.DECREMENT) { 100 fSideEffectNodes.add(node); 101 } 102 return false; 103 } 104 105 public boolean visit(MethodInvocation node) { 106 fSideEffectNodes.add(node); 107 return false; 108 } 109 110 public boolean visit(ClassInstanceCreation node) { 111 fSideEffectNodes.add(node); 112 return false; 113 } 114 115 public boolean visit(SuperMethodInvocation node) { 116 fSideEffectNodes.add(node); 117 return false; 118 } 119 } 120 121 private static class RemoveImportOperation extends AbstractFixRewriteOperation { 122 123 private final ImportDeclaration fImportDeclaration; 124 125 public RemoveImportOperation(ImportDeclaration importDeclaration) { 126 fImportDeclaration= importDeclaration; 127 } 128 129 132 public void rewriteAST(CompilationUnitRewrite cuRewrite, List textEditGroups) throws CoreException { 133 ImportDeclaration node= fImportDeclaration; 134 TextEditGroup group= createTextEditGroup(FixMessages.UnusedCodeFix_RemoveImport_description); 135 cuRewrite.getASTRewrite().remove(node, group); 136 textEditGroups.add(group); 137 } 138 139 } 140 141 private static class RemoveUnusedMemberOperation extends AbstractFixRewriteOperation { 142 143 private final SimpleName[] fUnusedNames; 144 private boolean fForceRemove; 145 private int fRemovedAssignmentsCount; 146 private int fAlteredAssignmentsCount; 147 148 public RemoveUnusedMemberOperation(SimpleName[] unusedNames, boolean forceRemoveInitializer) { 149 fUnusedNames= unusedNames; 150 fForceRemove=forceRemoveInitializer; 151 } 152 153 156 public void rewriteAST(CompilationUnitRewrite cuRewrite, List textEditGroups) throws CoreException { 157 for (int i= 0; i < fUnusedNames.length; i++) { 158 removeUnusedName(cuRewrite.getASTRewrite(), fUnusedNames[i], cuRewrite.getRoot(), textEditGroups); 159 } 160 } 161 162 private void removeUnusedName(ASTRewrite rewrite, SimpleName simpleName, CompilationUnit completeRoot, List groups) { 163 IBinding binding= simpleName.resolveBinding(); 164 CompilationUnit root= (CompilationUnit) simpleName.getRoot(); 165 String displayString= getDisplayString(binding); 166 TextEditGroup group= createTextEditGroup(displayString); 167 groups.add(group); 168 if (binding.getKind() == IBinding.METHOD) { 169 IMethodBinding decl= ((IMethodBinding) binding).getMethodDeclaration(); 170 ASTNode declaration= root.findDeclaringNode(decl); 171 rewrite.remove(declaration, group); 172 } else if (binding.getKind() == IBinding.TYPE) { 173 ITypeBinding decl= ((ITypeBinding) binding).getTypeDeclaration(); 174 ASTNode declaration= root.findDeclaringNode(decl); 175 if (declaration.getParent() instanceof TypeDeclarationStatement) { 176 declaration= declaration.getParent(); 177 } 178 rewrite.remove(declaration, group); 179 } else if (binding.getKind() == IBinding.VARIABLE) { 180 SimpleName nameNode= (SimpleName) NodeFinder.perform(completeRoot, simpleName.getStartPosition(), simpleName.getLength()); 181 SimpleName[] references= LinkedNodeFinder.findByBinding(completeRoot, nameNode.resolveBinding()); 182 for (int i= 0; i < references.length; i++) { 183 removeVariableReferences(rewrite, references[i], group); 184 } 185 186 IVariableBinding bindingDecl= ((IVariableBinding) nameNode.resolveBinding()).getVariableDeclaration(); 187 ASTNode declaringNode= completeRoot.findDeclaringNode(bindingDecl); 188 if (declaringNode instanceof SingleVariableDeclaration) { 189 removeParamTag(rewrite, (SingleVariableDeclaration) declaringNode, group); 190 } 191 } else { 192 } 194 } 195 196 private String getDisplayString(IBinding binding) { 197 switch (binding.getKind()) { 198 case IBinding.TYPE: 199 return FixMessages.UnusedCodeFix_RemoveUnusedType_description; 200 case IBinding.METHOD: 201 if (((IMethodBinding) binding).isConstructor()) { 202 return FixMessages.UnusedCodeFix_RemoveUnusedConstructor_description; 203 } else { 204 return FixMessages.UnusedCodeFix_RemoveUnusedPrivateMethod_description; 205 } 206 case IBinding.VARIABLE: 207 if (((IVariableBinding) binding).isField()) { 208 return FixMessages.UnusedCodeFix_RemoveUnusedField_description; 209 } else { 210 return FixMessages.UnusedCodeFix_RemoveUnusedVariabl_description; 211 } 212 default: 213 return ""; } 215 } 216 217 private void removeParamTag(ASTRewrite rewrite, SingleVariableDeclaration varDecl, TextEditGroup group) { 218 if (varDecl.getParent() instanceof MethodDeclaration) { 219 Javadoc javadoc= ((MethodDeclaration) varDecl.getParent()).getJavadoc(); 220 if (javadoc != null) { 221 TagElement tagElement= JavadocTagsSubProcessor.findParamTag(javadoc, varDecl.getName().getIdentifier()); 222 if (tagElement != null) { 223 rewrite.remove(tagElement, group); 224 } 225 } 226 } 227 } 228 229 235 private void removeVariableReferences(ASTRewrite rewrite, SimpleName reference, TextEditGroup group) { 236 ASTNode parent= reference.getParent(); 237 while (parent instanceof QualifiedName) { 238 parent= parent.getParent(); 239 } 240 if (parent instanceof FieldAccess) { 241 parent= parent.getParent(); 242 } 243 244 int nameParentType= parent.getNodeType(); 245 if (nameParentType == ASTNode.ASSIGNMENT) { 246 Assignment assignment= (Assignment) parent; 247 Expression rightHand= assignment.getRightHandSide(); 248 249 ASTNode assignParent= assignment.getParent(); 250 if (assignParent.getNodeType() == ASTNode.EXPRESSION_STATEMENT && rightHand.getNodeType() != ASTNode.ASSIGNMENT) { 251 removeVariableWithInitializer(rewrite, rightHand, assignParent, group); 252 } else { 253 rewrite.replace(assignment, rewrite.createCopyTarget(rightHand), group); 254 } 255 } else if (nameParentType == ASTNode.SINGLE_VARIABLE_DECLARATION) { 256 rewrite.remove(parent, group); 257 } else if (nameParentType == ASTNode.VARIABLE_DECLARATION_FRAGMENT) { 258 VariableDeclarationFragment frag= (VariableDeclarationFragment) parent; 259 ASTNode varDecl= frag.getParent(); 260 List fragments; 261 if (varDecl instanceof VariableDeclarationExpression) { 262 fragments= ((VariableDeclarationExpression) varDecl).fragments(); 263 } else if (varDecl instanceof FieldDeclaration) { 264 fragments= ((FieldDeclaration) varDecl).fragments(); 265 } else { 266 fragments= ((VariableDeclarationStatement) varDecl).fragments(); 267 } 268 Expression initializer = frag.getInitializer(); 269 boolean sideEffectInitializer = initializer instanceof MethodInvocation || initializer instanceof ClassInstanceCreation; 270 if (fragments.size() == fUnusedNames.length) { 271 if (fForceRemove) { 272 rewrite.remove(varDecl, group); 273 return; 274 } 275 if (parent.getParent() instanceof FieldDeclaration) { 276 rewrite.remove(varDecl, group); 277 return; 278 } 279 if (sideEffectInitializer){ 280 Expression movedInit = (Expression) rewrite.createMoveTarget(initializer); 281 ExpressionStatement wrapped = rewrite.getAST().newExpressionStatement(movedInit); 282 rewrite.replace(varDecl, wrapped, group); 283 } else { 284 rewrite.remove(varDecl, group); 285 } 286 } else { 287 if (fForceRemove) { 288 rewrite.remove(frag, group); 289 return; 290 } 291 ASTNode declaration = parent.getParent(); 293 if (declaration instanceof FieldDeclaration) { 294 rewrite.remove(frag, group); 295 return; 296 } 297 if (declaration instanceof VariableDeclarationStatement) { 298 ASTNode lst = declaration.getParent(); 299 if (lst instanceof Block) 300 splitUpDeclarations(rewrite, group, frag, lst, (VariableDeclarationStatement) declaration); 301 rewrite.remove(frag, group); 302 return; 303 } 304 if (declaration instanceof VariableDeclarationExpression) { 305 if (!sideEffectInitializer){ 307 rewrite.remove(frag, group); 308 } 309 } 310 } 311 } 312 } 313 314 private void splitUpDeclarations(ASTRewrite rewrite, TextEditGroup group, VariableDeclarationFragment frag, ASTNode block, VariableDeclarationStatement originalStatement) { 315 Expression initializer = frag.getInitializer(); 316 if (initializer instanceof MethodInvocation || initializer instanceof ClassInstanceCreation){ 318 Expression movedInitializer= (Expression) rewrite.createMoveTarget(initializer); 319 ListRewrite statementRewrite= rewrite.getListRewrite(block, Block.STATEMENTS_PROPERTY); 320 ExpressionStatement newInitializer= rewrite.getAST().newExpressionStatement( movedInitializer); 321 statementRewrite.insertAfter(newInitializer, originalStatement, group); 322 323 VariableDeclarationStatement newDeclaration= null; 324 List fragments= originalStatement.fragments(); 325 int fragIndex= fragments.indexOf(frag); 326 ListIterator fragmentIterator= fragments.listIterator(fragIndex+1); 327 while (fragmentIterator.hasNext()) { 328 VariableDeclarationFragment currentFragment= (VariableDeclarationFragment) fragmentIterator.next(); 329 VariableDeclarationFragment movedFragment= (VariableDeclarationFragment) rewrite.createMoveTarget(currentFragment); 330 if (newDeclaration == null) { 331 newDeclaration= rewrite.getAST().newVariableDeclarationStatement(movedFragment); 332 Type copiedType= (Type) rewrite.createCopyTarget(originalStatement.getType()); 333 newDeclaration.setType(copiedType); 334 } else 335 newDeclaration.fragments().add(movedFragment); 336 } 337 if (newDeclaration != null){ 338 statementRewrite.insertAfter(newDeclaration, newInitializer, group); 339 } 340 if (originalStatement.fragments().size() == newDeclaration.fragments().size() + 1){ 341 rewrite.remove(originalStatement, group); 342 } 343 } 344 } 345 346 private void removeVariableWithInitializer(ASTRewrite rewrite, ASTNode initializerNode, ASTNode statementNode, TextEditGroup group) { 347 boolean performRemove= fForceRemove; 348 if (!performRemove) { 349 ArrayList sideEffectNodes= new ArrayList (); 350 initializerNode.accept(new SideEffectFinder(sideEffectNodes)); 351 performRemove= sideEffectNodes.isEmpty(); 352 } 353 if (performRemove) { 354 if (ASTNodes.isControlStatementBody(statementNode.getLocationInParent())) { 355 rewrite.replace(statementNode, rewrite.getAST().newBlock(), group); 356 } else { 357 rewrite.remove(statementNode, group); 358 } 359 fRemovedAssignmentsCount++; 360 } else { 361 ASTNode initNode = rewrite.createMoveTarget(initializerNode); 362 ExpressionStatement statement = rewrite.getAST().newExpressionStatement((Expression) initNode); 363 rewrite.replace(statementNode, statement, null); 364 fAlteredAssignmentsCount++; 365 } 366 } 367 368 public String getAdditionalInfo() { 369 StringBuffer sb=new StringBuffer (); 370 if (fRemovedAssignmentsCount>0){ 371 sb.append(Messages.format(FixMessages.UnusedCodeFix_RemoveFieldOrLocal_RemovedAssignments_preview,String.valueOf(fRemovedAssignmentsCount))); 372 } 373 if (fAlteredAssignmentsCount>0){ 374 sb.append(Messages.format(FixMessages.UnusedCodeFix_RemoveFieldOrLocal_AlteredAssignments_preview,String.valueOf(fAlteredAssignmentsCount))); 375 } 376 if (sb.length()>0) { 377 return sb.toString(); 378 } else 379 return null; 380 } 381 } 382 383 private static class RemoveCastOperation extends AbstractFixRewriteOperation { 384 385 private final CastExpression fCast; 386 private final ASTNode fSelectedNode; 387 388 public RemoveCastOperation(CastExpression cast, ASTNode selectedNode) { 389 fCast= cast; 390 fSelectedNode= selectedNode; 391 } 392 393 396 public void rewriteAST(CompilationUnitRewrite cuRewrite, List textEditGroups) throws CoreException { 397 398 TextEditGroup group= createTextEditGroup(FixMessages.UnusedCodeFix_RemoveCast_description); 399 textEditGroups.add(group); 400 401 ASTRewrite rewrite= cuRewrite.getASTRewrite(); 402 403 CastExpression cast= fCast; 404 Expression expression= cast.getExpression(); 405 ASTNode placeholder= rewrite.createCopyTarget(expression); 406 407 if (ASTNodes.needsParentheses(expression)) { 408 rewrite.replace(fCast, placeholder, group); 409 } else { 410 rewrite.replace(fSelectedNode, placeholder, group); 411 } 412 } 413 } 414 415 private static class RemoveAllCastOperation extends AbstractFixRewriteOperation { 416 417 private final HashSet fUnnecessaryCasts; 418 419 public RemoveAllCastOperation(HashSet unnecessaryCasts) { 420 fUnnecessaryCasts= unnecessaryCasts; 421 } 422 423 426 public void rewriteAST(CompilationUnitRewrite cuRewrite, List textEditGroups) throws CoreException { 427 ASTRewrite rewrite= cuRewrite.getASTRewrite(); 428 429 TextEditGroup group= createTextEditGroup(FixMessages.UnusedCodeFix_RemoveCast_description); 430 textEditGroups.add(group); 431 432 while (fUnnecessaryCasts.size() > 0) { 433 CastExpression castExpression= (CastExpression)fUnnecessaryCasts.iterator().next(); 434 fUnnecessaryCasts.remove(castExpression); 435 CastExpression down= castExpression; 436 while (fUnnecessaryCasts.contains(down.getExpression())) { 437 down= (CastExpression)down.getExpression(); 438 fUnnecessaryCasts.remove(down); 439 } 440 441 ASTNode move= rewrite.createMoveTarget(down.getExpression()); 442 443 CastExpression top= castExpression; 444 while (fUnnecessaryCasts.contains(top.getParent())) { 445 top= (CastExpression)top.getParent(); 446 fUnnecessaryCasts.remove(top); 447 } 448 449 rewrite.replace(top, move, group); 450 } 451 } 452 } 453 454 public static UnusedCodeFix createRemoveUnusedImportFix(CompilationUnit compilationUnit, IProblemLocation problem) { 455 int id= problem.getProblemId(); 456 if (id == IProblem.UnusedImport || id == IProblem.DuplicateImport || id == IProblem.ConflictingImport || 457 id == IProblem.CannotImportPackage || id == IProblem.ImportNotFound) { 458 459 ImportDeclaration node= getImportDeclaration(problem, compilationUnit); 460 if (node != null) { 461 String label= FixMessages.UnusedCodeFix_RemoveImport_description; 462 RemoveImportOperation operation= new RemoveImportOperation(node); 463 Map options= new Hashtable (); 464 options.put(CleanUpConstants.REMOVE_UNUSED_CODE_IMPORTS, CleanUpConstants.TRUE); 465 return new UnusedCodeFix(label, compilationUnit, new IFixRewriteOperation[] {operation}, options); 466 } 467 } 468 return null; 469 } 470 471 public static UnusedCodeFix createUnusedMemberFix(CompilationUnit compilationUnit, IProblemLocation problem, boolean forceInitializerRemoval) { 472 int id= problem.getProblemId(); 473 if (id == IProblem.UnusedPrivateMethod || id == IProblem.UnusedPrivateConstructor || id == IProblem.UnusedPrivateField || 474 id == IProblem.UnusedPrivateType || id == IProblem.LocalVariableIsNeverUsed || id == IProblem.ArgumentIsNeverUsed) { 475 476 SimpleName name= getUnusedName(compilationUnit, problem); 477 if (name != null) { 478 IBinding binding= name.resolveBinding(); 479 if (binding != null) { 480 if (isFormalParameterInEnhancedForStatement(name)) 481 return null; 482 483 String label= getDisplayString(name, binding, forceInitializerRemoval); 484 RemoveUnusedMemberOperation operation= new RemoveUnusedMemberOperation(new SimpleName[] {name}, forceInitializerRemoval); 485 return new UnusedCodeFix(label, compilationUnit, new IFixRewriteOperation[] {operation}, getCleanUpOptions(binding)); 486 } 487 } 488 } 489 return null; 490 } 491 492 public static IFix createRemoveUnusedCastFix(CompilationUnit compilationUnit, IProblemLocation problem) { 493 if (problem.getProblemId() != IProblem.UnnecessaryCast) 494 return null; 495 496 ASTNode selectedNode= problem.getCoveringNode(compilationUnit); 497 498 ASTNode curr= selectedNode; 499 while (curr instanceof ParenthesizedExpression) { 500 curr= ((ParenthesizedExpression) curr).getExpression(); 501 } 502 503 if (!(curr instanceof CastExpression)) 504 return null; 505 506 return new UnusedCodeFix(FixMessages.UnusedCodeFix_RemoveCast_description, compilationUnit, new IFixRewriteOperation[] {new RemoveCastOperation((CastExpression)curr, selectedNode)}); 507 } 508 509 public static IFix createCleanUp(CompilationUnit compilationUnit, 510 boolean removeUnusedPrivateMethods, 511 boolean removeUnusedPrivateConstructors, 512 boolean removeUnusedPrivateFields, 513 boolean removeUnusedPrivateTypes, 514 boolean removeUnusedLocalVariables, 515 boolean removeUnusedImports, 516 boolean removeUnusedCast) { 517 518 IProblem[] problems= compilationUnit.getProblems(); 519 IProblemLocation[] locations= new IProblemLocation[problems.length]; 520 for (int i= 0; i < problems.length; i++) { 521 locations[i]= new ProblemLocation(problems[i]); 522 } 523 524 return createCleanUp(compilationUnit, locations, 525 removeUnusedPrivateMethods, 526 removeUnusedPrivateConstructors, 527 removeUnusedPrivateFields, 528 removeUnusedPrivateTypes, 529 removeUnusedLocalVariables, 530 removeUnusedImports, 531 removeUnusedCast); 532 } 533 534 public static IFix createCleanUp(CompilationUnit compilationUnit, IProblemLocation[] problems, 535 boolean removeUnusedPrivateMethods, 536 boolean removeUnusedPrivateConstructors, 537 boolean removeUnusedPrivateFields, 538 boolean removeUnusedPrivateTypes, 539 boolean removeUnusedLocalVariables, 540 boolean removeUnusedImports, 541 boolean removeUnusedCast) { 542 543 List result= new ArrayList (); 544 Hashtable variableDeclarations= new Hashtable (); 545 HashSet unnecessaryCasts= new HashSet (); 546 for (int i= 0; i < problems.length; i++) { 547 IProblemLocation problem= problems[i]; 548 int id= problem.getProblemId(); 549 550 if (removeUnusedImports && (id == IProblem.UnusedImport || id == IProblem.DuplicateImport || id == IProblem.ConflictingImport || 551 id == IProblem.CannotImportPackage || id == IProblem.ImportNotFound)) 552 { 553 ImportDeclaration node= UnusedCodeFix.getImportDeclaration(problem, compilationUnit); 554 if (node != null) { 555 result.add(new RemoveImportOperation(node)); 556 } 557 } 558 559 if ((removeUnusedPrivateMethods && id == IProblem.UnusedPrivateMethod) || (removeUnusedPrivateConstructors && id == IProblem.UnusedPrivateConstructor) || 560 (removeUnusedPrivateTypes && id == IProblem.UnusedPrivateType)) { 561 562 SimpleName name= getUnusedName(compilationUnit, problem); 563 if (name != null) { 564 IBinding binding= name.resolveBinding(); 565 if (binding != null) { 566 result.add(new RemoveUnusedMemberOperation(new SimpleName[] {name}, false)); 567 } 568 } 569 } 570 571 if ((removeUnusedLocalVariables && id == IProblem.LocalVariableIsNeverUsed) || (removeUnusedPrivateFields && id == IProblem.UnusedPrivateField)) { 572 SimpleName name= getUnusedName(compilationUnit, problem); 573 if (name != null) { 574 IBinding binding= name.resolveBinding(); 575 if (binding != null && !isFormalParameterInEnhancedForStatement(name) && isSideEffectFree(name, compilationUnit)) { 576 VariableDeclarationFragment parent= (VariableDeclarationFragment)ASTNodes.getParent(name, VariableDeclarationFragment.class); 577 if (parent != null) { 578 ASTNode varDecl= parent.getParent(); 579 if (!variableDeclarations.containsKey(varDecl)) { 580 variableDeclarations.put(varDecl, new ArrayList ()); 581 } 582 ((List )variableDeclarations.get(varDecl)).add(name); 583 } else { 584 result.add(new RemoveUnusedMemberOperation(new SimpleName[] {name}, false)); 585 } 586 } 587 } 588 } 589 590 if (removeUnusedCast && id == IProblem.UnnecessaryCast) { 591 ASTNode selectedNode= problem.getCoveringNode(compilationUnit); 592 593 ASTNode curr= selectedNode; 594 while (curr instanceof ParenthesizedExpression) { 595 curr= ((ParenthesizedExpression) curr).getExpression(); 596 } 597 598 if (curr instanceof CastExpression) { 599 unnecessaryCasts.add(curr); 600 } 601 } 602 } 603 for (Iterator iter= variableDeclarations.keySet().iterator(); iter.hasNext();) { 604 ASTNode node= (ASTNode)iter.next(); 605 List names= (List )variableDeclarations.get(node); 606 result.add(new RemoveUnusedMemberOperation((SimpleName[])names.toArray(new SimpleName[names.size()]), false)); 607 } 608 if (unnecessaryCasts.size() > 0) 609 result.add(new RemoveAllCastOperation(unnecessaryCasts)); 610 611 if (result.size() == 0) 612 return null; 613 614 return new UnusedCodeFix(FixMessages.UnusedCodeFix_change_name, compilationUnit, (IFixRewriteOperation[])result.toArray(new IFixRewriteOperation[result.size()])); 615 } 616 617 private static boolean isFormalParameterInEnhancedForStatement(SimpleName name) { 618 return name.getParent() instanceof SingleVariableDeclaration && name.getParent().getLocationInParent() == EnhancedForStatement.PARAMETER_PROPERTY; 619 } 620 621 private static boolean isSideEffectFree(SimpleName simpleName, CompilationUnit completeRoot) { 622 SimpleName nameNode= (SimpleName) NodeFinder.perform(completeRoot, simpleName.getStartPosition(), simpleName.getLength()); 623 SimpleName[] references= LinkedNodeFinder.findByBinding(completeRoot, nameNode.resolveBinding()); 624 for (int i= 0; i < references.length; i++) { 625 if (hasSideEffect(references[i])) 626 return false; 627 } 628 return true; 629 } 630 631 private static boolean hasSideEffect(SimpleName reference) { 632 ASTNode parent= reference.getParent(); 633 while (parent instanceof QualifiedName) { 634 parent= parent.getParent(); 635 } 636 if (parent instanceof FieldAccess) { 637 parent= parent.getParent(); 638 } 639 640 ASTNode node= null; 641 int nameParentType= parent.getNodeType(); 642 if (nameParentType == ASTNode.ASSIGNMENT) { 643 Assignment assignment= (Assignment) parent; 644 node= assignment.getRightHandSide(); 645 } else if (nameParentType == ASTNode.SINGLE_VARIABLE_DECLARATION) { 646 SingleVariableDeclaration decl= (SingleVariableDeclaration)parent; 647 node= decl.getInitializer(); 648 if (node == null) 649 return false; 650 } else if (nameParentType == ASTNode.VARIABLE_DECLARATION_FRAGMENT) { 651 node= parent; 652 } else { 653 return false; 654 } 655 656 ArrayList sideEffects= new ArrayList (); 657 node.accept(new SideEffectFinder(sideEffects)); 658 return sideEffects.size() > 0; 659 } 660 661 private static SimpleName getUnusedName(CompilationUnit compilationUnit, IProblemLocation problem) { 662 ASTNode selectedNode= problem.getCoveringNode(compilationUnit); 663 664 if (selectedNode instanceof MethodDeclaration) { 665 return ((MethodDeclaration) selectedNode).getName(); 666 } else if (selectedNode instanceof SimpleName) { 667 return (SimpleName) selectedNode; 668 } 669 670 return null; 671 } 672 673 private static String getDisplayString(SimpleName simpleName, IBinding binding, boolean forceRemoveInitializer) { 674 String name= simpleName.getIdentifier(); 675 switch (binding.getKind()) { 676 case IBinding.TYPE: 677 return Messages.format(FixMessages.UnusedCodeFix_RemoveType_description, name); 678 case IBinding.METHOD: 679 if (((IMethodBinding) binding).isConstructor()) { 680 return Messages.format(FixMessages.UnusedCodeFix_RemoveConstructor_description, name); 681 } else { 682 return Messages.format(FixMessages.UnusedCodeFix_RemoveMethod_description, name); 683 } 684 case IBinding.VARIABLE: 685 if (forceRemoveInitializer) { 686 return Messages.format(FixMessages.UnusedCodeFix_RemoveFieldOrLocalWithInitializer_description, name); 687 } else { 688 return Messages.format(FixMessages.UnusedCodeFix_RemoveFieldOrLocal_description, name); 689 } 690 default: 691 return ""; } 693 } 694 695 private static Map getCleanUpOptions(IBinding binding) { 696 Map result= new Hashtable (); 697 698 result.put(CleanUpConstants.REMOVE_UNUSED_CODE_PRIVATE_MEMBERS, CleanUpConstants.TRUE); 699 switch (binding.getKind()) { 700 case IBinding.TYPE: 701 result.put(CleanUpConstants.REMOVE_UNUSED_CODE_PRIVATE_TYPES, CleanUpConstants.TRUE); 702 break; 703 case IBinding.METHOD: 704 if (((IMethodBinding) binding).isConstructor()) { 705 result.put(CleanUpConstants.REMOVE_UNUSED_CODE_PRIVATE_CONSTRUCTORS, CleanUpConstants.TRUE); 706 } else { 707 result.put(CleanUpConstants.REMOVE_UNUSED_CODE_PRIVATE_METHODS, CleanUpConstants.TRUE); 708 } 709 break; 710 case IBinding.VARIABLE: 711 result.put(CleanUpConstants.REMOVE_UNUSED_CODE_PRIVATE_FELDS, CleanUpConstants.TRUE); 712 result.put(CleanUpConstants.REMOVE_UNUSED_CODE_LOCAL_VARIABLES, CleanUpConstants.TRUE); 713 break; 714 } 715 716 return result; 717 } 718 719 private static ImportDeclaration getImportDeclaration(IProblemLocation problem, CompilationUnit compilationUnit) { 720 ASTNode selectedNode= problem.getCoveringNode(compilationUnit); 721 if (selectedNode != null) { 722 ASTNode node= ASTNodes.getParent(selectedNode, ASTNode.IMPORT_DECLARATION); 723 if (node instanceof ImportDeclaration) { 724 return (ImportDeclaration)node; 725 } 726 } 727 return null; 728 } 729 730 private final Map fCleanUpOptions; 731 732 private UnusedCodeFix(String name, CompilationUnit compilationUnit, IFixRewriteOperation[] fixRewriteOperations) { 733 this(name, compilationUnit, fixRewriteOperations, null); 734 } 735 736 private UnusedCodeFix(String name, CompilationUnit compilationUnit, IFixRewriteOperation[] fixRewriteOperations, Map options) { 737 super(name, compilationUnit, fixRewriteOperations); 738 if (options == null) { 739 fCleanUpOptions= new Hashtable (); 740 } else { 741 fCleanUpOptions= options; 742 } 743 } 744 745 public UnusedCodeCleanUp getCleanUp() { 746 return new UnusedCodeCleanUp(fCleanUpOptions); 747 } 748 749 } 750 | Popular Tags |