From fb9f6f5b596208fd1e77bab3199037b207a8de86 Mon Sep 17 00:00:00 2001 From: Sergey Prigogin Date: Fri, 24 Feb 2012 16:30:37 -0800 Subject: [PATCH] Bug 369333 - Implement method requires files to be saved, and other assorted refactoring fixes. --- .../ExtractFunctionWizard.java | 2 +- .../refactoring/extractfunction/Messages.java | 1 - .../extractfunction/Messages.properties | 1 - ...ateGettersAndSettersRefactoringRunner.java | 2 +- ...a => GenerateGettersAndSettersWizard.java} | 7 +- .../gettersandsetters/Messages.properties | 2 +- .../ImplementMethodInputPage.java | 37 ++-- .../ImplementMethodRefactoring.java | 18 +- .../ImplementMethodRefactoringRunner.java | 2 +- ...Wizard.java => ImplementMethodWizard.java} | 9 +- .../ParameterNamesInputPage.java | 4 +- .../refactoring/utils/DefinitionFinder.java | 202 ++++++++++++++---- .../refactoring/actions/HideMethodAction.java | 1 - .../actions/ImplementMethodAction.java | 1 - .../actions/RefactoringAction.java | 6 +- .../actions/ToggleFunctionAction.java | 1 - 16 files changed, 206 insertions(+), 90 deletions(-) rename core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/gettersandsetters/{GenerateGettersAndSettersRefactoringWizard.java => GenerateGettersAndSettersWizard.java} (80%) rename core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/implementmethod/{ImplementMethodRefactoringWizard.java => ImplementMethodWizard.java} (92%) diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/extractfunction/ExtractFunctionWizard.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/extractfunction/ExtractFunctionWizard.java index 28581b23025..4fd4180fb91 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/extractfunction/ExtractFunctionWizard.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/extractfunction/ExtractFunctionWizard.java @@ -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()); } diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/extractfunction/Messages.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/extractfunction/Messages.java index 7d54c78bc01..74fa49567fb 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/extractfunction/Messages.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/extractfunction/Messages.java @@ -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; diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/extractfunction/Messages.properties b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/extractfunction/Messages.properties index 928f7845716..df9538cfaf6 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/extractfunction/Messages.properties +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/extractfunction/Messages.properties @@ -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. diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/gettersandsetters/GenerateGettersAndSettersRefactoringRunner.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/gettersandsetters/GenerateGettersAndSettersRefactoringRunner.java index cf7beb31ab0..a6f0eb33e20 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/gettersandsetters/GenerateGettersAndSettersRefactoringRunner.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/gettersandsetters/GenerateGettersAndSettersRefactoringRunner.java @@ -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); } } diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/gettersandsetters/GenerateGettersAndSettersRefactoringWizard.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/gettersandsetters/GenerateGettersAndSettersWizard.java similarity index 80% rename from core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/gettersandsetters/GenerateGettersAndSettersRefactoringWizard.java rename to core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/gettersandsetters/GenerateGettersAndSettersWizard.java index f1a81747290..8e48c62e61a 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/gettersandsetters/GenerateGettersAndSettersRefactoringWizard.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/gettersandsetters/GenerateGettersAndSettersWizard.java @@ -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 diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/gettersandsetters/Messages.properties b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/gettersandsetters/Messages.properties index f57203d0fe7..63ac02cf263 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/gettersandsetters/Messages.properties +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/gettersandsetters/Messages.properties @@ -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 Name Style 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 diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/implementmethod/ImplementMethodInputPage.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/implementmethod/ImplementMethodInputPage.java index e3b44cc2d1f..d42c06e605d 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/implementmethod/ImplementMethodInputPage.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/implementmethod/ImplementMethodInputPage.java @@ -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); } } - } diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/implementmethod/ImplementMethodRefactoring.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/implementmethod/ImplementMethodRefactoring.java index d795fbdb5ef..0fef24d8eee 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/implementmethod/ImplementMethodRefactoring.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/implementmethod/ImplementMethodRefactoring.java @@ -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 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 list = new ArrayList(); 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); } diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/implementmethod/ImplementMethodRefactoringRunner.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/implementmethod/ImplementMethodRefactoringRunner.java index 5c37e6c4393..56db8ce7df3 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/implementmethod/ImplementMethodRefactoringRunner.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/implementmethod/ImplementMethodRefactoringRunner.java @@ -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); } } diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/implementmethod/ImplementMethodRefactoringWizard.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/implementmethod/ImplementMethodWizard.java similarity index 92% rename from core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/implementmethod/ImplementMethodRefactoringWizard.java rename to core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/implementmethod/ImplementMethodWizard.java index f621bd18087..e4aa7bb4d2c 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/implementmethod/ImplementMethodRefactoringWizard.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/implementmethod/ImplementMethodWizard.java @@ -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 pagesMap = new HashMap(); - 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 diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/implementmethod/ParameterNamesInputPage.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/implementmethod/ParameterNamesInputPage.java index ee9dec64620..eeac152ad81 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/implementmethod/ParameterNamesInputPage.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/implementmethod/ParameterNamesInputPage.java @@ -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; diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/utils/DefinitionFinder.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/utils/DefinitionFinder.java index 1d774318685..66ba582788e 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/utils/DefinitionFinder.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/utils/DefinitionFinder.java @@ -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 searchedFiles = new HashSet(); List definitions = new ArrayList(); - // 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 true 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 dirtyFiles = new HashSet(); + 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 searchedFiles = new HashSet(); + 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 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) { diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/refactoring/actions/HideMethodAction.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/refactoring/actions/HideMethodAction.java index 1ce35df8df6..29110b127c3 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/refactoring/actions/HideMethodAction.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/refactoring/actions/HideMethodAction.java @@ -32,7 +32,6 @@ public class HideMethodAction extends RefactoringAction { public HideMethodAction() { super(Messages.HideMethodAction_label); - setSaveRequired(true); } @Override diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/refactoring/actions/ImplementMethodAction.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/refactoring/actions/ImplementMethodAction.java index e2512f25ff8..db66437114a 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/refactoring/actions/ImplementMethodAction.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/refactoring/actions/ImplementMethodAction.java @@ -36,7 +36,6 @@ public class ImplementMethodAction extends RefactoringAction { public ImplementMethodAction() { super(Messages.ImplementMethodAction_label); - setSaveRequired(true); } /** diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/refactoring/actions/RefactoringAction.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/refactoring/actions/RefactoringAction.java index 93f0ebd0b9b..7590da333b9 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/refactoring/actions/RefactoringAction.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/refactoring/actions/RefactoringAction.java @@ -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 true, 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; } diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/refactoring/actions/ToggleFunctionAction.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/refactoring/actions/ToggleFunctionAction.java index 15d6f610ae8..8a493e948a4 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/refactoring/actions/ToggleFunctionAction.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/refactoring/actions/ToggleFunctionAction.java @@ -33,7 +33,6 @@ public class ToggleFunctionAction extends RefactoringAction { public ToggleFunctionAction() { super(Messages.ToggleFunctionAction_label); - setSaveRequired(true); } @Override