/******************************************************************************* * Copyright (c) 2000, 2008 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.wst.jsdt.internal.ui.text.correction; import java.util.ArrayList; import java.util.List; import org.eclipse.ui.ISharedImages; import org.eclipse.wst.jsdt.core.IJavaScriptUnit; import org.eclipse.wst.jsdt.core.dom.ASTNode; import org.eclipse.wst.jsdt.core.dom.ASTVisitor; import org.eclipse.wst.jsdt.core.dom.Assignment; import org.eclipse.wst.jsdt.core.dom.ClassInstanceCreation; import org.eclipse.wst.jsdt.core.dom.JavaScriptUnit; import org.eclipse.wst.jsdt.core.dom.Expression; import org.eclipse.wst.jsdt.core.dom.FieldAccess; import org.eclipse.wst.jsdt.core.dom.FieldDeclaration; import org.eclipse.wst.jsdt.core.dom.IBinding; import org.eclipse.wst.jsdt.core.dom.IFunctionBinding; import org.eclipse.wst.jsdt.core.dom.ITypeBinding; import org.eclipse.wst.jsdt.core.dom.IVariableBinding; import org.eclipse.wst.jsdt.core.dom.JSdoc; import org.eclipse.wst.jsdt.core.dom.FunctionDeclaration; import org.eclipse.wst.jsdt.core.dom.FunctionInvocation; import org.eclipse.wst.jsdt.core.dom.PostfixExpression; import org.eclipse.wst.jsdt.core.dom.PrefixExpression; import org.eclipse.wst.jsdt.core.dom.QualifiedName; import org.eclipse.wst.jsdt.core.dom.SimpleName; import org.eclipse.wst.jsdt.core.dom.SingleVariableDeclaration; import org.eclipse.wst.jsdt.core.dom.SuperMethodInvocation; import org.eclipse.wst.jsdt.core.dom.TagElement; import org.eclipse.wst.jsdt.core.dom.VariableDeclarationExpression; import org.eclipse.wst.jsdt.core.dom.VariableDeclarationFragment; import org.eclipse.wst.jsdt.core.dom.VariableDeclarationStatement; import org.eclipse.wst.jsdt.core.dom.rewrite.ASTRewrite; import org.eclipse.wst.jsdt.internal.corext.dom.ASTNodes; import org.eclipse.wst.jsdt.internal.corext.dom.LinkedNodeFinder; import org.eclipse.wst.jsdt.internal.corext.dom.NodeFinder; import org.eclipse.wst.jsdt.internal.corext.util.Messages; import org.eclipse.wst.jsdt.internal.ui.JavaScriptPlugin; import org.eclipse.wst.jsdt.internal.ui.javaeditor.ASTProvider; public class RemoveDeclarationCorrectionProposal extends ASTRewriteCorrectionProposal { private static class SideEffectFinder extends ASTVisitor { private ArrayList fSideEffectNodes; public SideEffectFinder(ArrayList res) { fSideEffectNodes= res; } public boolean visit(Assignment node) { fSideEffectNodes.add(node); return false; } public boolean visit(PostfixExpression node) { fSideEffectNodes.add(node); return false; } public boolean visit(PrefixExpression node) { Object operator= node.getOperator(); if (operator == PrefixExpression.Operator.INCREMENT || operator == PrefixExpression.Operator.DECREMENT) { fSideEffectNodes.add(node); } return false; } public boolean visit(FunctionInvocation node) { fSideEffectNodes.add(node); return false; } public boolean visit(ClassInstanceCreation node) { fSideEffectNodes.add(node); return false; } public boolean visit(SuperMethodInvocation node) { fSideEffectNodes.add(node); return false; } } private SimpleName fName; public RemoveDeclarationCorrectionProposal(IJavaScriptUnit cu, SimpleName name, int relevance) { super("", cu, null, relevance, JavaScriptPlugin.getDefault().getWorkbench().getSharedImages().getImage(ISharedImages.IMG_TOOL_DELETE)); //$NON-NLS-1$ fName= name; } public String getDisplayString() { IBinding binding= fName.resolveBinding(); String name= fName.getIdentifier(); switch (binding.getKind()) { case IBinding.TYPE: return Messages.format(CorrectionMessages.RemoveDeclarationCorrectionProposal_removeunusedtype_description, name); case IBinding.METHOD: if (((IFunctionBinding) 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.wst.jsdt.internal.ui.text.correction.ASTRewriteCorrectionProposal#getRewrite() */ protected ASTRewrite getRewrite() { IBinding binding= fName.resolveBinding(); JavaScriptUnit root= (JavaScriptUnit) fName.getRoot(); ASTRewrite rewrite; if (binding.getKind() == IBinding.METHOD) { IFunctionBinding decl= ((IFunctionBinding) 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 JavaScriptUnit completeRoot= JavaScriptPlugin.getDefault().getASTProvider().getAST(getCompilationUnit(), ASTProvider.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 FunctionDeclaration) { JSdoc javadoc= ((FunctionDeclaration) 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. */ 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 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 sideEffectNodes= new ArrayList(); 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 } } }