blob: 5f745c8ae58098539e2672aef49f765392218d7f [file] [log] [blame]
/*******************************************************************************
* 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.ui.text.correction.proposals;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.ui.ISharedImages;
import org.eclipse.jdt.core.ICompilationUnit;
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.ClassInstanceCreation;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.Expression;
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.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.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.TagElement;
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.internal.corext.dom.ASTNodes;
import org.eclipse.jdt.internal.corext.dom.LinkedNodeFinder;
import org.eclipse.jdt.internal.corext.util.Messages;
import org.eclipse.jdt.ui.SharedASTProvider;
import org.eclipse.jdt.ui.text.java.correction.ASTRewriteCorrectionProposal;
import org.eclipse.jdt.internal.ui.JavaPlugin;
import org.eclipse.jdt.internal.ui.text.correction.CorrectionMessages;
import org.eclipse.jdt.internal.ui.text.correction.JavadocTagsSubProcessor;
import org.eclipse.jdt.internal.ui.viewsupport.BasicElementLabels;
public class RemoveDeclarationCorrectionProposal extends ASTRewriteCorrectionProposal {
private static class SideEffectFinder extends ASTVisitor {
private 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 SimpleName fName;
public RemoveDeclarationCorrectionProposal(ICompilationUnit cu, SimpleName name, int relevance) {
super("", cu, null, relevance, JavaPlugin.getDefault().getWorkbench().getSharedImages().getImage(ISharedImages.IMG_TOOL_DELETE)); //$NON-NLS-1$
fName= name;
}
@Override
public String getName() {
IBinding binding= fName.resolveBinding();
String name= BasicElementLabels.getJavaElementName(fName.getIdentifier());
switch (binding.getKind()) {
case IBinding.TYPE:
return Messages.format(CorrectionMessages.RemoveDeclarationCorrectionProposal_removeunusedtype_description, name);
case IBinding.METHOD:
if (((IMethodBinding) binding).isConstructor()) {
return Messages.format(CorrectionMessages.RemoveDeclarationCorrectionProposal_removeunusedconstructor_description, name);
} else {
return Messages.format(CorrectionMessages.RemoveDeclarationCorrectionProposal_removeunusedmethod_description, name);
}
case IBinding.VARIABLE:
if (((IVariableBinding) binding).isField()) {
return Messages.format(CorrectionMessages.RemoveDeclarationCorrectionProposal_removeunusedfield_description, name);
} else {
return Messages.format(CorrectionMessages.RemoveDeclarationCorrectionProposal_removeunusedvar_description, name);
}
default:
return super.getDisplayString();
}
}
/*(non-Javadoc)
* @see org.eclipse.jdt.internal.ui.text.correction.ASTRewriteCorrectionProposal#getRewrite()
*/
@Override
protected ASTRewrite getRewrite() {
IBinding binding= fName.resolveBinding();
CompilationUnit root= (CompilationUnit) fName.getRoot();
ASTRewrite rewrite;
if (binding.getKind() == IBinding.METHOD) {
IMethodBinding decl= ((IMethodBinding) binding).getMethodDeclaration();
ASTNode declaration= root.findDeclaringNode(decl);
rewrite= ASTRewrite.create(root.getAST());
rewrite.remove(declaration, null);
} else if (binding.getKind() == IBinding.TYPE) {
ITypeBinding decl= ((ITypeBinding) binding).getTypeDeclaration();
ASTNode declaration= root.findDeclaringNode(decl);
rewrite= ASTRewrite.create(root.getAST());
rewrite.remove(declaration, null);
} else if (binding.getKind() == IBinding.VARIABLE) {
// needs full AST
CompilationUnit completeRoot= SharedASTProvider.getAST(getCompilationUnit(), SharedASTProvider.WAIT_YES, null);
SimpleName nameNode= (SimpleName) NodeFinder.perform(completeRoot, fName.getStartPosition(), fName.getLength());
rewrite= ASTRewrite.create(completeRoot.getAST());
SimpleName[] references= LinkedNodeFinder.findByBinding(completeRoot, nameNode.resolveBinding());
for (int i= 0; i < references.length; i++) {
removeVariableReferences(rewrite, references[i]);
}
IVariableBinding bindingDecl= ((IVariableBinding) nameNode.resolveBinding()).getVariableDeclaration();
ASTNode declaringNode= completeRoot.findDeclaringNode(bindingDecl);
if (declaringNode instanceof SingleVariableDeclaration) {
removeParamTag(rewrite, (SingleVariableDeclaration) declaringNode);
}
} else {
throw new IllegalArgumentException("Unexpected binding"); //$NON-NLS-1$
}
return rewrite;
}
private void removeParamTag(ASTRewrite rewrite, SingleVariableDeclaration varDecl) {
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, null);
}
}
}
}
/**
* Remove the field or variable declaration including the initializer.
* @param rewrite the ast rewrite
* @param reference the reference
*/
private void removeVariableReferences(ASTRewrite rewrite, SimpleName reference) {
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);
} else {
rewrite.replace(assignment, rewrite.createCopyTarget(rightHand), null);
}
} else if (nameParentType == ASTNode.SINGLE_VARIABLE_DECLARATION) {
rewrite.remove(parent, null);
} 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();
}
if (fragments.size() == 1) {
rewrite.remove(varDecl, null);
} else {
rewrite.remove(frag, null); // don't try to preserve
}
}
}
private void removeVariableWithInitializer(ASTRewrite rewrite, ASTNode initializerNode, ASTNode statementNode) {
ArrayList<Expression> sideEffectNodes= new ArrayList<Expression>();
initializerNode.accept(new SideEffectFinder(sideEffectNodes));
int nSideEffects= sideEffectNodes.size();
if (nSideEffects == 0) {
if (ASTNodes.isControlStatementBody(statementNode.getLocationInParent())) {
rewrite.replace(statementNode, rewrite.getAST().newBlock(), null);
} else {
rewrite.remove(statementNode, null);
}
} else {
// do nothing yet
}
}
}