]> git.uio.no Git - ifi-stolz-refaktor.git/blobdiff - case-study/jdt-before/core extension/org/eclipse/jdt/internal/corext/fix/UnusedCodeFix.java
Case Study: adding data and statistics
[ifi-stolz-refaktor.git] / case-study / jdt-before / core extension / org / eclipse / jdt / internal / corext / fix / UnusedCodeFix.java
diff --git a/case-study/jdt-before/core extension/org/eclipse/jdt/internal/corext/fix/UnusedCodeFix.java b/case-study/jdt-before/core extension/org/eclipse/jdt/internal/corext/fix/UnusedCodeFix.java
new file mode 100644 (file)
index 0000000..aa0e678
--- /dev/null
@@ -0,0 +1,839 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2012 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.corext.fix;
+
+import java.util.ArrayList;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.CoreException;
+
+import org.eclipse.text.edits.TextEditGroup;
+
+import org.eclipse.jdt.core.compiler.IProblem;
+import org.eclipse.jdt.core.dom.ASTNode;
+import org.eclipse.jdt.core.dom.ASTVisitor;
+import org.eclipse.jdt.core.dom.Assignment;
+import org.eclipse.jdt.core.dom.Block;
+import org.eclipse.jdt.core.dom.CastExpression;
+import org.eclipse.jdt.core.dom.ClassInstanceCreation;
+import org.eclipse.jdt.core.dom.CompilationUnit;
+import org.eclipse.jdt.core.dom.EnhancedForStatement;
+import org.eclipse.jdt.core.dom.Expression;
+import org.eclipse.jdt.core.dom.ExpressionStatement;
+import org.eclipse.jdt.core.dom.FieldAccess;
+import org.eclipse.jdt.core.dom.FieldDeclaration;
+import org.eclipse.jdt.core.dom.IBinding;
+import org.eclipse.jdt.core.dom.IMethodBinding;
+import org.eclipse.jdt.core.dom.ITypeBinding;
+import org.eclipse.jdt.core.dom.IVariableBinding;
+import org.eclipse.jdt.core.dom.ImportDeclaration;
+import org.eclipse.jdt.core.dom.Javadoc;
+import org.eclipse.jdt.core.dom.MethodDeclaration;
+import org.eclipse.jdt.core.dom.MethodInvocation;
+import org.eclipse.jdt.core.dom.NodeFinder;
+import org.eclipse.jdt.core.dom.ParenthesizedExpression;
+import org.eclipse.jdt.core.dom.PostfixExpression;
+import org.eclipse.jdt.core.dom.PrefixExpression;
+import org.eclipse.jdt.core.dom.QualifiedName;
+import org.eclipse.jdt.core.dom.SimpleName;
+import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
+import org.eclipse.jdt.core.dom.SuperMethodInvocation;
+import org.eclipse.jdt.core.dom.SwitchStatement;
+import org.eclipse.jdt.core.dom.TagElement;
+import org.eclipse.jdt.core.dom.Type;
+import org.eclipse.jdt.core.dom.TypeDeclarationStatement;
+import org.eclipse.jdt.core.dom.VariableDeclarationExpression;
+import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
+import org.eclipse.jdt.core.dom.VariableDeclarationStatement;
+import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
+import org.eclipse.jdt.core.dom.rewrite.ListRewrite;
+
+import org.eclipse.jdt.internal.corext.dom.ASTNodes;
+import org.eclipse.jdt.internal.corext.dom.LinkedNodeFinder;
+import org.eclipse.jdt.internal.corext.dom.NecessaryParenthesesChecker;
+import org.eclipse.jdt.internal.corext.refactoring.structure.CompilationUnitRewrite;
+import org.eclipse.jdt.internal.corext.util.Messages;
+
+import org.eclipse.jdt.ui.cleanup.CleanUpOptions;
+import org.eclipse.jdt.ui.cleanup.ICleanUpFix;
+import org.eclipse.jdt.ui.text.java.IProblemLocation;
+
+import org.eclipse.jdt.internal.ui.fix.UnusedCodeCleanUp;
+import org.eclipse.jdt.internal.ui.text.correction.JavadocTagsSubProcessor;
+import org.eclipse.jdt.internal.ui.text.correction.ProblemLocation;
+import org.eclipse.jdt.internal.ui.viewsupport.BasicElementLabels;
+
+/**
+ * Fix which removes unused code.
+ */
+public class UnusedCodeFix extends CompilationUnitRewriteOperationsFix {
+
+       private static class SideEffectFinder extends ASTVisitor {
+
+               private final ArrayList<Expression> fSideEffectNodes;
+
+               public SideEffectFinder(ArrayList<Expression> res) {
+                       fSideEffectNodes= res;
+               }
+
+               @Override
+               public boolean visit(Assignment node) {
+                       fSideEffectNodes.add(node);
+                       return false;
+               }
+
+               @Override
+               public boolean visit(PostfixExpression node) {
+                       fSideEffectNodes.add(node);
+                       return false;
+               }
+
+               @Override
+               public boolean visit(PrefixExpression node) {
+                       Object operator= node.getOperator();
+                       if (operator == PrefixExpression.Operator.INCREMENT || operator == PrefixExpression.Operator.DECREMENT) {
+                               fSideEffectNodes.add(node);
+                       }
+                       return false;
+               }
+
+               @Override
+               public boolean visit(MethodInvocation node) {
+                       fSideEffectNodes.add(node);
+                       return false;
+               }
+
+               @Override
+               public boolean visit(ClassInstanceCreation node) {
+                       fSideEffectNodes.add(node);
+                       return false;
+               }
+
+               @Override
+               public boolean visit(SuperMethodInvocation node) {
+                       fSideEffectNodes.add(node);
+                       return false;
+               }
+       }
+
+       private static class RemoveImportOperation extends CompilationUnitRewriteOperation {
+
+               private final ImportDeclaration fImportDeclaration;
+
+               public RemoveImportOperation(ImportDeclaration importDeclaration) {
+                       fImportDeclaration= importDeclaration;
+               }
+
+               /**
+                * {@inheritDoc}
+                */
+               @Override
+               public void rewriteAST(CompilationUnitRewrite cuRewrite, LinkedProposalModel model) throws CoreException {
+                       ImportDeclaration node= fImportDeclaration;
+                       TextEditGroup group= createTextEditGroup(FixMessages.UnusedCodeFix_RemoveImport_description, cuRewrite);
+                       cuRewrite.getASTRewrite().remove(node, group);
+               }
+
+       }
+
+       private static class RemoveUnusedMemberOperation extends CompilationUnitRewriteOperation {
+
+               private final SimpleName[] fUnusedNames;
+               private boolean fForceRemove;
+               private int fRemovedAssignmentsCount;
+               private int fAlteredAssignmentsCount;
+
+               public RemoveUnusedMemberOperation(SimpleName[] unusedNames, boolean removeAllAsignements) {
+                       fUnusedNames= unusedNames;
+                       fForceRemove= removeAllAsignements;
+               }
+
+               /**
+                * {@inheritDoc}
+                */
+               @Override
+               public void rewriteAST(CompilationUnitRewrite cuRewrite, LinkedProposalModel model) throws CoreException {
+                       for (int i= 0; i < fUnusedNames.length; i++) {
+                               removeUnusedName(cuRewrite, fUnusedNames[i]);
+                       }
+               }
+
+               private void removeUnusedName(CompilationUnitRewrite cuRewrite, SimpleName simpleName) {
+                       ASTRewrite rewrite= cuRewrite.getASTRewrite();
+                       CompilationUnit completeRoot= cuRewrite.getRoot();
+
+                       IBinding binding= simpleName.resolveBinding();
+                       CompilationUnit root= (CompilationUnit) simpleName.getRoot();
+                       String displayString= getDisplayString(binding);
+                       TextEditGroup group= createTextEditGroup(displayString, cuRewrite);
+                       if (binding.getKind() == IBinding.METHOD) {
+                               IMethodBinding decl= ((IMethodBinding) binding).getMethodDeclaration();
+                               ASTNode declaration= root.findDeclaringNode(decl);
+                               rewrite.remove(declaration, group);
+                       } else if (binding.getKind() == IBinding.TYPE) {
+                               ITypeBinding decl= ((ITypeBinding) binding).getTypeDeclaration();
+                               ASTNode declaration= root.findDeclaringNode(decl);
+                               if (declaration.getParent() instanceof TypeDeclarationStatement) {
+                                       declaration= declaration.getParent();
+                               }
+                               rewrite.remove(declaration, group);
+                       } else if (binding.getKind() == IBinding.VARIABLE) {
+                               SimpleName nameNode= (SimpleName) NodeFinder.perform(completeRoot, simpleName.getStartPosition(), simpleName.getLength());
+                               SimpleName[] references= LinkedNodeFinder.findByBinding(completeRoot, nameNode.resolveBinding());
+                               for (int i= 0; i < references.length; i++) {
+                                       removeVariableReferences(rewrite, references[i], group);
+                               }
+
+                               IVariableBinding bindingDecl= ((IVariableBinding) nameNode.resolveBinding()).getVariableDeclaration();
+                               ASTNode declaringNode= completeRoot.findDeclaringNode(bindingDecl);
+                               if (declaringNode instanceof SingleVariableDeclaration) {
+                                       removeParamTag(rewrite, (SingleVariableDeclaration) declaringNode, group);
+                               }
+                       } else {
+                               // unexpected
+                       }
+               }
+
+               private String getDisplayString(IBinding binding) {
+                       switch (binding.getKind()) {
+                               case IBinding.TYPE:
+                                       return FixMessages.UnusedCodeFix_RemoveUnusedType_description;
+                               case IBinding.METHOD:
+                                       if (((IMethodBinding) binding).isConstructor()) {
+                                               return FixMessages.UnusedCodeFix_RemoveUnusedConstructor_description;
+                                       } else {
+                                               return FixMessages.UnusedCodeFix_RemoveUnusedPrivateMethod_description;
+                                       }
+                               case IBinding.VARIABLE:
+                                       if (((IVariableBinding) binding).isField()) {
+                                               return FixMessages.UnusedCodeFix_RemoveUnusedField_description;
+                                       } else {
+                                               return FixMessages.UnusedCodeFix_RemoveUnusedVariabl_description;
+                                       }
+                               default:
+                                       return ""; //$NON-NLS-1$
+                       }
+               }
+
+               private void removeParamTag(ASTRewrite rewrite, SingleVariableDeclaration varDecl, TextEditGroup group) {
+                       if (varDecl.getParent() instanceof MethodDeclaration) {
+                               Javadoc javadoc= ((MethodDeclaration) varDecl.getParent()).getJavadoc();
+                               if (javadoc != null) {
+                                       TagElement tagElement= JavadocTagsSubProcessor.findParamTag(javadoc, varDecl.getName().getIdentifier());
+                                       if (tagElement != null) {
+                                               rewrite.remove(tagElement, group);
+                                       }
+                               }
+                       }
+               }
+
+               /**
+                * Remove the field or variable declaration including the initializer.
+                * @param rewrite the AST rewriter to use
+                * @param reference a reference to the variable to remove
+                * @param group the text edit group to use
+                */
+               private void removeVariableReferences(ASTRewrite rewrite, SimpleName reference, TextEditGroup group) {
+                       ASTNode parent= reference.getParent();
+                       while (parent instanceof QualifiedName) {
+                               parent= parent.getParent();
+                       }
+                       if (parent instanceof FieldAccess) {
+                               parent= parent.getParent();
+                       }
+
+                       int nameParentType= parent.getNodeType();
+                       if (nameParentType == ASTNode.ASSIGNMENT) {
+                               Assignment assignment= (Assignment) parent;
+                               Expression rightHand= assignment.getRightHandSide();
+
+                               ASTNode assignParent= assignment.getParent();
+                               if (assignParent.getNodeType() == ASTNode.EXPRESSION_STATEMENT && rightHand.getNodeType() != ASTNode.ASSIGNMENT) {
+                                       removeVariableWithInitializer(rewrite, rightHand, assignParent, group);
+                               }       else {
+                                       rewrite.replace(assignment, rewrite.createCopyTarget(rightHand), group);
+                               }
+                       } else if (nameParentType == ASTNode.SINGLE_VARIABLE_DECLARATION) {
+                               rewrite.remove(parent, group);
+                       } else if (nameParentType == ASTNode.VARIABLE_DECLARATION_FRAGMENT) {
+                               VariableDeclarationFragment frag= (VariableDeclarationFragment) parent;
+                               ASTNode varDecl= frag.getParent();
+                               List<VariableDeclarationFragment> fragments;
+                               if (varDecl instanceof VariableDeclarationExpression) {
+                                       fragments= ((VariableDeclarationExpression) varDecl).fragments();
+                               } else if (varDecl instanceof FieldDeclaration) {
+                                       fragments= ((FieldDeclaration) varDecl).fragments();
+                               } else {
+                                       fragments= ((VariableDeclarationStatement) varDecl).fragments();
+                               }
+                               Expression initializer = frag.getInitializer();
+                               if (initializer instanceof CastExpression) {
+                                       initializer= ((CastExpression) initializer).getExpression();
+                               }
+                               boolean sideEffectInitializer = initializer instanceof MethodInvocation || initializer instanceof ClassInstanceCreation;
+                               if (fragments.size() == fUnusedNames.length) {
+                                       if (fForceRemove) {
+                                               rewrite.remove(varDecl, group);
+                                               return;
+                                       }
+                                       if (parent.getParent() instanceof FieldDeclaration) {
+                                               rewrite.remove(varDecl, group);
+                                               return;
+                                       }
+                                       if (sideEffectInitializer){
+                                               Expression movedInit = (Expression) rewrite.createMoveTarget(initializer);
+                                               ExpressionStatement wrapped = rewrite.getAST().newExpressionStatement(movedInit);
+                                               rewrite.replace(varDecl, wrapped, group);
+                                       } else {
+                                               rewrite.remove(varDecl, group);
+                                       }
+                               } else {
+                                       if (fForceRemove) {
+                                               rewrite.remove(frag, group);
+                                               return;
+                                       }
+                                       //multiple declarations in one line
+                                       ASTNode declaration = parent.getParent();
+                                       if (declaration instanceof FieldDeclaration) {
+                                               rewrite.remove(frag, group);
+                                               return;
+                                       }
+                                       if (declaration instanceof VariableDeclarationStatement) {
+                                               ASTNode lst = declaration.getParent();
+                                               ListRewrite listRewrite= null;
+                                               if (lst instanceof Block) {
+                                                       listRewrite= rewrite.getListRewrite(lst, Block.STATEMENTS_PROPERTY);
+                                               } else if (lst instanceof SwitchStatement) {
+                                                       listRewrite= rewrite.getListRewrite(lst, SwitchStatement.STATEMENTS_PROPERTY);
+                                               } else {
+                                                       Assert.isTrue(false);
+                                               }
+                                               splitUpDeclarations(rewrite, group, frag, listRewrite, (VariableDeclarationStatement) declaration);
+                                               rewrite.remove(frag, group);
+                                               return;
+                                       }
+                                       if (declaration instanceof VariableDeclarationExpression) {
+                                               //keep constructors and method invocations
+                                               if (!sideEffectInitializer){
+                                                       rewrite.remove(frag, group);
+                                               }
+                                       }
+                               }
+                       } else if (nameParentType == ASTNode.POSTFIX_EXPRESSION || nameParentType == ASTNode.PREFIX_EXPRESSION) {
+                               Expression expression= (Expression)parent;
+                               ASTNode expressionParent= expression.getParent();
+                               if (expressionParent.getNodeType() == ASTNode.EXPRESSION_STATEMENT) {
+                                       removeStatement(rewrite, expressionParent, group);
+                               } else {
+                                       rewrite.remove(expression, group);
+                               }
+                       }
+               }
+
+               private void splitUpDeclarations(ASTRewrite rewrite, TextEditGroup group, VariableDeclarationFragment frag, ListRewrite statementRewrite, VariableDeclarationStatement originalStatement) {
+                       Expression initializer = frag.getInitializer();
+                       //keep constructors and method invocations
+                       if (initializer instanceof MethodInvocation || initializer instanceof ClassInstanceCreation){
+                               Expression movedInitializer= (Expression) rewrite.createMoveTarget(initializer);
+
+                               ExpressionStatement newInitializer= rewrite.getAST().newExpressionStatement( movedInitializer);
+                               statementRewrite.insertAfter(newInitializer, originalStatement, group);
+
+                               VariableDeclarationStatement newDeclaration= null;
+                               List<VariableDeclarationFragment> fragments= originalStatement.fragments();
+                               int fragIndex= fragments.indexOf(frag);
+                               ListIterator<VariableDeclarationFragment> fragmentIterator= fragments.listIterator(fragIndex+1);
+                               while (fragmentIterator.hasNext()) {
+                                       VariableDeclarationFragment currentFragment= fragmentIterator.next();
+                                       VariableDeclarationFragment movedFragment= (VariableDeclarationFragment) rewrite.createMoveTarget(currentFragment);
+                                       if (newDeclaration == null) {
+                                               newDeclaration= rewrite.getAST().newVariableDeclarationStatement(movedFragment);
+                                               Type copiedType= (Type) rewrite.createCopyTarget(originalStatement.getType());
+                                               newDeclaration.setType(copiedType);
+                                       } else
+                                               newDeclaration.fragments().add(movedFragment);
+                               }
+                               if (newDeclaration != null){
+                                       statementRewrite.insertAfter(newDeclaration, newInitializer, group);
+                               }
+                               if (originalStatement.fragments().size() == newDeclaration.fragments().size() + 1){
+                                       rewrite.remove(originalStatement, group);
+                               }
+                       }
+               }
+
+               private void removeVariableWithInitializer(ASTRewrite rewrite, ASTNode initializerNode, ASTNode statementNode, TextEditGroup group) {
+                       boolean performRemove= fForceRemove;
+                       if (!performRemove) {
+                               ArrayList<Expression> sideEffectNodes= new ArrayList<Expression>();
+                               initializerNode.accept(new SideEffectFinder(sideEffectNodes));
+                               performRemove= sideEffectNodes.isEmpty();
+                       }
+                       if (performRemove) {
+                               removeStatement(rewrite, statementNode, group);
+                               fRemovedAssignmentsCount++;
+                       } else {
+                               ASTNode initNode = rewrite.createMoveTarget(initializerNode);
+                               ExpressionStatement statement = rewrite.getAST().newExpressionStatement((Expression) initNode);
+                               rewrite.replace(statementNode, statement, null);
+                               fAlteredAssignmentsCount++;
+                       }
+               }
+
+               private void removeStatement(ASTRewrite rewrite, ASTNode statementNode, TextEditGroup group) {
+                       if (ASTNodes.isControlStatementBody(statementNode.getLocationInParent())) {
+                               rewrite.replace(statementNode, rewrite.getAST().newBlock(), group);
+                       } else {
+                               rewrite.remove(statementNode, group);
+                       }
+               }
+
+               @Override
+               public String getAdditionalInfo() {
+                       StringBuffer sb=new StringBuffer();
+                       if (fRemovedAssignmentsCount == 1) {
+                               sb.append(FixMessages.UnusedCodeFix_RemoveFieldOrLocal_RemovedAssignments_preview_singular);
+                       } else if (fRemovedAssignmentsCount > 1) {
+                               sb.append(Messages.format(FixMessages.UnusedCodeFix_RemoveFieldOrLocal_RemovedAssignments_preview_plural, String.valueOf(fRemovedAssignmentsCount)));
+                       }
+                       if (fAlteredAssignmentsCount == 1) {
+                               sb.append(FixMessages.UnusedCodeFix_RemoveFieldOrLocal_AlteredAssignments_preview_singular);
+                       } else if (fAlteredAssignmentsCount > 1) {
+                               sb.append(Messages.format(FixMessages.UnusedCodeFix_RemoveFieldOrLocal_AlteredAssignments_preview_plural, String.valueOf(fAlteredAssignmentsCount)));
+                       }
+                       if (sb.length()>0) {
+                               return sb.toString();
+                       } else
+                               return null;
+               }
+       }
+
+       private static class RemoveCastOperation extends CompilationUnitRewriteOperation {
+
+               private final CastExpression fCast;
+
+               public RemoveCastOperation(CastExpression cast) {
+                       fCast= cast;
+               }
+
+               /**
+                * {@inheritDoc}
+                */
+               @Override
+               public void rewriteAST(CompilationUnitRewrite cuRewrite, LinkedProposalModel model) throws CoreException {
+
+                       TextEditGroup group= createTextEditGroup(FixMessages.UnusedCodeFix_RemoveCast_description, cuRewrite);
+
+                       ASTRewrite rewrite= cuRewrite.getASTRewrite();
+
+                       CastExpression cast= fCast;
+                       Expression expression= cast.getExpression();
+                       if (expression instanceof ParenthesizedExpression) {
+                               Expression childExpression= ((ParenthesizedExpression) expression).getExpression();
+                               if (NecessaryParenthesesChecker.needsParentheses(childExpression, cast, CastExpression.EXPRESSION_PROPERTY)) {
+                                       expression= childExpression;
+                               }
+                       }
+                       
+                       replaceCast(cast, expression, rewrite, group);
+               }
+       }
+
+       private static class RemoveAllCastOperation extends CompilationUnitRewriteOperation {
+
+               private final LinkedHashSet<CastExpression> fUnnecessaryCasts;
+
+               public RemoveAllCastOperation(LinkedHashSet<CastExpression> unnecessaryCasts) {
+                       fUnnecessaryCasts= unnecessaryCasts;
+               }
+
+               /**
+                * {@inheritDoc}
+                */
+               @Override
+               public void rewriteAST(CompilationUnitRewrite cuRewrite, LinkedProposalModel model) throws CoreException {
+                       ASTRewrite rewrite= cuRewrite.getASTRewrite();
+
+                       TextEditGroup group= createTextEditGroup(FixMessages.UnusedCodeFix_RemoveCast_description, cuRewrite);
+
+                       while (fUnnecessaryCasts.size() > 0) {
+                               CastExpression castExpression= fUnnecessaryCasts.iterator().next();
+                               fUnnecessaryCasts.remove(castExpression);
+                               
+                               /*
+                                * ASTRewrite doesn't allow replacing (deleting) of moved nodes. To solve problems
+                                * with nested casts, we need to replace all casts at once.
+                                * 
+                                * The loop proceeds downwards to find the innermost expression that stays in the result (downChild)
+                                * and it also skips necessary parentheses.
+                                */
+                               CastExpression down= castExpression;
+                               Expression downChild= down.getExpression();
+                               while (true) {
+                                       if (fUnnecessaryCasts.contains(downChild)) {
+                                               down= (CastExpression) downChild;
+                                               fUnnecessaryCasts.remove(down);
+                                               downChild= down.getExpression();
+                                       } else if (downChild instanceof ParenthesizedExpression) {
+                                               Expression downChildExpression= ((ParenthesizedExpression) downChild).getExpression();
+                                               // is it justified that downChild is a ParenthesizedExpression?
+                                               if (NecessaryParenthesesChecker.needsParentheses(downChildExpression, down, CastExpression.EXPRESSION_PROPERTY)) {
+                                                       // yes => continue walking down
+                                                       downChild= downChildExpression;
+                                               } else {
+                                                       // no => stop walking
+                                                       break;
+                                               }
+                                       } else {
+                                               break;
+                                       }
+                               }
+                               
+                               // downChild is the innermost CastExpression's expression, stripped of a necessary surrounding ParenthesizedExpression
+                               // Move either downChild (if it doesn't need parentheses), or a parenthesized version if necessary
+                               
+                               replaceCast(castExpression, downChild, rewrite, group);
+                       }
+               }
+       }
+
+       public static UnusedCodeFix createRemoveUnusedImportFix(CompilationUnit compilationUnit, IProblemLocation problem) {
+               if (isUnusedImport(problem)) {
+                       ImportDeclaration node= getImportDeclaration(problem, compilationUnit);
+                       if (node != null) {
+                               String label= FixMessages.UnusedCodeFix_RemoveImport_description;
+                               RemoveImportOperation operation= new RemoveImportOperation(node);
+                               Map<String, String> options= new Hashtable<String, String>();
+                               options.put(CleanUpConstants.REMOVE_UNUSED_CODE_IMPORTS, CleanUpOptions.TRUE);
+                               return new UnusedCodeFix(label, compilationUnit, new CompilationUnitRewriteOperation[] {operation}, options);
+                       }
+               }
+               return null;
+       }
+
+       public static boolean isUnusedImport(IProblemLocation problem) {
+               int id= problem.getProblemId();
+               return id == IProblem.UnusedImport || id == IProblem.DuplicateImport || id == IProblem.ConflictingImport || id == IProblem.CannotImportPackage || id == IProblem.ImportNotFound;
+       }
+
+       public static UnusedCodeFix createUnusedMemberFix(CompilationUnit compilationUnit, IProblemLocation problem, boolean removeAllAssignements) {
+               if (isUnusedMember(problem)) {
+                       SimpleName name= getUnusedName(compilationUnit, problem);
+                       if (name != null) {
+                               IBinding binding= name.resolveBinding();
+                               if (binding != null) {
+                                       if (isFormalParameterInEnhancedForStatement(name))
+                                               return null;
+
+                                       String label= getDisplayString(name, binding, removeAllAssignements);
+                                       RemoveUnusedMemberOperation operation= new RemoveUnusedMemberOperation(new SimpleName[] { name }, removeAllAssignements);
+                                       return new UnusedCodeFix(label, compilationUnit, new CompilationUnitRewriteOperation[] { operation }, getCleanUpOptions(binding, removeAllAssignements));
+                               }
+                       }
+               }
+               return null;
+       }
+
+       public static boolean isUnusedMember(IProblemLocation problem) {
+               int id= problem.getProblemId();
+               return id == IProblem.UnusedPrivateMethod || id == IProblem.UnusedPrivateConstructor || id == IProblem.UnusedPrivateField || id == IProblem.UnusedPrivateType
+                               || id == IProblem.LocalVariableIsNeverUsed || id == IProblem.ArgumentIsNeverUsed;
+       }
+
+       public static UnusedCodeFix createRemoveUnusedCastFix(CompilationUnit compilationUnit, IProblemLocation problem) {
+               if (problem.getProblemId() != IProblem.UnnecessaryCast)
+                       return null;
+
+               ASTNode selectedNode= problem.getCoveringNode(compilationUnit);
+
+               ASTNode curr= selectedNode;
+               while (curr instanceof ParenthesizedExpression) {
+                       curr= ((ParenthesizedExpression) curr).getExpression();
+               }
+
+               if (!(curr instanceof CastExpression))
+                       return null;
+
+               return new UnusedCodeFix(FixMessages.UnusedCodeFix_RemoveCast_description, compilationUnit, new CompilationUnitRewriteOperation[] {new RemoveCastOperation((CastExpression)curr)});
+       }
+
+       public static ICleanUpFix createCleanUp(CompilationUnit compilationUnit,
+                       boolean removeUnusedPrivateMethods,
+                       boolean removeUnusedPrivateConstructors,
+                       boolean removeUnusedPrivateFields,
+                       boolean removeUnusedPrivateTypes,
+                       boolean removeUnusedLocalVariables,
+                       boolean removeUnusedImports,
+                       boolean removeUnusedCast) {
+
+               IProblem[] problems= compilationUnit.getProblems();
+               IProblemLocation[] locations= new IProblemLocation[problems.length];
+               for (int i= 0; i < problems.length; i++) {
+                       locations[i]= new ProblemLocation(problems[i]);
+               }
+
+               return createCleanUp(compilationUnit, locations,
+                               removeUnusedPrivateMethods,
+                               removeUnusedPrivateConstructors,
+                               removeUnusedPrivateFields,
+                               removeUnusedPrivateTypes,
+                               removeUnusedLocalVariables,
+                               removeUnusedImports,
+                               removeUnusedCast);
+       }
+
+       public static ICleanUpFix createCleanUp(CompilationUnit compilationUnit, IProblemLocation[] problems,
+                       boolean removeUnusedPrivateMethods,
+                       boolean removeUnusedPrivateConstructors,
+                       boolean removeUnusedPrivateFields,
+                       boolean removeUnusedPrivateTypes,
+                       boolean removeUnusedLocalVariables,
+                       boolean removeUnusedImports,
+                       boolean removeUnusedCast) {
+
+               List<CompilationUnitRewriteOperation> result= new ArrayList<CompilationUnitRewriteOperation>();
+               Hashtable<ASTNode, List<SimpleName>> variableDeclarations= new Hashtable<ASTNode, List<SimpleName>>();
+               LinkedHashSet<CastExpression> unnecessaryCasts= new LinkedHashSet<CastExpression>();
+               for (int i= 0; i < problems.length; i++) {
+                       IProblemLocation problem= problems[i];
+                       int id= problem.getProblemId();
+
+                       if (removeUnusedImports && (id == IProblem.UnusedImport || id == IProblem.DuplicateImport || id == IProblem.ConflictingImport ||
+                                   id == IProblem.CannotImportPackage || id == IProblem.ImportNotFound))
+                       {
+                               ImportDeclaration node= UnusedCodeFix.getImportDeclaration(problem, compilationUnit);
+                               if (node != null) {
+                                       result.add(new RemoveImportOperation(node));
+                               }
+                       }
+
+                       if ((removeUnusedPrivateMethods && id == IProblem.UnusedPrivateMethod) || (removeUnusedPrivateConstructors && id == IProblem.UnusedPrivateConstructor) ||
+                           (removeUnusedPrivateTypes && id == IProblem.UnusedPrivateType)) {
+
+                               SimpleName name= getUnusedName(compilationUnit, problem);
+                               if (name != null) {
+                                       IBinding binding= name.resolveBinding();
+                                       if (binding != null) {
+                                               result.add(new RemoveUnusedMemberOperation(new SimpleName[] {name}, false));
+                                       }
+                               }
+                       }
+
+                       if ((removeUnusedLocalVariables && id == IProblem.LocalVariableIsNeverUsed) ||  (removeUnusedPrivateFields && id == IProblem.UnusedPrivateField)) {
+                               SimpleName name= getUnusedName(compilationUnit, problem);
+                               if (name != null) {
+                                       IBinding binding= name.resolveBinding();
+                                       if (binding instanceof IVariableBinding && !isFormalParameterInEnhancedForStatement(name) && (!((IVariableBinding) binding).isField() || isSideEffectFree(name, compilationUnit))) {
+                                               VariableDeclarationFragment parent= (VariableDeclarationFragment) ASTNodes.getParent(name, VariableDeclarationFragment.class);
+                                               if (parent != null) {
+                                                       ASTNode varDecl= parent.getParent();
+                                                       if (!variableDeclarations.containsKey(varDecl)) {
+                                                               variableDeclarations.put(varDecl, new ArrayList<SimpleName>());
+                                                       }
+                                                       variableDeclarations.get(varDecl).add(name);
+                                               } else {
+                                                       result.add(new RemoveUnusedMemberOperation(new SimpleName[] {name}, false));
+                                               }
+                                       }
+                               }
+                       }
+
+                       if (removeUnusedCast && id == IProblem.UnnecessaryCast) {
+                               ASTNode selectedNode= problem.getCoveringNode(compilationUnit);
+
+                               ASTNode curr= selectedNode;
+                               while (curr instanceof ParenthesizedExpression) {
+                                       curr= ((ParenthesizedExpression) curr).getExpression();
+                               }
+
+                               if (curr instanceof CastExpression) {
+                                       unnecessaryCasts.add((CastExpression) curr);
+                               }
+                       }
+               }
+               for (Iterator<ASTNode> iter= variableDeclarations.keySet().iterator(); iter.hasNext();) {
+                       ASTNode node= iter.next();
+                       List<SimpleName> names= variableDeclarations.get(node);
+                       result.add(new RemoveUnusedMemberOperation(names.toArray(new SimpleName[names.size()]), false));
+               }
+               if (unnecessaryCasts.size() > 0)
+                       result.add(new RemoveAllCastOperation(unnecessaryCasts));
+
+               if (result.size() == 0)
+                       return null;
+
+               return new UnusedCodeFix(FixMessages.UnusedCodeFix_change_name, compilationUnit, result.toArray(new CompilationUnitRewriteOperation[result.size()]));
+       }
+
+       private static boolean isFormalParameterInEnhancedForStatement(SimpleName name) {
+               return name.getParent() instanceof SingleVariableDeclaration && name.getParent().getLocationInParent() == EnhancedForStatement.PARAMETER_PROPERTY;
+       }
+
+       private static boolean isSideEffectFree(SimpleName simpleName, CompilationUnit completeRoot) {
+               SimpleName nameNode= (SimpleName) NodeFinder.perform(completeRoot, simpleName.getStartPosition(), simpleName.getLength());
+               SimpleName[] references= LinkedNodeFinder.findByBinding(completeRoot, nameNode.resolveBinding());
+               for (int i= 0; i < references.length; i++) {
+                       if (hasSideEffect(references[i]))
+                               return false;
+               }
+               return true;
+       }
+
+       private static boolean hasSideEffect(SimpleName reference) {
+               ASTNode parent= reference.getParent();
+               while (parent instanceof QualifiedName) {
+                       parent= parent.getParent();
+               }
+               if (parent instanceof FieldAccess) {
+                       parent= parent.getParent();
+               }
+
+               ASTNode node= null;
+               int nameParentType= parent.getNodeType();
+               if (nameParentType == ASTNode.ASSIGNMENT) {
+                       Assignment assignment= (Assignment) parent;
+                       node= assignment.getRightHandSide();
+               } else if (nameParentType == ASTNode.SINGLE_VARIABLE_DECLARATION) {
+                       SingleVariableDeclaration decl= (SingleVariableDeclaration)parent;
+                       node= decl.getInitializer();
+                       if (node == null)
+                               return false;
+               } else if (nameParentType == ASTNode.VARIABLE_DECLARATION_FRAGMENT) {
+                       node= parent;
+               } else {
+                       return false;
+               }
+
+               ArrayList<Expression> sideEffects= new ArrayList<Expression>();
+               node.accept(new SideEffectFinder(sideEffects));
+               return sideEffects.size() > 0;
+       }
+
+       private static SimpleName getUnusedName(CompilationUnit compilationUnit, IProblemLocation problem) {
+               ASTNode selectedNode= problem.getCoveringNode(compilationUnit);
+
+               if (selectedNode instanceof MethodDeclaration) {
+                       return ((MethodDeclaration) selectedNode).getName();
+               } else if (selectedNode instanceof SimpleName) {
+                       return (SimpleName) selectedNode;
+               }
+
+               return null;
+       }
+
+       private static String getDisplayString(SimpleName simpleName, IBinding binding, boolean removeAllAssignements) {
+               String name= BasicElementLabels.getJavaElementName(simpleName.getIdentifier());
+               switch (binding.getKind()) {
+                       case IBinding.TYPE:
+                               return Messages.format(FixMessages.UnusedCodeFix_RemoveType_description, name);
+                       case IBinding.METHOD:
+                               if (((IMethodBinding) binding).isConstructor()) {
+                                       return Messages.format(FixMessages.UnusedCodeFix_RemoveConstructor_description, name);
+                               } else {
+                                       return Messages.format(FixMessages.UnusedCodeFix_RemoveMethod_description, name);
+                               }
+                       case IBinding.VARIABLE:
+                               if (removeAllAssignements) {
+                                       return Messages.format(FixMessages.UnusedCodeFix_RemoveFieldOrLocalWithInitializer_description, name);
+                               } else {
+                                       return Messages.format(FixMessages.UnusedCodeFix_RemoveFieldOrLocal_description, name);
+                               }
+                       default:
+                               return ""; //$NON-NLS-1$
+               }
+       }
+
+       private static Map<String, String> getCleanUpOptions(IBinding binding, boolean removeAll) {
+               Map<String, String> result= new Hashtable<String, String>();
+
+               result.put(CleanUpConstants.REMOVE_UNUSED_CODE_PRIVATE_MEMBERS, CleanUpOptions.TRUE);
+               switch (binding.getKind()) {
+                       case IBinding.TYPE:
+                               result.put(CleanUpConstants.REMOVE_UNUSED_CODE_PRIVATE_TYPES, CleanUpOptions.TRUE);
+                               break;
+                       case IBinding.METHOD:
+                               if (((IMethodBinding) binding).isConstructor()) {
+                                       result.put(CleanUpConstants.REMOVE_UNUSED_CODE_PRIVATE_CONSTRUCTORS, CleanUpOptions.TRUE);
+                               } else {
+                                       result.put(CleanUpConstants.REMOVE_UNUSED_CODE_PRIVATE_METHODS, CleanUpOptions.TRUE);
+                               }
+                               break;
+                       case IBinding.VARIABLE:
+                               if (removeAll)
+                                       return null;
+
+                               result.put(CleanUpConstants.REMOVE_UNUSED_CODE_PRIVATE_FELDS, CleanUpOptions.TRUE);
+                               result.put(CleanUpConstants.REMOVE_UNUSED_CODE_LOCAL_VARIABLES, CleanUpOptions.TRUE);
+                               break;
+               }
+
+               return result;
+       }
+
+       private static ImportDeclaration getImportDeclaration(IProblemLocation problem, CompilationUnit compilationUnit) {
+               ASTNode selectedNode= problem.getCoveringNode(compilationUnit);
+               if (selectedNode != null) {
+                       ASTNode node= ASTNodes.getParent(selectedNode, ASTNode.IMPORT_DECLARATION);
+                       if (node instanceof ImportDeclaration) {
+                               return (ImportDeclaration)node;
+                       }
+               }
+               return null;
+       }
+
+       private static void replaceCast(CastExpression castExpression, Expression replacement, ASTRewrite rewrite, TextEditGroup group) {
+               boolean castEnclosedInNecessaryParentheses= castExpression.getParent() instanceof ParenthesizedExpression
+                               && NecessaryParenthesesChecker.needsParentheses(castExpression, castExpression.getParent().getParent(), castExpression.getParent().getLocationInParent());
+               
+               ASTNode toReplace= castEnclosedInNecessaryParentheses ? castExpression.getParent() : castExpression;
+               ASTNode move;
+               if (NecessaryParenthesesChecker.needsParentheses(replacement, toReplace.getParent(), toReplace.getLocationInParent())) {
+                       if (replacement.getParent() instanceof ParenthesizedExpression) {
+                               move= rewrite.createMoveTarget(replacement.getParent());
+                       } else if (castEnclosedInNecessaryParentheses) {
+                               toReplace= castExpression;
+                               move= rewrite.createMoveTarget(replacement);
+                       } else {
+                               ParenthesizedExpression parentheses= replacement.getAST().newParenthesizedExpression();
+                               parentheses.setExpression((Expression) rewrite.createMoveTarget(replacement));
+                               move= parentheses;
+                       }
+               } else {
+                       move= rewrite.createMoveTarget(replacement);
+               }
+               rewrite.replace(toReplace, move, group);
+       }
+
+       private final Map<String, String> fCleanUpOptions;
+
+       private UnusedCodeFix(String name, CompilationUnit compilationUnit, CompilationUnitRewriteOperation[] fixRewriteOperations) {
+               this(name, compilationUnit, fixRewriteOperations, null);
+       }
+
+       private UnusedCodeFix(String name, CompilationUnit compilationUnit, CompilationUnitRewriteOperation[] fixRewriteOperations, Map<String, String> options) {
+               super(name, compilationUnit, fixRewriteOperations);
+               fCleanUpOptions= options;
+       }
+
+       public UnusedCodeCleanUp getCleanUp() {
+               if (fCleanUpOptions == null)
+                       return null;
+
+               return new UnusedCodeCleanUp(fCleanUpOptions);
+       }
+
+}