1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-08-01 13:25:45 +02:00

Bug 369333 - Implement method requires files to be saved,

and other assorted refactoring fixes.
This commit is contained in:
Sergey Prigogin 2012-02-24 16:30:37 -08:00
parent 0ecc12f363
commit fb9f6f5b59
16 changed files with 206 additions and 90 deletions

View file

@ -19,7 +19,7 @@ import org.eclipse.cdt.ui.CUIPlugin;
public class ExtractFunctionWizard extends RefactoringWizard {
public ExtractFunctionWizard(ExtractFunctionRefactoring refactoring) {
super(refactoring, DIALOG_BASED_USER_INTERFACE | PREVIEW_EXPAND_FIRST_NODE);
setDefaultPageTitle(Messages.ExtractFunctionWizard_extract_function);
setDefaultPageTitle(Messages.ExtractFunctionRefactoring_ExtractFunction);
setDialogSettings(CUIPlugin.getDefault().getDialogSettings());
}

View file

@ -15,7 +15,6 @@ package org.eclipse.cdt.internal.ui.refactoring.extractfunction;
import org.eclipse.osgi.util.NLS;
public final class Messages extends NLS {
public static String ExtractFunctionWizard_extract_function;
public static String ExtractFunctionRefactoring_ExtractFunction;
public static String ExtractFunctionRefactoring_NoStmtSelected;
public static String ExtractFunctionRefactoring_TooManySelected;

View file

@ -10,7 +10,6 @@
# Institute for Software - initial API and implementation
# Sergey Prigogin (Google)
###############################################################################
ExtractFunctionWizard_extract_function=Extract Function
ExtractFunctionRefactoring_ExtractFunction=Extract Function
ExtractFunctionRefactoring_NoStmtSelected=No statement selected
ExtractFunctionRefactoring_TooManySelected=Too many declarations in selection.

View file

@ -41,7 +41,7 @@ public class GenerateGettersAndSettersRefactoringRunner extends RefactoringRunne
GenerateGettersAndSettersRefactoring refactoring =
new GenerateGettersAndSettersRefactoring(element, selection, project);
RefactoringWizard wizard =
new GenerateGettersAndSettersRefactoringWizard(refactoring);
new GenerateGettersAndSettersWizard(refactoring);
run(wizard, refactoring, RefactoringSaveHelper.SAVE_REFACTORING);
}
}

View file

@ -17,10 +17,11 @@ import org.eclipse.ltk.ui.refactoring.UserInputWizardPage;
/**
* @author Thomas Corbat
*/
public class GenerateGettersAndSettersRefactoringWizard extends RefactoringWizard {
public GenerateGettersAndSettersRefactoringWizard(
public class GenerateGettersAndSettersWizard extends RefactoringWizard {
public GenerateGettersAndSettersWizard(
GenerateGettersAndSettersRefactoring refactoring) {
super(refactoring, WIZARD_BASED_USER_INTERFACE);
super(refactoring, DIALOG_BASED_USER_INTERFACE | PREVIEW_EXPAND_FIRST_NODE);
setDefaultPageTitle(Messages.GenerateGettersAndSettersInputPage_Name);
}
@Override

View file

@ -13,7 +13,7 @@ GenerateGettersAndSettersInputPage_DeselectAll=Deselect All
GenerateGettersAndSettersInputPage_Header=Select getters and setters to create:
GenerateGettersAndSettersInputPage_LinkDescription=The names of getters and setters may be configured on the <a>Name Style</a> preference page.
GenerateGettersAndSettersInputPage_LinkTooltip=Show the name style preferences.
GenerateGettersAndSettersInputPage_Name=Generate getters and setters
GenerateGettersAndSettersInputPage_Name=Generate Getters and Setters
GenerateGettersAndSettersInputPage_SeparateDefinition=Definition separate from declaration
GenerateGettersAndSettersInputPage_SelectAll=Select All
GenerateGettersAndSettersInputPage_SelectGetters=Select Getters

View file

@ -7,7 +7,7 @@
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Institute for Software (IFS)- initial API and implementation
* Institute for Software (IFS)- initial API and implementation
******************************************************************************/
package org.eclipse.cdt.internal.ui.refactoring.implementmethod;
@ -27,36 +27,27 @@ import org.eclipse.ui.dialogs.ContainerCheckedTreeViewer;
/**
* @author Emanuel Graf IFS
*
*/
public class ImplementMethodInputPage extends UserInputWizardPage{
public class ImplementMethodInputPage extends UserInputWizardPage {
private ImplementMethodData data;
private ImplementMethodRefactoringWizard wizard;
private ContainerCheckedTreeViewer tree;
public ImplementMethodInputPage(ImplementMethodData data, ImplementMethodRefactoringWizard implementMethodRefactoringWizard) {
public ImplementMethodInputPage(ImplementMethodData data, ImplementMethodWizard implementMethodRefactoringWizard) {
super(Messages.ImplementMethodInputPage_PageTitle);
this.setData(data);
wizard = implementMethodRefactoringWizard;
}
@Override
public boolean canFlipToNextPage() {
if(data.needParameterInput()) {
if (data.needParameterInput()) {
return super.canFlipToNextPage();
}else {//getNextPage call is too expensive in this case.
} else { // getNextPage call is too expensive in this case.
return isPageComplete();
}
}
@Override
public void createControl(Composite parent) {
setTitle(Messages.ImplementMethodInputPage_PageTitle);
setMessage(Messages.ImplementMethodInputPage_Header);
@ -120,7 +111,6 @@ public class ImplementMethodInputPage extends UserInputWizardPage{
tree.getTree().setLayoutData(new GridData(GridData.FILL_BOTH));
tree.addCheckStateListener(new ICheckStateListener() {
@Override
public void checkStateChanged(CheckStateChangedEvent event) {
MethodToImplementConfig config = ((MethodToImplementConfig)event.getElement());
@ -131,18 +121,22 @@ public class ImplementMethodInputPage extends UserInputWizardPage{
for (MethodToImplementConfig config : data.getMethodsToImplement()) {
tree.setChecked(config, config.isChecked());
}
}
@Override
public IWizardPage getNextPage() {
if(data.needParameterInput()) {
return wizard.getPageForConfig(data.getFirstConfigNeedingParameterNames());
}else {
if (data.needParameterInput()) {
return getWizard().getPageForConfig(data.getFirstConfigNeedingParameterNames());
} else {
return computeSuccessorPage();
}
}
@Override
public ImplementMethodWizard getWizard() {
return (ImplementMethodWizard) super.getWizard();
}
public void setData(ImplementMethodData data) {
this.data = data;
}
@ -152,11 +146,10 @@ public class ImplementMethodInputPage extends UserInputWizardPage{
}
private void checkPage() {
if(data.getMethodsToImplement().size() > 0) {
if (data.getMethodsToImplement().size() > 0) {
setPageComplete(true);
}else {
} else {
setPageComplete(false);
}
}
}

View file

@ -52,8 +52,6 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunction;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPNodeFactory;
import org.eclipse.cdt.core.dom.rewrite.ASTRewrite;
import org.eclipse.cdt.core.index.IIndex;
import org.eclipse.cdt.core.index.IIndexName;
import org.eclipse.cdt.core.model.ICElement;
import org.eclipse.cdt.core.model.ICProject;
import org.eclipse.cdt.ui.CUIPlugin;
@ -63,6 +61,7 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor;
import org.eclipse.cdt.internal.ui.refactoring.CRefactoring;
import org.eclipse.cdt.internal.ui.refactoring.ModificationCollector;
import org.eclipse.cdt.internal.ui.refactoring.utils.Checks;
import org.eclipse.cdt.internal.ui.refactoring.utils.DefinitionFinder;
import org.eclipse.cdt.internal.ui.refactoring.utils.NameHelper;
import org.eclipse.cdt.internal.ui.refactoring.utils.NodeHelper;
import org.eclipse.cdt.internal.ui.refactoring.utils.SelectionHelper;
@ -120,7 +119,8 @@ public class ImplementMethodRefactoring extends CRefactoring {
private List<IASTSimpleDeclaration> findUnimplementedMethodDeclarations(IProgressMonitor pm)
throws OperationCanceledException, CoreException {
IASTTranslationUnit ast = getAST(tu, pm);
final SubMonitor sm = SubMonitor.convert(pm, 2);
IASTTranslationUnit ast = getAST(tu, sm.newChild(1));
final List<IASTSimpleDeclaration> list = new ArrayList<IASTSimpleDeclaration>();
ast.accept(new ASTVisitor() {
{
@ -134,7 +134,7 @@ public class ImplementMethodRefactoring extends CRefactoring {
if (NodeHelper.isMethodDeclaration(simpleDeclaration)) {
IASTDeclarator[] declarators = simpleDeclaration.getDeclarators();
IBinding binding = declarators[0].getName().resolveBinding();
if (isUnimplementedMethodBinding(binding)) {
if (isUnimplementedMethodBinding(binding, sm.newChild(0))) {
list.add(simpleDeclaration);
return ASTVisitor.PROCESS_SKIP;
}
@ -145,8 +145,8 @@ public class ImplementMethodRefactoring extends CRefactoring {
});
return list;
}
private boolean isUnimplementedMethodBinding(IBinding binding) {
private boolean isUnimplementedMethodBinding(IBinding binding, IProgressMonitor pm) {
if (binding instanceof ICPPFunction) {
if (binding instanceof ICPPMethod) {
ICPPMethod methodBinding = (ICPPMethod) binding;
@ -156,11 +156,7 @@ public class ImplementMethodRefactoring extends CRefactoring {
}
try {
IIndexName[] indexNames = getIndex().findNames(binding,
IIndex.FIND_DEFINITIONS | IIndex.SEARCH_ACROSS_LANGUAGE_BOUNDARIES);
if (indexNames.length == 0) {
return true;
}
return !DefinitionFinder.hasDefinition(binding, refactoringContext, pm);
} catch (CoreException e) {
CUIPlugin.log(e);
}

View file

@ -36,7 +36,7 @@ public class ImplementMethodRefactoringRunner extends RefactoringRunner {
public void run() {
ImplementMethodRefactoring refactoring =
new ImplementMethodRefactoring(element, selection, project);
ImplementMethodRefactoringWizard wizard = new ImplementMethodRefactoringWizard(refactoring);
ImplementMethodWizard wizard = new ImplementMethodWizard(refactoring);
run(wizard, refactoring, RefactoringSaveHelper.SAVE_REFACTORING);
}
}

View file

@ -25,14 +25,15 @@ import org.eclipse.cdt.ui.CUIPlugin;
/**
* @author Mirko Stocker
*/
public class ImplementMethodRefactoringWizard extends RefactoringWizard {
public class ImplementMethodWizard extends RefactoringWizard {
private final ImplementMethodRefactoring refactoring;
private Map<MethodToImplementConfig, ParameterNamesInputPage> pagesMap =
new HashMap<MethodToImplementConfig, ParameterNamesInputPage>();
public ImplementMethodRefactoringWizard(ImplementMethodRefactoring refactoring) {
super(refactoring, WIZARD_BASED_USER_INTERFACE);
this.refactoring = refactoring;
public ImplementMethodWizard(ImplementMethodRefactoring refactoring) {
super(refactoring, DIALOG_BASED_USER_INTERFACE | PREVIEW_EXPAND_FIRST_NODE);
setDefaultPageTitle(Messages.ImplementMethodInputPage_PageTitle);
this.refactoring = refactoring;
}
@Override

View file

@ -52,9 +52,9 @@ public class ParameterNamesInputPage extends UserInputWizardPage {
private MethodToImplementConfig config;
private TranslationUnitPreview translationUnitPreview;
private Job delayedPreviewUpdater;
private ImplementMethodRefactoringWizard wizard;
private ImplementMethodWizard wizard;
public ParameterNamesInputPage(MethodToImplementConfig config, ImplementMethodRefactoringWizard wizard) {
public ParameterNamesInputPage(MethodToImplementConfig config, ImplementMethodWizard wizard) {
super(Messages.ParameterNamesInputPage_Title);
this.config = config;
this.wizard = wizard;

View file

@ -37,7 +37,6 @@ import org.eclipse.cdt.core.model.ITranslationUnit;
import org.eclipse.cdt.core.parser.util.ArrayUtil;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor;
import org.eclipse.cdt.internal.corext.util.CModelUtil;
import org.eclipse.cdt.internal.ui.editor.ITranslationUnitEditorInput;
import org.eclipse.cdt.internal.ui.refactoring.CRefactoringContext;
@ -47,47 +46,53 @@ import org.eclipse.cdt.internal.ui.util.EditorUtility;
* Helper class for finding definitions and class member declarations
*/
public class DefinitionFinder {
/**
* Finds the definition for the given name. The definition and the original name may belong
* to a different ASTs. The search is done in the index and in the ASTs of dirty editors.
*
* @param name the name to find the definition for
* @param context the refactoring context
* @param pm the progress monitor
* @return the definition name, or {@code null} if there is no definition or if it is
* not unique.
* @throws CoreException thrown in case of errors
*/
public static IASTName getDefinition(IASTName name, CRefactoringContext context,
IProgressMonitor pm) throws CoreException {
IIndex index = context.getIndex();
if (index == null) {
return null;
}
IProgressMonitor pm) throws CoreException, OperationCanceledException {
IBinding binding = name.resolveBinding();
if (binding == null) {
return null;
}
return getDefinition(binding, context, index, pm);
return getDefinition(binding, context, pm);
}
private static IASTName getDefinition(IBinding binding, CRefactoringContext context,
IIndex index, IProgressMonitor pm) throws CoreException {
/**
* Finds the definition for the given binding. The search is done in the index and in the ASTs
* of dirty editors.
*
* @param binding the binding to find the definition for
* @param context the refactoring context
* @param pm the progress monitor
* @return the definition name, or {@code null} if there is no definition or if it is
* not unique.
* @throws CoreException thrown in case of errors
*/
public static IASTName getDefinition(IBinding binding, CRefactoringContext context,
IProgressMonitor pm) throws CoreException {
SubMonitor sm = SubMonitor.convert(pm, 10);
IIndex index = context.getIndex();
if (index == null) {
return null;
}
IIndexBinding indexBinding = index.adaptBinding(binding);
if (binding == null)
return null;
Set<String> searchedFiles = new HashSet<String>();
List<IASTName> definitions = new ArrayList<IASTName>();
// TODO(sprigogin): Check index before dirty editors.
IEditorPart[] dirtyEditors = EditorUtility.getDirtyEditors(true);
SubMonitor loopProgress = sm.newChild(3).setWorkRemaining(dirtyEditors.length);
for (IEditorPart editor : dirtyEditors) {
if (sm.isCanceled()) {
throw new OperationCanceledException();
}
IEditorInput editorInput = editor.getEditorInput();
if (editorInput instanceof ITranslationUnitEditorInput) {
ITranslationUnit tu =
CModelUtil.toWorkingCopy(((ITranslationUnitEditorInput) editorInput).getTranslationUnit());
findDefinitionsInTranslationUnit(indexBinding, tu, context, definitions, loopProgress.newChild(1));
searchedFiles.add(tu.getLocation().toOSString());
}
}
IIndexName[] definitionsFromIndex = index.findDefinitions(indexBinding);
IIndexName[] definitionsFromIndex =
index.findNames(indexBinding, IIndex.FIND_DEFINITIONS | IIndex.SEARCH_ACROSS_LANGUAGE_BOUNDARIES);
int remainingCount = definitionsFromIndex.length;
loopProgress = sm.newChild(6).setWorkRemaining(remainingCount);
SubMonitor loopProgress = sm.newChild(6).setWorkRemaining(remainingCount);
for (IIndexName name : definitionsFromIndex) {
if (sm.isCanceled()) {
throw new OperationCanceledException();
@ -96,39 +101,162 @@ public class DefinitionFinder {
name.getFile().getLocation(), null);
if (searchedFiles.add(tu.getLocation().toOSString())) {
findDefinitionsInTranslationUnit(indexBinding, tu, context, definitions, pm);
if (definitions.size() > 1)
return null;
}
loopProgress.setWorkRemaining(--remainingCount);
}
if (definitions.isEmpty()) {
// Check dirty editors in case definition has just been introduced but not saved yet.
IEditorPart[] dirtyEditors = EditorUtility.getDirtyEditors(true);
loopProgress = sm.newChild(3).setWorkRemaining(dirtyEditors.length);
for (IEditorPart editor : dirtyEditors) {
if (sm.isCanceled()) {
throw new OperationCanceledException();
}
IEditorInput editorInput = editor.getEditorInput();
if (editorInput instanceof ITranslationUnitEditorInput) {
ITranslationUnit tu = ((ITranslationUnitEditorInput) editorInput).getTranslationUnit();
if (searchedFiles.add(tu.getLocation().toOSString())) {
findDefinitionsInTranslationUnit(indexBinding, tu, context, definitions, loopProgress.newChild(1));
if (definitions.size() > 1)
return null;
}
}
}
}
return definitions.size() == 1 ? definitions.get(0) : null;
}
/**
* Checks if the given binding has a definition The search is done in the index and in the ASTs
* of dirty editors.
*
* @param binding the binding to find the definition for
* @param context the refactoring context
* @param pm the progress monitor
* @return <code>true</code> if the binding has a definition.
* @throws CoreException thrown in case of errors
*/
public static boolean hasDefinition(IBinding binding, CRefactoringContext context,
IProgressMonitor pm) throws CoreException, OperationCanceledException {
SubMonitor sm = SubMonitor.convert(pm, 10);
IIndex index = context.getIndex();
if (index == null) {
return false;
}
IIndexBinding indexBinding = index.adaptBinding(binding);
if (binding == null)
return false;
Set<String> dirtyFiles = new HashSet<String>();
IEditorPart[] dirtyEditors = EditorUtility.getDirtyEditors(true);
for (IEditorPart editor : dirtyEditors) {
IEditorInput editorInput = editor.getEditorInput();
if (editorInput instanceof ITranslationUnitEditorInput) {
ITranslationUnit tu = ((ITranslationUnitEditorInput) editorInput).getTranslationUnit();
dirtyFiles.add(tu.getLocation().toOSString());
}
}
Set<String> searchedFiles = new HashSet<String>();
IIndexName[] definitionsFromIndex =
index.findNames(indexBinding, IIndex.FIND_DEFINITIONS | IIndex.SEARCH_ACROSS_LANGUAGE_BOUNDARIES);
int remainingCount = definitionsFromIndex.length;
SubMonitor loopProgress = sm.newChild(6).setWorkRemaining(remainingCount);
for (IIndexName name : definitionsFromIndex) {
if (sm.isCanceled()) {
throw new OperationCanceledException();
}
ITranslationUnit tu = CoreModelUtil.findTranslationUnitForLocation(
name.getFile().getLocation(), null);
String filename = tu.getLocation().toOSString();
if (searchedFiles.add(filename) &&
(!dirtyFiles.contains(filename) ||
hasDefinitionsInTranslationUnit(indexBinding, tu, context, loopProgress.newChild(1)))) {
return true;
}
loopProgress.setWorkRemaining(--remainingCount);
}
// Check dirty editors in case definition has just been introduced but not saved yet.
loopProgress = sm.newChild(3).setWorkRemaining(dirtyEditors.length);
for (IEditorPart editor : dirtyEditors) {
if (sm.isCanceled()) {
throw new OperationCanceledException();
}
IEditorInput editorInput = editor.getEditorInput();
if (editorInput instanceof ITranslationUnitEditorInput) {
ITranslationUnit tu = ((ITranslationUnitEditorInput) editorInput).getTranslationUnit();
String filename = tu.getLocation().toOSString();
if (searchedFiles.add(filename) &&
hasDefinitionsInTranslationUnit(indexBinding, tu, context, loopProgress.newChild(1))) {
return true;
}
}
}
return false;
}
private static void findDefinitionsInTranslationUnit(IIndexBinding binding, ITranslationUnit tu,
CRefactoringContext context, List<IASTName> definitions, IProgressMonitor pm)
throws OperationCanceledException, CoreException {
throws CoreException, OperationCanceledException {
IASTTranslationUnit ast = context.getAST(tu, pm);
ArrayUtil.addAll(definitions, ast.getDefinitionsInAST(binding));
}
private static boolean hasDefinitionsInTranslationUnit(IIndexBinding binding, ITranslationUnit tu,
CRefactoringContext context, IProgressMonitor pm)
throws CoreException, OperationCanceledException {
IASTTranslationUnit ast = context.getAST(tu, pm);
return ast.getDefinitionsInAST(binding).length != 0;
}
/**
* Finds the declaration for the given class member. The declaration and the original member
* name may belong to a different ASTs. The search is done in the index and in the ASTs of dirty
* editors.
*
* @param memberName the name of the class member to find the declaration for
* @param context the refactoring context
* @param pm the progress monitor
* @return the declaration name, or {@code null} if there is no declaration or if it is
* not unique.
* @throws CoreException thrown in case of errors
*/
public static IASTName getMemberDeclaration(IASTName memberName, CRefactoringContext context,
IProgressMonitor pm) throws CoreException {
IIndex index = context.getIndex();
if (index == null)
return null;
IProgressMonitor pm) throws CoreException, OperationCanceledException {
IBinding binding = memberName.resolveBinding();
if (!(binding instanceof ICPPMember))
return null;
return getMemberDeclaration((ICPPMember) binding, context, index, pm);
return getMemberDeclaration((ICPPMember) binding, context, pm);
}
private static IASTName getMemberDeclaration(ICPPMember member, CRefactoringContext context,
IIndex index, IProgressMonitor pm) throws CoreException {
IASTName classDefintionName = getDefinition(member.getClassOwner(), context, index, pm);
/**
* Finds the declaration for the given class member. The declaration and the original member
* name may belong to a different ASTs. The search is done in the index and in the ASTs of dirty
* editors.
*
* @param member the class member binding to find the declaration for
* @param context the refactoring context
* @param pm the progress monitor
* @return the declaration name, or {@code null} if there is no declaration or if it is
* not unique.
* @throws CoreException thrown in case of errors
*/
public static IASTName getMemberDeclaration(ICPPMember member, CRefactoringContext context,
IProgressMonitor pm) throws CoreException, OperationCanceledException {
IASTName classDefintionName = getDefinition(member.getClassOwner(), context, pm);
if (classDefintionName == null)
return null;
IASTCompositeTypeSpecifier compositeTypeSpecifier =
CPPVisitor.findAncestorWithType(classDefintionName, IASTCompositeTypeSpecifier.class);
IASTTranslationUnit ast = classDefintionName.getTranslationUnit();
IIndex index = context.getIndex();
if (index == null) {
return null;
}
IASTName[] memberDeclarationNames = ast.getDeclarationsInAST(index.adaptBinding(member));
for (IASTName name : memberDeclarationNames) {
if (name.getPropertyInParent() == IASTDeclarator.DECLARATOR_NAME) {

View file

@ -32,7 +32,6 @@ public class HideMethodAction extends RefactoringAction {
public HideMethodAction() {
super(Messages.HideMethodAction_label);
setSaveRequired(true);
}
@Override

View file

@ -36,7 +36,6 @@ public class ImplementMethodAction extends RefactoringAction {
public ImplementMethodAction() {
super(Messages.ImplementMethodAction_label);
setSaveRequired(true);
}
/**

View file

@ -26,7 +26,7 @@ import org.eclipse.cdt.internal.ui.editor.CEditor;
import org.eclipse.cdt.internal.ui.refactoring.utils.EclipseObjects;
/**
* Common base class for refactoring actions
* Common base class for refactoring actions.
* @since 5.0
* @noextend This class is not intended to be subclassed by clients.
*/
@ -38,14 +38,16 @@ public abstract class RefactoringAction extends Action {
public RefactoringAction(String label) {
super(label);
saveRequired = false;
}
/**
* Sets behavior with respect to saving dirty editors.
* @param saveRequired if <code>true</code>, dirty editors will be saved before refactoring.
*
* @deprecated saving of editors should be controlled by refactoring runner, not by the action.
* @since 5.3
*/
@Deprecated
public void setSaveRequired(boolean saveRequired) {
this.saveRequired = saveRequired;
}

View file

@ -33,7 +33,6 @@ public class ToggleFunctionAction extends RefactoringAction {
public ToggleFunctionAction() {
super(Messages.ToggleFunctionAction_label);
setSaveRequired(true);
}
@Override