KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > corext > fix > UnusedCodeFix


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.fix;
12
13 import java.util.ArrayList JavaDoc;
14 import java.util.HashSet JavaDoc;
15 import java.util.Hashtable JavaDoc;
16 import java.util.Iterator JavaDoc;
17 import java.util.List JavaDoc;
18 import java.util.ListIterator JavaDoc;
19 import java.util.Map JavaDoc;
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 /**
75  * Fix which removes unused code.
76  */

77 public class UnusedCodeFix extends AbstractFix {
78     
79     private static class SideEffectFinder extends ASTVisitor {
80
81         private final ArrayList JavaDoc fSideEffectNodes;
82
83         public SideEffectFinder(ArrayList JavaDoc 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 JavaDoc 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         /* (non-Javadoc)
130          * @see org.eclipse.jdt.internal.corext.fix.AbstractFix.IFixRewriteOperation#rewriteAST(org.eclipse.jdt.internal.corext.refactoring.structure.CompilationUnitRewrite, java.util.List)
131          */

132         public void rewriteAST(CompilationUnitRewrite cuRewrite, List JavaDoc 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         /* (non-Javadoc)
154          * @see org.eclipse.jdt.internal.corext.fix.AbstractFix.IFixRewriteOperation#rewriteAST(org.eclipse.jdt.internal.corext.refactoring.structure.CompilationUnitRewrite, java.util.List)
155          */

156         public void rewriteAST(CompilationUnitRewrite cuRewrite, List JavaDoc 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 JavaDoc groups) {
163             IBinding binding= simpleName.resolveBinding();
164             CompilationUnit root= (CompilationUnit) simpleName.getRoot();
165             String JavaDoc 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                 // unexpected
193
}
194         }
195         
196         private String JavaDoc 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 ""; //$NON-NLS-1$
214
}
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         /**
230          * Remove the field or variable declaration including the initializer.
231          * @param rewrite the AST rewriter to use
232          * @param reference a reference to the variable to remove
233          * @param group the text edit group to use
234          */

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 JavaDoc 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                     //multiple declarations in one line
292
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                         //keep constructors and method invocations
306
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             //keep constructors and method invocations
317
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 JavaDoc fragments= originalStatement.fragments();
325                 int fragIndex= fragments.indexOf(frag);
326                 ListIterator JavaDoc 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 JavaDoc sideEffectNodes= new ArrayList JavaDoc();
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 JavaDoc getAdditionalInfo() {
369             StringBuffer JavaDoc sb=new StringBuffer JavaDoc();
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         /**
394          * {@inheritDoc}
395          */

396         public void rewriteAST(CompilationUnitRewrite cuRewrite, List JavaDoc 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 JavaDoc fUnnecessaryCasts;
418
419         public RemoveAllCastOperation(HashSet JavaDoc unnecessaryCasts) {
420             fUnnecessaryCasts= unnecessaryCasts;
421         }
422
423         /**
424          * {@inheritDoc}
425          */

426         public void rewriteAST(CompilationUnitRewrite cuRewrite, List JavaDoc 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 JavaDoc label= FixMessages.UnusedCodeFix_RemoveImport_description;
462                 RemoveImportOperation operation= new RemoveImportOperation(node);
463                 Map JavaDoc options= new Hashtable JavaDoc();
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 JavaDoc 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 JavaDoc/*<IFixRewriteOperation>*/ result= new ArrayList JavaDoc();
544         Hashtable JavaDoc/*<ASTNode, List>*/ variableDeclarations= new Hashtable JavaDoc();
545         HashSet JavaDoc/*/CastExpression>*/ unnecessaryCasts= new HashSet JavaDoc();
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 JavaDoc());
581                             }
582                             ((List JavaDoc)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 JavaDoc iter= variableDeclarations.keySet().iterator(); iter.hasNext();) {
604             ASTNode node= (ASTNode)iter.next();
605             List JavaDoc names= (List JavaDoc)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 JavaDoc sideEffects= new ArrayList JavaDoc();
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 JavaDoc getDisplayString(SimpleName simpleName, IBinding binding, boolean forceRemoveInitializer) {
674         String JavaDoc 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 ""; //$NON-NLS-1$
692
}
693     }
694     
695     private static Map JavaDoc getCleanUpOptions(IBinding binding) {
696         Map JavaDoc result= new Hashtable JavaDoc();
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 JavaDoc fCleanUpOptions;
731     
732     private UnusedCodeFix(String JavaDoc name, CompilationUnit compilationUnit, IFixRewriteOperation[] fixRewriteOperations) {
733         this(name, compilationUnit, fixRewriteOperations, null);
734     }
735     
736     private UnusedCodeFix(String JavaDoc name, CompilationUnit compilationUnit, IFixRewriteOperation[] fixRewriteOperations, Map JavaDoc options) {
737         super(name, compilationUnit, fixRewriteOperations);
738         if (options == null) {
739             fCleanUpOptions= new Hashtable JavaDoc();
740         } else {
741             fCleanUpOptions= options;
742         }
743     }
744
745     public UnusedCodeCleanUp getCleanUp() {
746         return new UnusedCodeCleanUp(fCleanUpOptions);
747     }
748
749 }
750
Popular Tags