mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-04-22 22:22:11 +02:00
Remove Function Bodies and Remove Unused Declarations refactorings.
Change-Id: I99cfe7e561ab1615c7d4ee8c126e07acbc672196
This commit is contained in:
parent
3d584f5deb
commit
739281bec7
18 changed files with 1153 additions and 14 deletions
|
@ -2,13 +2,15 @@ Manifest-Version: 1.0
|
|||
Bundle-ManifestVersion: 2
|
||||
Bundle-Name: org.eclipse.cdt.ui.tests
|
||||
Bundle-SymbolicName: org.eclipse.cdt.ui.tests; singleton:=true
|
||||
Bundle-Version: 5.4.0.qualifier
|
||||
Bundle-Version: 5.5.0.qualifier
|
||||
Bundle-Activator: org.eclipse.cdt.ui.testplugin.CTestPlugin
|
||||
Bundle-Localization: plugin
|
||||
Export-Package: org.eclipse.cdt.ui.testplugin,
|
||||
org.eclipse.cdt.ui.testplugin.util,
|
||||
org.eclipse.cdt.ui.tests,
|
||||
org.eclipse.cdt.ui.tests.DOMAST,
|
||||
org.eclipse.cdt.ui.tests.chelp,
|
||||
org.eclipse.cdt.ui.tests.reducer,
|
||||
org.eclipse.cdt.ui.tests.refactoring,
|
||||
org.eclipse.cdt.ui.tests.refactoring.rename,
|
||||
org.eclipse.cdt.ui.tests.text,
|
||||
|
@ -34,7 +36,8 @@ Require-Bundle: org.eclipse.jface.text,
|
|||
org.eclipse.core.expressions,
|
||||
com.ibm.icu,
|
||||
org.eclipse.ltk.core.refactoring;bundle-version="3.4.0",
|
||||
org.eclipse.core.filesystem;bundle-version="1.2.0"
|
||||
org.eclipse.core.filesystem;bundle-version="1.2.0",
|
||||
org.eclipse.ltk.ui.refactoring
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Bundle-Vendor: Eclipse CDT
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
|
||||
|
|
|
@ -19,5 +19,6 @@ bin.includes = plugin.xml,\
|
|||
src/,\
|
||||
ui/,\
|
||||
META-INF/,\
|
||||
.options
|
||||
.options,\
|
||||
plugin.properties
|
||||
src.includes = about.html
|
||||
|
|
16
core/org.eclipse.cdt.ui.tests/plugin.properties
Normal file
16
core/org.eclipse.cdt.ui.tests/plugin.properties
Normal file
|
@ -0,0 +1,16 @@
|
|||
###############################################################################
|
||||
# Copyright (c) 2016 Google, Inc 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:
|
||||
# Sergey Prigogin (Google) - initial implementation
|
||||
###############################################################################
|
||||
category.CodeReduction=C++ Code Reduction
|
||||
command.RemoveFunctionBodies.name=Remove Function Bodies
|
||||
command.RemoveFunctionBodies.label=Remove &Function Bodies
|
||||
command.RemoveUnusedDeclarations.name=Remove Unused Declarations
|
||||
command.RemoveUnusedDeclarations.label=Remove &Unused Declarations
|
||||
menu.ReduceCode.label=Reduce Code
|
|
@ -238,4 +238,49 @@
|
|||
</filesystem>
|
||||
</extension>
|
||||
|
||||
<extension
|
||||
point="org.eclipse.ui.commands">
|
||||
<category
|
||||
id="org.eclipse.ui.tests.category.codeReduction"
|
||||
name="%category.CodeReduction"/>
|
||||
<command
|
||||
name="%command.RemoveFunctionBodies.name"
|
||||
categoryId="org.eclipse.ui.tests.category.codeReduction"
|
||||
id="org.eclipse.cdt.ui.tests.removeFunctionBodies"/>
|
||||
<command
|
||||
name="%command.RemoveUnusedDeclarations.name"
|
||||
categoryId="org.eclipse.ui.tests.category.codeReduction"
|
||||
id="org.eclipse.cdt.ui.tests.removeUnusedDeclarations"/>
|
||||
</extension>
|
||||
|
||||
<extension
|
||||
point="org.eclipse.ui.handlers">
|
||||
<handler
|
||||
class="org.eclipse.cdt.ui.tests.reducer.RemoveFunctionBodiesHandler"
|
||||
commandId="org.eclipse.cdt.ui.tests.removeFunctionBodies"/>
|
||||
<handler
|
||||
class="org.eclipse.cdt.ui.tests.reducer.RemoveUnusedDeclarationsHandler"
|
||||
commandId="org.eclipse.cdt.ui.tests.removeUnusedDeclarations"/>
|
||||
</extension>
|
||||
|
||||
<extension point="org.eclipse.ui.menus">
|
||||
<menuContribution
|
||||
locationURI="popup:#CEditorContext?after=org.eclipse.cdt.ui.source.menu">
|
||||
<menu
|
||||
id="org.eclipse.cdt.ui.tests.reduceCode"
|
||||
label="%menu.ReduceCode.label">
|
||||
<command
|
||||
commandId="org.eclipse.cdt.ui.tests.removeFunctionBodies"
|
||||
label="%command.RemoveFunctionBodies.label"
|
||||
style="push">
|
||||
</command>
|
||||
<command
|
||||
commandId="org.eclipse.cdt.ui.tests.removeUnusedDeclarations"
|
||||
label="%command.RemoveUnusedDeclarations.label"
|
||||
style="push">
|
||||
</command>
|
||||
</menu>
|
||||
</menuContribution>
|
||||
</extension>
|
||||
|
||||
</plugin>
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<version>5.4.0-SNAPSHOT</version>
|
||||
<version>5.5.0-SNAPSHOT</version>
|
||||
<artifactId>org.eclipse.cdt.ui.tests</artifactId>
|
||||
<packaging>eclipse-test-plugin</packaging>
|
||||
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2016 Google, Inc 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:
|
||||
* Sergey Prigogin (Google) - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.ui.tests.reducer;
|
||||
|
||||
import org.eclipse.osgi.util.NLS;
|
||||
|
||||
final class Messages extends NLS {
|
||||
public static String RemoveFunctionBodiesRefactoring_RemoveFunctionBodies;
|
||||
public static String RemoveUnusedDeclarationsRefactoring_RemoveUnusedDeclarations;
|
||||
|
||||
static {
|
||||
NLS.initializeMessages(Messages.class.getName(), Messages.class);
|
||||
}
|
||||
|
||||
// Do not instantiate.
|
||||
private Messages() {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
###############################################################################
|
||||
# Copyright (c) 2016 Google, Inc 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:
|
||||
# Sergey Prigogin (Google) - initial implementation
|
||||
###############################################################################
|
||||
RemoveFunctionBodiesRefactoring_RemoveFunctionBodies=Remove Function Bodies
|
||||
RemoveUnusedDeclarationsRefactoring_RemoveUnusedDeclarations=Remove Unused Declarations
|
|
@ -0,0 +1,30 @@
|
|||
package org.eclipse.cdt.ui.tests.reducer;
|
||||
|
||||
import org.eclipse.cdt.core.dom.ast.ASTVisitor;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTName;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTNode;
|
||||
import org.eclipse.cdt.core.dom.ast.IProblemBinding;
|
||||
|
||||
class ProblemFinder extends ASTVisitor {
|
||||
boolean foundProblem;
|
||||
|
||||
public ProblemFinder() {
|
||||
shouldVisitNames = true;
|
||||
shouldVisitImplicitNames = true;
|
||||
}
|
||||
|
||||
public boolean containsProblemBinding(IASTNode node) {
|
||||
foundProblem = false;
|
||||
node.accept(this);
|
||||
return foundProblem;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int visit(IASTName name) {
|
||||
if (name.resolveBinding() instanceof IProblemBinding) {
|
||||
foundProblem = true;
|
||||
return PROCESS_ABORT;
|
||||
}
|
||||
return PROCESS_CONTINUE;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2016 Google, Inc 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:
|
||||
* Sergey Prigogin (Google) - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.ui.tests.reducer;
|
||||
|
||||
import org.eclipse.core.commands.AbstractHandler;
|
||||
import org.eclipse.core.commands.ExecutionEvent;
|
||||
import org.eclipse.core.commands.ExecutionException;
|
||||
import org.eclipse.jface.text.ITextSelection;
|
||||
import org.eclipse.jface.viewers.ISelection;
|
||||
import org.eclipse.ui.IWorkbenchPart;
|
||||
import org.eclipse.ui.handlers.HandlerUtil;
|
||||
|
||||
import org.eclipse.cdt.core.model.IWorkingCopy;
|
||||
import org.eclipse.cdt.ui.CUIPlugin;
|
||||
import org.eclipse.cdt.ui.ICEditor;
|
||||
|
||||
import org.eclipse.cdt.internal.ui.refactoring.RefactoringRunner;
|
||||
|
||||
public class RemoveFunctionBodiesHandler extends AbstractHandler {
|
||||
@Override
|
||||
public Object execute(ExecutionEvent event) throws ExecutionException {
|
||||
ISelection selection = HandlerUtil.getCurrentSelection(event);
|
||||
if (selection instanceof ITextSelection) {
|
||||
IWorkbenchPart part = HandlerUtil.getActivePart(event);
|
||||
if (part instanceof ICEditor) {
|
||||
ICEditor editor = (ICEditor) part;
|
||||
IWorkingCopy wc = CUIPlugin.getDefault().getWorkingCopyManager().getWorkingCopy(editor.getEditorInput());
|
||||
if (wc != null && wc.getResource() != null) {
|
||||
RefactoringRunner runner = new RemoveFunctionBodiesRefactoringRunner(wc, selection,
|
||||
editor.getEditorSite(), wc.getCProject());
|
||||
runner.run();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,214 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2016 Google, Inc 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:
|
||||
* Sergey Prigogin (Google) - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.ui.tests.reducer;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.core.runtime.CoreException;
|
||||
import org.eclipse.core.runtime.IProgressMonitor;
|
||||
import org.eclipse.core.runtime.OperationCanceledException;
|
||||
import org.eclipse.core.runtime.SubMonitor;
|
||||
import org.eclipse.jface.viewers.ISelection;
|
||||
import org.eclipse.ltk.core.refactoring.Change;
|
||||
import org.eclipse.ltk.core.refactoring.RefactoringChangeDescriptor;
|
||||
import org.eclipse.ltk.core.refactoring.RefactoringDescriptor;
|
||||
import org.eclipse.ltk.core.refactoring.RefactoringStatus;
|
||||
import org.eclipse.ltk.core.refactoring.participants.CheckConditionsContext;
|
||||
import org.eclipse.text.edits.DeleteEdit;
|
||||
import org.eclipse.text.edits.MultiTextEdit;
|
||||
import org.eclipse.text.edits.ReplaceEdit;
|
||||
|
||||
import org.eclipse.cdt.core.dom.ast.ASTVisitor;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTDeclaration;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTFunctionDeclarator;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTName;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTNode;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTStatement;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
|
||||
import org.eclipse.cdt.core.dom.ast.IBinding;
|
||||
import org.eclipse.cdt.core.dom.ast.INodeFactory;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTConstructorChainInitializer;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDeclSpecifier;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDeclarator;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDefinition;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateDeclaration;
|
||||
import org.eclipse.cdt.core.formatter.DefaultCodeFormatterOptions;
|
||||
import org.eclipse.cdt.core.index.IIndex;
|
||||
import org.eclipse.cdt.core.model.ICElement;
|
||||
import org.eclipse.cdt.core.model.ICProject;
|
||||
import org.eclipse.cdt.ui.refactoring.CTextFileChange;
|
||||
|
||||
import org.eclipse.cdt.internal.core.dom.parser.ASTNode;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPInternalBinding;
|
||||
import org.eclipse.cdt.internal.core.dom.rewrite.util.ASTNodes;
|
||||
|
||||
import org.eclipse.cdt.internal.ui.refactoring.CRefactoring;
|
||||
import org.eclipse.cdt.internal.ui.refactoring.ModificationCollector;
|
||||
import org.eclipse.cdt.internal.ui.refactoring.changes.CCompositeChange;
|
||||
|
||||
public class RemoveFunctionBodiesRefactoring extends CRefactoring {
|
||||
private INodeFactory nodeFactory;
|
||||
private final DefaultCodeFormatterOptions formattingOptions;
|
||||
|
||||
private IIndex index;
|
||||
private IASTTranslationUnit ast;
|
||||
|
||||
public RemoveFunctionBodiesRefactoring(ICElement element, ISelection selection, ICProject project) {
|
||||
super(element, selection, project);
|
||||
name = Messages.RemoveFunctionBodiesRefactoring_RemoveFunctionBodies;
|
||||
formattingOptions = new DefaultCodeFormatterOptions(project.getOptions(true));
|
||||
}
|
||||
|
||||
@Override
|
||||
public RefactoringStatus checkInitialConditions(IProgressMonitor pm)
|
||||
throws CoreException, OperationCanceledException {
|
||||
SubMonitor progress = SubMonitor.convert(pm, 10);
|
||||
|
||||
RefactoringStatus status = super.checkInitialConditions(progress.newChild(8));
|
||||
if (status.hasError()) {
|
||||
return status;
|
||||
}
|
||||
|
||||
ast = getAST(tu, progress.newChild(1));
|
||||
index = getIndex();
|
||||
nodeFactory = ast.getASTNodeFactory();
|
||||
|
||||
if (isProgressMonitorCanceled(progress, initStatus))
|
||||
return initStatus;
|
||||
|
||||
return initStatus;
|
||||
}
|
||||
|
||||
private ICPPASTFunctionDeclarator getDeclaration(IASTNode node) {
|
||||
while (node != null && !(node instanceof IASTFunctionDefinition)) {
|
||||
node = node.getParent();
|
||||
}
|
||||
if (node != null) {
|
||||
IASTFunctionDeclarator declarator = ((IASTFunctionDefinition) node).getDeclarator();
|
||||
if (declarator instanceof ICPPASTFunctionDeclarator) {
|
||||
return (ICPPASTFunctionDeclarator) declarator;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RefactoringStatus checkFinalConditions(IProgressMonitor pm, CheckConditionsContext checkContext) {
|
||||
return new RefactoringStatus();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Change createChange(IProgressMonitor pm) throws CoreException, OperationCanceledException {
|
||||
// This method bypasses the standard refactoring framework involving ModificationCollector and ASTRewrite since
|
||||
// it is too slow for the gigantic changes this refactoring has to deal with.
|
||||
FunctionDefinitionCollector finder = new FunctionDefinitionCollector();
|
||||
ast.accept(finder);
|
||||
String code = ast.getRawSignature();
|
||||
CTextFileChange fileChange = new CTextFileChange(tu.getElementName(), tu);
|
||||
fileChange.setEdit(new MultiTextEdit());
|
||||
for (IASTFunctionDefinition definition : finder.functionDefinitions) {
|
||||
IASTStatement body = definition.getBody();
|
||||
IASTName name = definition.getDeclarator().getName();
|
||||
IBinding binding = name.resolveBinding();
|
||||
if (binding instanceof ICPPInternalBinding) {
|
||||
IASTNode[] declarations = ((ICPPInternalBinding) binding).getDeclarations();
|
||||
if (declarations != null && declarations.length != 0
|
||||
&& ((ASTNode) declarations[0]).getOffset() < ((ASTNode) definition).getOffset()) {
|
||||
IASTNode node = definition;
|
||||
IASTNode parent;
|
||||
while ((parent = node.getParent()) instanceof ICPPASTTemplateDeclaration) {
|
||||
node = parent;
|
||||
}
|
||||
int offset = ASTNodes.offset(node);
|
||||
int endOffset = ASTNodes.endOffset(node);
|
||||
offset = skipWhitespaceBefore(offset, code);
|
||||
// Remove the whole definition since the function is declared already.
|
||||
fileChange.addEdit(new DeleteEdit(offset, endOffset - offset));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
int offset = ASTNodes.offset(body);
|
||||
int endOffset = ASTNodes.endOffset(body);
|
||||
if (definition instanceof ICPPASTFunctionDefinition) {
|
||||
ICPPASTConstructorChainInitializer[] initializers =
|
||||
((ICPPASTFunctionDefinition) definition).getMemberInitializers();
|
||||
if (initializers.length != 0) {
|
||||
offset = ASTNodes.offset(initializers[0]);
|
||||
offset = skipWhitespaceBefore(offset, code);
|
||||
if (offset > 0 && code.charAt(offset - 1) == ':')
|
||||
offset--;
|
||||
}
|
||||
}
|
||||
offset = skipWhitespaceBefore(offset, code);
|
||||
fileChange.addEdit(new ReplaceEdit(offset, endOffset - offset, ";"));
|
||||
}
|
||||
|
||||
CCompositeChange change = new CCompositeChange(""); //$NON-NLS-1$
|
||||
change.markAsSynthetic();
|
||||
change.add(fileChange);
|
||||
change.setDescription(new RefactoringChangeDescriptor(getRefactoringDescriptor()));
|
||||
return change;
|
||||
}
|
||||
|
||||
private static int skipWhitespaceBefore(int offset, String text) {
|
||||
while (--offset >= 0) {
|
||||
char c = text.charAt(offset);
|
||||
if (!Character.isWhitespace(c))
|
||||
break;
|
||||
}
|
||||
return offset + 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void collectModifications(IProgressMonitor pm, ModificationCollector collector)
|
||||
throws CoreException, OperationCanceledException {
|
||||
// This method is no-op for this refactoring. The change is created in the createChange method.
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds function definitions that have bodies, are not constexpr, and don't contain problem bindings.
|
||||
*/
|
||||
private class FunctionDefinitionCollector extends ASTVisitor {
|
||||
final List<IASTFunctionDefinition> functionDefinitions = new ArrayList<>();
|
||||
final ProblemFinder problemFinder = new ProblemFinder();
|
||||
|
||||
FunctionDefinitionCollector() {
|
||||
shouldVisitDeclarations = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int visit(IASTDeclaration declaration) {
|
||||
if (!declaration.isPartOfTranslationUnitFile())
|
||||
return PROCESS_SKIP;
|
||||
if (!(declaration instanceof IASTFunctionDefinition))
|
||||
return PROCESS_CONTINUE;
|
||||
IASTFunctionDefinition definition = (IASTFunctionDefinition) declaration;
|
||||
if (definition.getBody() == null)
|
||||
return PROCESS_SKIP;
|
||||
IASTDeclSpecifier declSpec = definition.getDeclSpecifier();
|
||||
if (declSpec instanceof ICPPASTDeclSpecifier && ((ICPPASTDeclSpecifier) declSpec).isConstexpr())
|
||||
return PROCESS_SKIP;
|
||||
if (problemFinder.containsProblemBinding(declaration))
|
||||
return PROCESS_SKIP;
|
||||
functionDefinitions.add(definition);
|
||||
return PROCESS_SKIP;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RefactoringDescriptor getRefactoringDescriptor() {
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2016 Google, Inc 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:
|
||||
* Sergey Prigogin (Google) - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.ui.tests.reducer;
|
||||
|
||||
import org.eclipse.jface.viewers.ISelection;
|
||||
import org.eclipse.jface.window.IShellProvider;
|
||||
|
||||
import org.eclipse.cdt.core.model.ICElement;
|
||||
import org.eclipse.cdt.core.model.ICProject;
|
||||
|
||||
import org.eclipse.cdt.internal.ui.refactoring.RefactoringRunner;
|
||||
import org.eclipse.cdt.internal.ui.refactoring.RefactoringSaveHelper;
|
||||
|
||||
public class RemoveFunctionBodiesRefactoringRunner extends RefactoringRunner {
|
||||
|
||||
public RemoveFunctionBodiesRefactoringRunner(ICElement element, ISelection selection,
|
||||
IShellProvider shellProvider, ICProject cProject) {
|
||||
super(element, selection, shellProvider, cProject);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
RemoveFunctionBodiesRefactoring refactoring =
|
||||
new RemoveFunctionBodiesRefactoring(element, selection, project);
|
||||
RemoveFunctionBodiesWizard wizard = new RemoveFunctionBodiesWizard(refactoring);
|
||||
run(wizard, refactoring, RefactoringSaveHelper.SAVE_NOTHING);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2016 Google, Inc 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:
|
||||
* Sergey Prigogin (Google) - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.ui.tests.reducer;
|
||||
|
||||
import org.eclipse.ltk.ui.refactoring.RefactoringWizard;
|
||||
|
||||
import org.eclipse.cdt.ui.CUIPlugin;
|
||||
|
||||
public class RemoveFunctionBodiesWizard extends RefactoringWizard {
|
||||
public RemoveFunctionBodiesWizard(RemoveFunctionBodiesRefactoring refactoring) {
|
||||
super(refactoring, DIALOG_BASED_USER_INTERFACE | PREVIEW_EXPAND_FIRST_NODE);
|
||||
setDefaultPageTitle(Messages.RemoveFunctionBodiesRefactoring_RemoveFunctionBodies);
|
||||
setDialogSettings(CUIPlugin.getDefault().getDialogSettings());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addUserInputPages() {
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2016 Google, Inc 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:
|
||||
* Sergey Prigogin (Google) - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.ui.tests.reducer;
|
||||
|
||||
import org.eclipse.core.commands.AbstractHandler;
|
||||
import org.eclipse.core.commands.ExecutionEvent;
|
||||
import org.eclipse.core.commands.ExecutionException;
|
||||
import org.eclipse.jface.text.ITextSelection;
|
||||
import org.eclipse.jface.viewers.ISelection;
|
||||
import org.eclipse.ui.IWorkbenchPart;
|
||||
import org.eclipse.ui.handlers.HandlerUtil;
|
||||
|
||||
import org.eclipse.cdt.core.model.IWorkingCopy;
|
||||
import org.eclipse.cdt.ui.CUIPlugin;
|
||||
import org.eclipse.cdt.ui.ICEditor;
|
||||
|
||||
import org.eclipse.cdt.internal.ui.refactoring.RefactoringRunner;
|
||||
|
||||
public class RemoveUnusedDeclarationsHandler extends AbstractHandler {
|
||||
@Override
|
||||
public Object execute(ExecutionEvent event) throws ExecutionException {
|
||||
ISelection selection = HandlerUtil.getCurrentSelection(event);
|
||||
if (selection instanceof ITextSelection) {
|
||||
IWorkbenchPart part = HandlerUtil.getActivePart(event);
|
||||
if (part instanceof ICEditor) {
|
||||
ICEditor editor = (ICEditor) part;
|
||||
IWorkingCopy wc = CUIPlugin.getDefault().getWorkingCopyManager().getWorkingCopy(editor.getEditorInput());
|
||||
if (wc != null && wc.getResource() != null) {
|
||||
RefactoringRunner runner = new RemoveUnusedDeclarationsRefactoringRunner(wc, selection,
|
||||
editor.getEditorSite(), wc.getCProject());
|
||||
runner.run();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2016 Google, Inc 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:
|
||||
* Sergey Prigogin (Google) - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.ui.tests.reducer;
|
||||
|
||||
import org.eclipse.jface.dialogs.IDialogSettings;
|
||||
import org.eclipse.ltk.ui.refactoring.UserInputWizardPage;
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.events.ModifyEvent;
|
||||
import org.eclipse.swt.events.ModifyListener;
|
||||
import org.eclipse.swt.layout.GridData;
|
||||
import org.eclipse.swt.layout.GridLayout;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.Text;
|
||||
|
||||
import org.eclipse.cdt.internal.ui.CPluginImages;
|
||||
import org.eclipse.cdt.internal.ui.dialogs.TextFieldNavigationHandler;
|
||||
import org.eclipse.cdt.internal.ui.util.RowLayouter;
|
||||
|
||||
public class RemoveUnusedDeclarationsInputPage extends UserInputWizardPage {
|
||||
public static final String PAGE_NAME = "RemoveUnusedDeclarationsInputPage"; //$NON-NLS-1$
|
||||
|
||||
private RemoveFunctionBodiesRefactoring refactoring;
|
||||
private Text textField;
|
||||
private IDialogSettings settings;
|
||||
|
||||
public RemoveUnusedDeclarationsInputPage() {
|
||||
super(PAGE_NAME);
|
||||
setImageDescriptor(CPluginImages.DESC_WIZBAN_REFACTOR_TU);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createControl(Composite parent) {
|
||||
refactoring = (RemoveFunctionBodiesRefactoring) getRefactoring();
|
||||
|
||||
Composite result = new Composite(parent, SWT.NONE);
|
||||
setControl(result);
|
||||
GridLayout layout = new GridLayout();
|
||||
layout.numColumns = 2;
|
||||
result.setLayout(layout);
|
||||
RowLayouter layouter = new RowLayouter(2);
|
||||
GridData gd = null;
|
||||
|
||||
initializeDialogUnits(result);
|
||||
|
||||
Composite group = new Composite(result, SWT.NONE);
|
||||
group.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
|
||||
layout = new GridLayout();
|
||||
layout.numColumns = 4;
|
||||
layout.marginWidth = 0;
|
||||
group.setLayout(layout);
|
||||
}
|
||||
|
||||
private Text createTextInputField(Composite parent, int style) {
|
||||
Text result = new Text(parent, style);
|
||||
result.addModifyListener(new ModifyListener() {
|
||||
@Override
|
||||
public void modifyText(ModifyEvent e) {
|
||||
// textModified(result.getText());
|
||||
}
|
||||
});
|
||||
TextFieldNavigationHandler.install(result);
|
||||
return result;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,499 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2016 Google, Inc 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:
|
||||
* Sergey Prigogin (Google) - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.ui.tests.reducer;
|
||||
|
||||
import static org.eclipse.cdt.internal.core.dom.parser.ASTQueries.findInnermostDeclarator;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.NavigableSet;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import org.eclipse.core.runtime.CoreException;
|
||||
import org.eclipse.core.runtime.IProgressMonitor;
|
||||
import org.eclipse.core.runtime.OperationCanceledException;
|
||||
import org.eclipse.core.runtime.SubMonitor;
|
||||
import org.eclipse.jface.text.IRegion;
|
||||
import org.eclipse.jface.text.Region;
|
||||
import org.eclipse.jface.viewers.ISelection;
|
||||
import org.eclipse.ltk.core.refactoring.Change;
|
||||
import org.eclipse.ltk.core.refactoring.RefactoringChangeDescriptor;
|
||||
import org.eclipse.ltk.core.refactoring.RefactoringDescriptor;
|
||||
import org.eclipse.ltk.core.refactoring.RefactoringStatus;
|
||||
import org.eclipse.ltk.core.refactoring.participants.CheckConditionsContext;
|
||||
import org.eclipse.text.edits.DeleteEdit;
|
||||
import org.eclipse.text.edits.MultiTextEdit;
|
||||
import org.eclipse.text.edits.TextEdit;
|
||||
|
||||
import org.eclipse.cdt.core.dom.ast.ASTNodeProperty;
|
||||
import org.eclipse.cdt.core.dom.ast.ASTVisitor;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTCompositeTypeSpecifier;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTDeclaration;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTDeclarationListOwner;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTDeclarationStatement;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTDeclarator;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTElaboratedTypeSpecifier;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTEnumerationSpecifier;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTFunctionDeclarator;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTName;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTNode;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorMacroExpansion;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
|
||||
import org.eclipse.cdt.core.dom.ast.IBinding;
|
||||
import org.eclipse.cdt.core.dom.ast.INodeFactory;
|
||||
import org.eclipse.cdt.core.dom.ast.IProblemBinding;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTAliasDeclaration;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTConversionName;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTEnumerationSpecifier;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTExplicitTemplateInstantiation;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDeclarator;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTLinkageSpecification;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNamespaceAlias;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNamespaceDefinition;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTQualifiedName;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateDeclaration;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateId;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateSpecialization;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTUsingDeclaration;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTUsingDirective;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTVisibilityLabel;
|
||||
import org.eclipse.cdt.core.formatter.DefaultCodeFormatterOptions;
|
||||
import org.eclipse.cdt.core.index.IIndex;
|
||||
import org.eclipse.cdt.core.model.ICElement;
|
||||
import org.eclipse.cdt.core.model.ICProject;
|
||||
import org.eclipse.cdt.core.parser.util.CharArrayUtils;
|
||||
import org.eclipse.cdt.ui.refactoring.CTextFileChange;
|
||||
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTName;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPInternalBinding;
|
||||
import org.eclipse.cdt.internal.core.dom.rewrite.util.ASTNodes;
|
||||
|
||||
import org.eclipse.cdt.internal.ui.refactoring.CRefactoring;
|
||||
import org.eclipse.cdt.internal.ui.refactoring.ModificationCollector;
|
||||
import org.eclipse.cdt.internal.ui.refactoring.changes.CCompositeChange;
|
||||
import org.eclipse.cdt.internal.ui.refactoring.utils.SelectionHelper;
|
||||
|
||||
public class RemoveUnusedDeclarationsRefactoring extends CRefactoring {
|
||||
private static final IASTName UNUSED_NAME = new CPPASTName(null);
|
||||
private static final ProblemFinder problemFinder = new ProblemFinder();
|
||||
|
||||
private INodeFactory nodeFactory;
|
||||
private final DefaultCodeFormatterOptions formattingOptions;
|
||||
|
||||
private IIndex index;
|
||||
private IASTTranslationUnit ast;
|
||||
private IRegion region;
|
||||
|
||||
public RemoveUnusedDeclarationsRefactoring(ICElement element, ISelection selection, ICProject project) {
|
||||
super(element, selection, project);
|
||||
name = Messages.RemoveUnusedDeclarationsRefactoring_RemoveUnusedDeclarations;
|
||||
formattingOptions = new DefaultCodeFormatterOptions(project.getOptions(true));
|
||||
}
|
||||
|
||||
@Override
|
||||
public RefactoringStatus checkInitialConditions(IProgressMonitor pm)
|
||||
throws CoreException, OperationCanceledException {
|
||||
SubMonitor progress = SubMonitor.convert(pm, 10);
|
||||
|
||||
RefactoringStatus status = super.checkInitialConditions(progress.newChild(8));
|
||||
if (status.hasError()) {
|
||||
return status;
|
||||
}
|
||||
|
||||
ast = getAST(tu, progress.newChild(1));
|
||||
index = getIndex();
|
||||
nodeFactory = ast.getASTNodeFactory();
|
||||
region = selectedRegion.getLength() == 0 ?
|
||||
new Region(0, ast.getFileLocation().getNodeLength()) : selectedRegion;
|
||||
|
||||
if (isProgressMonitorCanceled(progress, initStatus))
|
||||
return initStatus;
|
||||
|
||||
return initStatus;
|
||||
}
|
||||
|
||||
private ICPPASTFunctionDeclarator getDeclaration(IASTNode node) {
|
||||
while (node != null && !(node instanceof IASTFunctionDefinition)) {
|
||||
node = node.getParent();
|
||||
}
|
||||
if (node != null) {
|
||||
IASTFunctionDeclarator declarator = ((IASTFunctionDefinition) node).getDeclarator();
|
||||
if (declarator instanceof ICPPASTFunctionDeclarator) {
|
||||
return (ICPPASTFunctionDeclarator) declarator;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RefactoringStatus checkFinalConditions(IProgressMonitor pm, CheckConditionsContext checkContext) {
|
||||
return new RefactoringStatus();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Change createChange(IProgressMonitor pm) throws CoreException, OperationCanceledException {
|
||||
// This method bypasses the standard refactoring framework involving ModificationCollector and ASTRewrite since
|
||||
// it is too slow for the gigantic changes this refactoring has to deal with.
|
||||
NavigableSet<IASTName> names = NameCollector.getContainedNames(ast);
|
||||
|
||||
SortedNodeSet<IASTNode> nodesToDelete = new SortedNodeSet<>();
|
||||
IASTPreprocessorMacroExpansion[] macroExpansions = ast.getMacroExpansions();
|
||||
for (IASTPreprocessorMacroExpansion macroExpansion : macroExpansions) {
|
||||
IASTName name = macroExpansion.getMacroReference();
|
||||
if (SelectionHelper.isNodeInsideRegion(name, region)
|
||||
&& macroExpansion.getMacroDefinition().getExpansion().isEmpty()) {
|
||||
nodesToDelete.add(macroExpansion);
|
||||
}
|
||||
}
|
||||
|
||||
CandidateDeclarationFinder finder = new CandidateDeclarationFinder();
|
||||
ast.accept(finder);
|
||||
List<IASTDeclaration> declarations = finder.declarations;
|
||||
|
||||
for (int i = declarations.size(); --i >= 0;) {
|
||||
IASTDeclaration declaration = declarations.get(i);
|
||||
if (SelectionHelper.isNodeInsideRegion(declaration, region)
|
||||
&& !problemFinder.containsProblemBinding(declaration)
|
||||
&& !isPossiblyUsed(declaration, names, nodesToDelete)) {
|
||||
nodesToDelete.add(declaration);
|
||||
removeContainedNames(declaration, names);
|
||||
}
|
||||
}
|
||||
|
||||
String code = ast.getRawSignature();
|
||||
CTextFileChange fileChange = new CTextFileChange(tu.getElementName(), tu);
|
||||
fileChange.setEdit(new MultiTextEdit());
|
||||
|
||||
int maxOffset = 0;
|
||||
TextEdit lastEdit = null;
|
||||
IASTNode lastNode = null;
|
||||
for (IASTNode node : nodesToDelete) {
|
||||
int offset = ASTNodes.offset(node);
|
||||
int endOffset = ASTNodes.endOffset(node);
|
||||
offset = skipWhitespaceBefore(offset, code);
|
||||
if (offset < region.getOffset())
|
||||
offset = region.getOffset();
|
||||
// Do not attempt to delete nodes inside a deleted region.
|
||||
if (endOffset > maxOffset) {
|
||||
DeleteEdit edit = new DeleteEdit(offset, endOffset - offset);
|
||||
fileChange.addEdit(edit);
|
||||
if (maxOffset < endOffset)
|
||||
maxOffset = endOffset;
|
||||
lastEdit = edit;
|
||||
lastNode = node;
|
||||
}
|
||||
}
|
||||
|
||||
CCompositeChange change = new CCompositeChange(""); //$NON-NLS-1$
|
||||
change.markAsSynthetic();
|
||||
change.add(fileChange);
|
||||
change.setDescription(new RefactoringChangeDescriptor(getRefactoringDescriptor()));
|
||||
return change;
|
||||
}
|
||||
|
||||
private boolean containsAncestor(Collection<IASTNode> nodes, IASTNode node) {
|
||||
while ((node = node.getParent()) != null) {
|
||||
if (nodes.contains(node))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private IASTNode getTopMostContainer(IASTNode node) {
|
||||
while (node != null) {
|
||||
IASTNode prevNode = node;
|
||||
node = node.getParent();
|
||||
if (node instanceof IASTTranslationUnit)
|
||||
return prevNode;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean isPossiblyUsed(IASTDeclaration declaration, NavigableSet<IASTName> names,
|
||||
SortedNodeSet<IASTNode> nodesToDelete) {
|
||||
if (declaration instanceof ICPPASTNamespaceDefinition) {
|
||||
// An empty namespace definition can be removed.
|
||||
IASTDeclaration[] children = ((ICPPASTNamespaceDefinition) declaration).getDeclarations(false);
|
||||
for (IASTDeclaration child : children) {
|
||||
if (!nodesToDelete.contains(child))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
} else if (declaration instanceof ICPPASTLinkageSpecification) {
|
||||
// An empty linkage specification can be removed.
|
||||
IASTDeclaration[] children = ((ICPPASTLinkageSpecification) declaration).getDeclarations(false);
|
||||
for (IASTDeclaration child : children) {
|
||||
if (!nodesToDelete.contains(child))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
} else if (declaration instanceof ICPPASTVisibilityLabel) {
|
||||
// A visibility label not followed by a member declaration can be removed.
|
||||
IASTNode parent = declaration.getParent();
|
||||
IASTDeclaration[] siblings = ((ICPPASTCompositeTypeSpecifier) parent).getDeclarations(false);
|
||||
boolean after = false;
|
||||
for (IASTDeclaration sibling : siblings) {
|
||||
if (after) {
|
||||
if (sibling instanceof ICPPASTVisibilityLabel)
|
||||
break;
|
||||
if (!nodesToDelete.contains(sibling))
|
||||
return true;
|
||||
} else if (sibling == declaration) {
|
||||
after = true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Collection<IASTName> declaredNames = getDeclaredNames(declaration);
|
||||
if (declaredNames == null)
|
||||
return true;
|
||||
|
||||
for (IASTName declName : declaredNames) {
|
||||
char[] declNameChars = declName.getSimpleID();
|
||||
if (declNameChars.length != 0 && declNameChars[0] == '~')
|
||||
declNameChars = Arrays.copyOfRange(declNameChars, 1, declNameChars.length);
|
||||
IASTNode startPoint = declName;
|
||||
int startOffset = ASTNodes.endOffset(declaration);
|
||||
if (declaration.getPropertyInParent() == IASTCompositeTypeSpecifier.MEMBER_DECLARATION) {
|
||||
// Member declarations can be referenced by other members declared before them.
|
||||
startPoint = declaration.getParent();
|
||||
startOffset = ASTNodes.offset(startPoint);
|
||||
} else {
|
||||
ASTNodeProperty property = declName.getPropertyInParent();
|
||||
if (property == IASTCompositeTypeSpecifier.TYPE_NAME
|
||||
|| property == ICPPASTEnumerationSpecifier.ENUMERATION_NAME && ((ICPPASTEnumerationSpecifier) declName.getParent()).isScoped()) {
|
||||
while (declName instanceof ICPPASTTemplateId) {
|
||||
declName = ((ICPPASTTemplateId) declName).getTemplateName();
|
||||
}
|
||||
IBinding binding = declName.resolveBinding();
|
||||
if (binding instanceof IProblemBinding)
|
||||
return true;
|
||||
if (binding instanceof ICPPInternalBinding) {
|
||||
IASTNode[] declarations = ((ICPPInternalBinding) binding).getDeclarations();
|
||||
if (declarations != null && declarations.length != 0) {
|
||||
IASTNode firstDeclaration = declarations[0];
|
||||
int firstDeclarationOffset = ASTNodes.offset(firstDeclaration);
|
||||
if (startOffset > firstDeclarationOffset) {
|
||||
startPoint = firstDeclaration;
|
||||
startOffset = firstDeclarationOffset;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (IASTName name : names) {
|
||||
if (name != declName) {
|
||||
char[] nameChars = name.getSimpleID();
|
||||
int offset = nameChars.length != 0 && nameChars[0] == '~' ? 1 : 0;
|
||||
if (CharArrayUtils.equals(nameChars, offset, nameChars.length - offset, declNameChars)
|
||||
&& (ASTNodes.offset(name) >= startOffset
|
||||
|| isInsideTemplateDeclarationOrSpecialization(name))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
private static Collection<IASTName> getDeclaredNames(IASTDeclaration declaration) {
|
||||
while (declaration instanceof ICPPASTTemplateDeclaration) {
|
||||
declaration = ((ICPPASTTemplateDeclaration) declaration).getDeclaration();
|
||||
}
|
||||
while (declaration instanceof ICPPASTTemplateSpecialization) {
|
||||
declaration = ((ICPPASTTemplateSpecialization) declaration).getDeclaration();
|
||||
}
|
||||
while (declaration instanceof ICPPASTExplicitTemplateInstantiation) {
|
||||
declaration = ((ICPPASTExplicitTemplateInstantiation) declaration).getDeclaration();
|
||||
}
|
||||
|
||||
if (declaration instanceof IASTSimpleDeclaration) {
|
||||
List<IASTName> names = new ArrayList<>();
|
||||
IASTDeclarator[] declarators = ((IASTSimpleDeclaration) declaration).getDeclarators();
|
||||
for (IASTDeclarator declarator : declarators) {
|
||||
declarator = findInnermostDeclarator(declarator);
|
||||
IASTName name = declarator.getName();
|
||||
if (name instanceof ICPPASTConversionName)
|
||||
return null; // Do not remove conversion operators.
|
||||
names.add(name);
|
||||
}
|
||||
IASTDeclSpecifier declSpecifier = ((IASTSimpleDeclaration) declaration).getDeclSpecifier();
|
||||
if (declSpecifier instanceof IASTCompositeTypeSpecifier) {
|
||||
names.add(((IASTCompositeTypeSpecifier) declSpecifier).getName());
|
||||
} else if (declSpecifier instanceof IASTElaboratedTypeSpecifier) {
|
||||
names.add(((IASTElaboratedTypeSpecifier) declSpecifier).getName());
|
||||
} else if (declSpecifier instanceof IASTEnumerationSpecifier) {
|
||||
names.add(((IASTEnumerationSpecifier) declSpecifier).getName());
|
||||
}
|
||||
return names;
|
||||
} else if (declaration instanceof IASTFunctionDefinition) {
|
||||
IASTDeclarator declarator = ((IASTFunctionDefinition) declaration).getDeclarator();
|
||||
declarator = findInnermostDeclarator(declarator);
|
||||
IASTName name = declarator.getName();
|
||||
if (name instanceof ICPPASTConversionName)
|
||||
return null; // Do not remove conversion operators.
|
||||
return Collections.singletonList(name);
|
||||
} else if (declaration instanceof ICPPASTUsingDirective) {
|
||||
return Collections.singletonList(((ICPPASTUsingDirective) declaration).getQualifiedName());
|
||||
} else if (declaration instanceof ICPPASTUsingDeclaration) {
|
||||
return Collections.singletonList(((ICPPASTUsingDeclaration) declaration).getName());
|
||||
} else if (declaration instanceof ICPPASTNamespaceAlias) {
|
||||
return Collections.singletonList(((ICPPASTNamespaceAlias) declaration).getAlias());
|
||||
} else if (declaration instanceof ICPPASTAliasDeclaration) {
|
||||
return Collections.singletonList(((ICPPASTAliasDeclaration) declaration).getAlias());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean isInsideTemplateDeclarationOrSpecialization(IASTNode node) {
|
||||
while ((node = node.getParent()) != null) {
|
||||
if (node instanceof ICPPASTTemplateDeclaration || node instanceof ICPPASTTemplateSpecialization)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static void removeContainedNames(IASTNode node, Set<IASTName> names) {
|
||||
NavigableSet<IASTName> containedNames = NameCollector.getContainedNames(node);
|
||||
names.removeAll(containedNames);
|
||||
}
|
||||
|
||||
private static int skipWhitespaceBefore(int offset, String text) {
|
||||
while (--offset >= 0) {
|
||||
char c = text.charAt(offset);
|
||||
if (!Character.isWhitespace(c))
|
||||
break;
|
||||
}
|
||||
return offset + 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void collectModifications(IProgressMonitor pm, ModificationCollector collector)
|
||||
throws CoreException, OperationCanceledException {
|
||||
// This method is no-op for this refactoring. The change is created in the createChange method.
|
||||
}
|
||||
|
||||
private class CandidateDeclarationFinder extends ASTVisitor {
|
||||
final List<IASTDeclaration> declarations = new ArrayList<>();
|
||||
|
||||
CandidateDeclarationFinder() {
|
||||
shouldVisitDeclarations = true;
|
||||
shouldVisitNamespaces = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int visit(IASTDeclaration declaration) {
|
||||
if (!declaration.isPartOfTranslationUnitFile())
|
||||
return PROCESS_SKIP;
|
||||
if (declaration.getParent() instanceof IASTDeclarationListOwner)
|
||||
declarations.add(declaration);
|
||||
return PROCESS_CONTINUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int visit(ICPPASTNamespaceDefinition namespaceDefinition) {
|
||||
if (!namespaceDefinition.isPartOfTranslationUnitFile())
|
||||
return PROCESS_SKIP;
|
||||
declarations.add(namespaceDefinition);
|
||||
return PROCESS_CONTINUE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Collects all simple names.
|
||||
*/
|
||||
private static class NameCollector extends ASTVisitor {
|
||||
NavigableSet<IASTName> names = new SortedNodeSet<>();
|
||||
|
||||
static NavigableSet<IASTName> getContainedNames(IASTNode node) {
|
||||
NameCollector collector = new NameCollector();
|
||||
node.accept(collector);
|
||||
return collector.names;
|
||||
}
|
||||
|
||||
NameCollector() {
|
||||
this.shouldVisitNames = true;
|
||||
this.shouldVisitImplicitNames = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int visit(IASTName name) {
|
||||
if (name instanceof ICPPASTQualifiedName || name instanceof ICPPASTTemplateId
|
||||
|| name instanceof ICPPASTConversionName) {
|
||||
return PROCESS_CONTINUE;
|
||||
}
|
||||
names.add(name);
|
||||
return PROCESS_CONTINUE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A set of AST nodes sorted by their offsets, or, if the offsets are equal, by the end offsets
|
||||
* in the reverse order.
|
||||
*/
|
||||
private static class SortedNodeSet<T extends IASTNode> extends TreeSet<T> {
|
||||
private static final Comparator<IASTNode> COMPARATOR = new Comparator<IASTNode>() {
|
||||
@Override
|
||||
public int compare(IASTNode node1, IASTNode node2) {
|
||||
int c = Integer.compare(ASTNodes.offset(node1), ASTNodes.offset(node2));
|
||||
if (c != 0)
|
||||
return c;
|
||||
return -Integer.compare(ASTNodes.endOffset(node1), ASTNodes.endOffset(node2));
|
||||
}
|
||||
};
|
||||
|
||||
public SortedNodeSet() {
|
||||
super(COMPARATOR);
|
||||
}
|
||||
}
|
||||
|
||||
private static IASTDeclarationStatement getDeclarationStatement(IASTDeclaration declaration) {
|
||||
while (true) {
|
||||
IASTNode parent = declaration.getParent();
|
||||
if (parent instanceof IASTDeclarationStatement)
|
||||
return (IASTDeclarationStatement) parent;
|
||||
if (!(parent instanceof ICPPASTTemplateDeclaration))
|
||||
return null;
|
||||
declaration = (IASTDeclaration) parent;
|
||||
}
|
||||
}
|
||||
|
||||
private static IASTName getAstName(IASTDeclarator decl) {
|
||||
IASTName astName = null;
|
||||
do {
|
||||
astName = decl.getName();
|
||||
if (astName != null && astName.getSimpleID().length != 0)
|
||||
return astName;
|
||||
|
||||
// Resolve parenthesis if need to.
|
||||
decl = decl.getNestedDeclarator();
|
||||
} while (decl != null);
|
||||
|
||||
return astName;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RefactoringDescriptor getRefactoringDescriptor() {
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2016 Google, Inc 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:
|
||||
* Sergey Prigogin (Google) - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.ui.tests.reducer;
|
||||
|
||||
import org.eclipse.jface.viewers.ISelection;
|
||||
import org.eclipse.jface.window.IShellProvider;
|
||||
|
||||
import org.eclipse.cdt.core.model.ICElement;
|
||||
import org.eclipse.cdt.core.model.ICProject;
|
||||
|
||||
import org.eclipse.cdt.internal.ui.refactoring.RefactoringRunner;
|
||||
import org.eclipse.cdt.internal.ui.refactoring.RefactoringSaveHelper;
|
||||
|
||||
public class RemoveUnusedDeclarationsRefactoringRunner extends RefactoringRunner {
|
||||
|
||||
public RemoveUnusedDeclarationsRefactoringRunner(ICElement element, ISelection selection,
|
||||
IShellProvider shellProvider, ICProject cProject) {
|
||||
super(element, selection, shellProvider, cProject);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
RemoveUnusedDeclarationsRefactoring refactoring =
|
||||
new RemoveUnusedDeclarationsRefactoring(element, selection, project);
|
||||
RemoveUnusedDeclarationsWizard wizard = new RemoveUnusedDeclarationsWizard(refactoring);
|
||||
run(wizard, refactoring, RefactoringSaveHelper.SAVE_NOTHING);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2016 Google, Inc 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:
|
||||
* Sergey Prigogin (Google) - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.ui.tests.reducer;
|
||||
|
||||
import org.eclipse.ltk.ui.refactoring.RefactoringWizard;
|
||||
|
||||
import org.eclipse.cdt.ui.CUIPlugin;
|
||||
|
||||
public class RemoveUnusedDeclarationsWizard extends RefactoringWizard {
|
||||
public RemoveUnusedDeclarationsWizard(RemoveUnusedDeclarationsRefactoring refactoring) {
|
||||
super(refactoring, DIALOG_BASED_USER_INTERFACE | PREVIEW_EXPAND_FIRST_NODE);
|
||||
setDefaultPageTitle(Messages.RemoveFunctionBodiesRefactoring_RemoveFunctionBodies);
|
||||
setDialogSettings(CUIPlugin.getDefault().getDialogSettings());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addUserInputPages() {
|
||||
}
|
||||
}
|
||||
|
|
@ -13,6 +13,7 @@
|
|||
*******************************************************************************/
|
||||
package org.eclipse.cdt.internal.ui.refactoring.utils;
|
||||
|
||||
import org.eclipse.jface.text.IRegion;
|
||||
import org.eclipse.jface.text.ITextSelection;
|
||||
import org.eclipse.jface.text.Region;
|
||||
import org.eclipse.jface.viewers.ISelection;
|
||||
|
@ -43,9 +44,9 @@ public class SelectionHelper {
|
|||
return null;
|
||||
}
|
||||
|
||||
public static IASTSimpleDeclaration findFirstSelectedDeclaration(final Region textSelection,
|
||||
public static IASTSimpleDeclaration findFirstSelectedDeclaration(final IRegion textSelection,
|
||||
IASTTranslationUnit translationUnit) {
|
||||
final Container<IASTSimpleDeclaration> container = new Container<IASTSimpleDeclaration>();
|
||||
final Container<IASTSimpleDeclaration> container = new Container<>();
|
||||
|
||||
translationUnit.accept(new ASTVisitor() {
|
||||
{
|
||||
|
@ -64,18 +65,18 @@ public class SelectionHelper {
|
|||
return container.getObject();
|
||||
}
|
||||
|
||||
public static boolean doesNodeOverlapWithRegion(IASTNode node, Region region) {
|
||||
public static boolean doesNodeOverlapWithRegion(IASTNode node, IRegion region) {
|
||||
return doRegionsOverlap(getNodeSpan(node), region);
|
||||
}
|
||||
|
||||
public static boolean isNodeInsideRegion(IASTNode node, Region region) {
|
||||
public static boolean isNodeInsideRegion(IASTNode node, IRegion region) {
|
||||
return isRegionInside(getNodeSpan(node), region);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the first region is inside the second.
|
||||
*/
|
||||
private static boolean isRegionInside(Region region1, Region region2) {
|
||||
private static boolean isRegionInside(IRegion region1, IRegion region2) {
|
||||
int offset1 = region1.getOffset();
|
||||
int offset2 = region2.getOffset();
|
||||
return offset1 >= offset2 &&
|
||||
|
@ -85,26 +86,26 @@ public class SelectionHelper {
|
|||
/**
|
||||
* Returns true if the two regions have at least one common point.
|
||||
*/
|
||||
private static boolean doRegionsOverlap(Region region1, Region region2) {
|
||||
private static boolean doRegionsOverlap(IRegion region1, IRegion region2) {
|
||||
int offset1 = region1.getOffset();
|
||||
int offset2 = region2.getOffset();
|
||||
return offset1 + region1.getLength() >= offset2 &&
|
||||
offset1 <= offset2 + region2.getLength();
|
||||
}
|
||||
|
||||
public static boolean isNodeInsideSelection(IASTNode node, Region selection) {
|
||||
public static boolean isNodeInsideSelection(IASTNode node, IRegion selection) {
|
||||
return node.isPartOfTranslationUnitFile() && isNodeInsideRegion(node, selection);
|
||||
}
|
||||
|
||||
public static boolean isSelectionInsideNode(IASTNode node, Region selection) {
|
||||
public static boolean isSelectionInsideNode(IASTNode node, IRegion selection) {
|
||||
return node.isPartOfTranslationUnitFile() && isRegionInside(selection, getNodeSpan(node));
|
||||
}
|
||||
|
||||
public static boolean nodeMatchesSelection(IASTNode node, Region region) {
|
||||
public static boolean nodeMatchesSelection(IASTNode node, IRegion region) {
|
||||
return getNodeSpan(node).equals(region);
|
||||
}
|
||||
|
||||
protected static Region getNodeSpan(IASTNode region) {
|
||||
protected static IRegion getNodeSpan(IASTNode region) {
|
||||
int start = Integer.MAX_VALUE;
|
||||
int nodeLength = 0;
|
||||
IASTNodeLocation[] nodeLocations = region.getNodeLocations();
|
||||
|
|
Loading…
Add table
Reference in a new issue