1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-04-29 19:45:01 +02:00

Bug 313027 - Rename refactoring is very slow on large projects

This commit is contained in:
Sergey Prigogin 2010-06-30 18:15:14 +00:00
parent 75abd66291
commit eea0205ab1
9 changed files with 165 additions and 50 deletions

View file

@ -44,6 +44,7 @@ public class CRefactory {
public static final int OPTION_IN_INACTIVE_CODE = 0x40;
public static final int OPTION_IN_CODE = 0x80;
public static final int OPTION_DO_VIRTUAL = 0x100;
public static final int OPTION_EXHAUSTIVE_FILE_SEARCH = 0x200;
public static final int ARGUMENT_UNKNOWN = 0;
public static final int ARGUMENT_LOCAL_VAR = 1;
@ -72,9 +73,9 @@ public class CRefactory {
private CRefactory() {
}
// runs the rename refactoring
// Runs the rename refactoring.
public void rename(Shell shell, ICElement arg) {
if (!IDE.saveAllEditors(new IResource[] {ResourcesPlugin.getWorkspace().getRoot()}, false)) {
if (!IDE.saveAllEditors(new IResource[] { ResourcesPlugin.getWorkspace().getRoot() }, false)) {
return;
}
CRefactoringArgument iarg= new CRefactoringArgument(arg);
@ -101,7 +102,7 @@ public class CRefactory {
if (res instanceof IFile == false) {
return;
}
if (!IDE.saveAllEditors(new IResource[] {ResourcesPlugin.getWorkspace().getRoot()}, false)) {
if (!IDE.saveAllEditors(new IResource[] { ResourcesPlugin.getWorkspace().getRoot() }, false)) {
return;
}
CRefactoringArgument iarg= new CRefactoringArgument((IFile) res, s.getOffset(), s.getLength());

View file

@ -18,7 +18,8 @@ public class CRenameGlobalProcessor extends CRenameProcessorDelegate {
public CRenameGlobalProcessor(CRenameProcessor processor, String name) {
super(processor, name);
setAvailableOptions(CRefactory.OPTION_ASK_SCOPE |
setAvailableOptions(CRefactory.OPTION_ASK_SCOPE |
CRefactory.OPTION_EXHAUSTIVE_FILE_SEARCH |
CRefactory.OPTION_IN_CODE |
CRefactory.OPTION_IN_COMMENT |
CRefactory.OPTION_IN_MACRO_DEFINITION);

View file

@ -18,6 +18,7 @@ public class CRenameIncludeProcessor extends CRenameProcessorDelegate {
public CRenameIncludeProcessor(CRenameProcessor input, String kind) {
super(input, kind);
setAvailableOptions(CRefactory.OPTION_ASK_SCOPE |
CRefactory.OPTION_EXHAUSTIVE_FILE_SEARCH |
CRefactory.OPTION_IN_COMMENT |
CRefactory.OPTION_IN_MACRO_DEFINITION);
setOptionsForcingPreview(-1);

View file

@ -24,6 +24,7 @@ public class CRenameMacroProcessor extends CRenameGlobalProcessor {
public CRenameMacroProcessor(CRenameProcessor processor, String name) {
super(processor, name);
setAvailableOptions(CRefactory.OPTION_ASK_SCOPE |
CRefactory.OPTION_EXHAUSTIVE_FILE_SEARCH |
CRefactory.OPTION_IN_CODE |
CRefactory.OPTION_IN_COMMENT |
CRefactory.OPTION_IN_PREPROCESSOR_DIRECTIVE);

View file

@ -8,6 +8,7 @@
* Contributors:
* Markus Schorn - initial API and implementation
* IBM Corporation - Bug 112366
* Sergey Prigogin (Google)
******************************************************************************/
package org.eclipse.cdt.internal.ui.refactoring.rename;
@ -16,8 +17,12 @@ import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
@ -37,12 +42,13 @@ import org.eclipse.text.edits.TextEditGroup;
import org.eclipse.cdt.core.dom.ast.IBinding;
import org.eclipse.cdt.core.index.IIndex;
import org.eclipse.cdt.core.index.IIndexFileLocation;
import org.eclipse.cdt.core.index.IIndexName;
import org.eclipse.cdt.ui.refactoring.CTextFileChange;
/**
* Abstract base for all different rename processors used by the top
* processor.
* Abstract base for all different rename processors used by the top processor.
*/
public abstract class CRenameProcessorDelegate {
private CRenameProcessor fTopProcessor;
@ -50,13 +56,14 @@ public abstract class CRenameProcessorDelegate {
protected String fProcessorBaseName;
private int fAvailableOptions=
CRefactory.OPTION_ASK_SCOPE |
CRefactory.OPTION_EXHAUSTIVE_FILE_SEARCH |
CRefactory.OPTION_IN_CODE |
CRefactory.OPTION_IN_COMMENT |
CRefactory.OPTION_IN_MACRO_DEFINITION |
CRefactory.OPTION_IN_STRING_LITERAL;
private int fOptionsForcingPreview=
CRefactory.OPTION_IN_CODE |
CRefactory.OPTION_IN_INACTIVE_CODE |
CRefactory.OPTION_IN_COMMENT |
CRefactory.OPTION_IN_MACRO_DEFINITION |
CRefactory.OPTION_IN_PREPROCESSOR_DIRECTIVE |
@ -148,6 +155,54 @@ public abstract class CRenameProcessorDelegate {
return getSelectedScope();
}
/**
* Builds an index-based file filter for the name search.
* @return A set of files containing references to the name, or <code>null</code> if
* exhaustive file search is requested.
*/
private IResource[] getFileFilter() {
if ((getSelectedOptions() & CRefactory.OPTION_EXHAUSTIVE_FILE_SEARCH) != 0) {
return null;
}
IIndex index = getIndex();
if (index == null) {
return null;
}
IBinding binding = getArgument().getBinding();
if (binding == null) {
return null;
}
Set<IIndexFileLocation> locations = new HashSet<IIndexFileLocation>();
try {
index.acquireReadLock();
IIndexName[] names = index.findNames(binding,
IIndex.FIND_ALL_OCCURRENCES | IIndex.SEARCH_ACROSS_LANGUAGE_BOUNDARIES);
for (IIndexName name : names) {
locations.add(name.getFile().getLocation());
}
} catch (InterruptedException e) {
return null;
} catch (CoreException e) {
return null;
} finally {
index.releaseReadLock();
}
ArrayList<IResource> files = new ArrayList<IResource>(locations.size());
IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
for (IIndexFileLocation location : locations) {
String fullPath= location.getFullPath();
if (fullPath != null) {
IResource file= workspaceRoot.findMember(fullPath);
if (file != null) {
files.add(file);
}
}
}
return files.toArray(new IResource[files.size()]);
}
public RefactoringStatus checkInitialConditions(IProgressMonitor pm) throws CoreException, OperationCanceledException {
return new RefactoringStatus();
}
@ -162,7 +217,7 @@ public abstract class CRenameProcessorDelegate {
fMatches= new ArrayList<CRefactoringMatch>();
TextSearchWrapper txtSearch= getManager().getTextSearch();
IStatus stat= txtSearch.searchWord(getSearchScope(), file, getSelectedWorkingSet(),
getManager().getCCppPatterns(), getArgument().getName(),
getFileFilter(), getManager().getCCppPatterns(), getArgument().getName(),
new SubProgressMonitor(monitor, 1), fMatches);
if (monitor.isCanceled()) {
throw new OperationCanceledException();
@ -228,7 +283,7 @@ public abstract class CRenameProcessorDelegate {
return result;
}
protected void analyzeTextMatches(ArrayList<CRefactoringMatch> matches, IProgressMonitor monitor, RefactoringStatus status) {
protected void analyzeTextMatches(ArrayList<CRefactoringMatch> matches, IProgressMonitor monitor, RefactoringStatus status) {
CRefactoringArgument argument= getArgument();
IBinding[] renameBindings= getBindingsToBeRenamed(status);
if (renameBindings != null && renameBindings.length > 0 &&

View file

@ -8,6 +8,7 @@
* Contributors:
* Markus Schorn - initial API and implementation
* Emanuel Graf (Institute for Software, HSR Hochschule fuer Technik)
* Sergey Prigogin (Google)
******************************************************************************/
package org.eclipse.cdt.internal.ui.refactoring.rename;
@ -54,6 +55,7 @@ public class CRenameRefactoringInputPage extends UserInputWizardPage {
private static final String KEY_INCLUDE = "include"; //$NON-NLS-1$
private static final String KEY_MACRO_DEFINITION = "macroDefinition"; //$NON-NLS-1$
private static final String KEY_PREPROCESSOR = "preprocessor"; //$NON-NLS-1$
private static final String KEY_EXHAUSTIVE_FILE_SEARCH = "exhausiveFileSearch"; //$NON-NLS-1$
private IDialogSettings fDialogSettings;
private String fSearchString;
@ -76,6 +78,7 @@ public class CRenameRefactoringInputPage extends UserInputWizardPage {
private Button fWorkingSetButton;
private Button fInMacro;
private Button fInPreprocessor;
private Button fExhausiveFileSearch;
public CRenameRefactoringInputPage() {
super(PAGE_NAME);
@ -110,15 +113,15 @@ public class CRenameRefactoringInputPage extends UserInputWizardPage {
GridData gd;
GridLayout gl;
Label label= new Label(group, SWT.NONE);
Label label= new Label(top, SWT.NONE);
label.setText(Messages.CRenameRefactoringInputPage_label_newName);
fNewName= new Text(group, SWT.BORDER);
fNewName= new Text(top, SWT.BORDER);
fNewName.setText(fSearchString);
fNewName.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
fNewName.selectAll();
if (hasOption(CRefactory.OPTION_DO_VIRTUAL)) {
fDoVirtual= new Button(group, SWT.CHECK);
fDoVirtual= new Button(top, SWT.CHECK);
fDoVirtual.setText(Messages.CRenameRefactoringInputPage_renameBaseAndDerivedMethods);
fDoVirtual.setLayoutData(gd= new GridData());
gd.horizontalSpan= 2;
@ -204,6 +207,16 @@ public class CRenameRefactoringInputPage extends UserInputWizardPage {
fInPreprocessor= new Button(group, SWT.CHECK);
fInPreprocessor.setText(Messages.CRenameRefactoringInputPage_button_preprocessor);
}
if (hasOption(CRefactory.OPTION_EXHAUSTIVE_FILE_SEARCH)) {
skipLine(top);
fExhausiveFileSearch= new Button(top, SWT.CHECK);
fExhausiveFileSearch.setText(Messages.CRenameRefactoringInputPage_button_exhaustiveFileSearch);
fExhausiveFileSearch.setLayoutData(gd= new GridData());
gd.horizontalIndent= 5;
gd.horizontalSpan= 2;
}
Dialog.applyDialogFont(top);
hookSelectionListeners();
readPreferences();
@ -270,6 +283,7 @@ public class CRenameRefactoringInputPage extends UserInputWizardPage {
registerOptionListener(fInMacro, listenOption);
registerOptionListener(fInString, listenOption);
registerOptionListener(fInPreprocessor, listenOption);
registerOptionListener(fExhausiveFileSearch, listenOption);
}
private void registerScopeListener(Button button, final int scope) {
@ -296,7 +310,7 @@ public class CRenameRefactoringInputPage extends UserInputWizardPage {
private void onSelectOption() {
int selectedOptions= computeSelectedOptions();
boolean forcePreview= fForcePreviewOptions==-1 ||
boolean forcePreview= fForcePreviewOptions == -1 ||
(selectedOptions & fForcePreviewOptions) != 0;
getRenameProcessor().setSelectedOptions(selectedOptions);
getRefactoringWizard().setForcePreviewReview(forcePreview);
@ -322,12 +336,11 @@ public class CRenameRefactoringInputPage extends UserInputWizardPage {
int choice;
try {
choice= fDialogSettings.getInt(KEY_SCOPE);
}
catch (Exception e) {
} catch (Exception e) {
choice= TextSearchWrapper.SCOPE_RELATED_PROJECTS;
}
switch(choice) {
switch (choice) {
case TextSearchWrapper.SCOPE_WORKSPACE:
fWorkspace.setSelection(true);
break;
@ -363,6 +376,7 @@ public class CRenameRefactoringInputPage extends UserInputWizardPage {
initOption(fInMacro, KEY_MACRO_DEFINITION);
initOption(fInPreprocessor, KEY_PREPROCESSOR);
initOption(fInInactiveCode, KEY_INACTIVE);
initOption(fExhausiveFileSearch, KEY_EXHAUSTIVE_FILE_SEARCH);
}
private int computeSelectedOptions() {
@ -375,6 +389,7 @@ public class CRenameRefactoringInputPage extends UserInputWizardPage {
options |= computeOption(fInPreprocessor, CRefactory.OPTION_IN_PREPROCESSOR_DIRECTIVE);
options |= computeOption(fInMacro, CRefactory.OPTION_IN_MACRO_DEFINITION);
options |= computeOption(fInInactiveCode, CRefactory.OPTION_IN_INACTIVE_CODE);
options |= computeOption(fExhausiveFileSearch, CRefactory.OPTION_EXHAUSTIVE_FILE_SEARCH);
return options;
}
@ -440,6 +455,9 @@ public class CRenameRefactoringInputPage extends UserInputWizardPage {
if (fInInactiveCode != null) {
fDialogSettings.put(KEY_INACTIVE, fInInactiveCode.getSelection());
}
if (fExhausiveFileSearch != null) {
fDialogSettings.put(KEY_EXHAUSTIVE_FILE_SEARCH, fExhausiveFileSearch.getSelection());
}
}
protected void onSelectWorkingSet() {
@ -488,7 +506,7 @@ public class CRenameRefactoringInputPage extends UserInputWizardPage {
}
protected void updateEnablement() {
boolean enable= fEnableScopeOptions==-1 ||
boolean enable= fEnableScopeOptions == -1 ||
(computeSelectedOptions() & fEnableScopeOptions) != 0;
if (fWorkspace != null) {

View file

@ -69,10 +69,11 @@ public class Messages extends NLS {
public static String CRenameRefactoringInputPage_button_includes;
public static String CRenameRefactoringInputPage_button_macroDefinitions;
public static String CRenameRefactoringInputPage_button_preprocessor;
public static String CRenameRefactoringInputPage_button_strings;
public static String CRenameRefactoringInputPage_button_exhaustiveFileSearch;
public static String CRenameRefactoringInputPage_button_singleProject;
public static String CRenameRefactoringInputPage_button_relatedProjects;
public static String CRenameRefactoringInputPage_button_workspace;
public static String CRenameRefactoringInputPage_button_strings;
public static String CRenameRefactoringInputPage_button_workingSet;
public static String CRenameRefactoringInputPage_errorInvalidIdentifier;
public static String CRenameRefactoringInputPage_label_newName;

View file

@ -65,10 +65,11 @@ CRenameRefactoringInputPage_button_inactiveCode=Inactive conditional compilation
CRenameRefactoringInputPage_button_includes=Include directives
CRenameRefactoringInputPage_button_macroDefinitions=Macro definitions
CRenameRefactoringInputPage_button_preprocessor=Other preprocessor directives
CRenameRefactoringInputPage_button_strings=String literals
CRenameRefactoringInputPage_button_exhaustiveFileSearch=Exhaustive file search (slow)
CRenameRefactoringInputPage_button_singleProject=Project
CRenameRefactoringInputPage_button_relatedProjects=Related projects
CRenameRefactoringInputPage_button_workspace=All projects
CRenameRefactoringInputPage_button_strings=String literals
CRenameRefactoringInputPage_button_workingSet=Working set:
CRenameRefactoringInputPage_errorInvalidIdentifier=''{0}'' is not a valid identifier
CRenameRefactoringInputPage_label_newName=New Name:

View file

@ -6,7 +6,8 @@
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Markus Schorn - initial API and implementation
* Markus Schorn - initial API and implementation
* Sergey Prigogin (Google)
*******************************************************************************/
package org.eclipse.cdt.internal.ui.refactoring.rename;
@ -32,6 +33,7 @@ import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceProxy;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.SubProgressMonitor;
@ -46,6 +48,7 @@ import org.eclipse.ui.PlatformUI;
import org.eclipse.cdt.core.model.CoreModel;
import org.eclipse.cdt.core.model.ICElement;
import org.eclipse.cdt.core.model.ITranslationUnit;
import org.eclipse.cdt.utils.PathUtil;
import org.eclipse.cdt.internal.formatter.scanner.SimpleScanner;
import org.eclipse.cdt.internal.formatter.scanner.Token;
@ -62,7 +65,7 @@ public class TextSearchWrapper {
public final static int SCOPE_WORKING_SET = 5;
private static class SearchScope extends TextSearchScope {
public static SearchScope newSearchScope(IWorkingSet ws) {
public static SearchScope newSearchScope(IWorkingSet ws, IResource[] filter) {
IAdaptable[] adaptables= ws.getElements();
ArrayList<IResource> resources = new ArrayList<IResource>();
for (int i = 0; i < adaptables.length; i++) {
@ -72,18 +75,40 @@ public class TextSearchWrapper {
resources.add(r);
}
}
return newSearchScope(resources.toArray(new IResource[resources.size()]), false);
return newSearchScope(resources.toArray(new IResource[resources.size()]), filter);
}
public static SearchScope newSearchScope(IResource[] resources, boolean copy) {
return new SearchScope(resources, copy);
public static SearchScope newSearchScope(IResource[] roots, IResource[] filter) {
if (filter != null) {
ArrayList<IResource> files = new ArrayList<IResource>(filter.length);
for (IResource file : filter) {
if (isInForest(file, roots)) {
files.add(file);
}
}
roots = files.toArray(new IResource[files.size()]);
}
return new SearchScope(roots);
}
private IResource[] fRootResources;
/**
* Checks is a file belongs to one of the given containers.
*/
private static boolean isInForest(IResource file, IResource[] roots) {
IPath filePath = file.getFullPath();
for (IResource root : roots) {
if (PathUtil.isPrefix(root.getFullPath(), filePath)) {
return true;
}
}
return false;
}
private IResource[] fRootResources;
private ArrayList<Matcher> fFileMatcher= new ArrayList<Matcher>();
private SearchScope(IResource[] resources, boolean copy) {
fRootResources= copy ? (IResource[]) resources.clone() : resources;
private SearchScope(IResource[] roots) {
fRootResources= roots;
}
@Override
@ -153,29 +178,30 @@ public class TextSearchWrapper {
}
}
public TextSearchWrapper() {}
public TextSearchWrapper() {
}
private TextSearchScope createSearchScope(IFile file, int scope,
String workingSetName, String[] patterns) {
private TextSearchScope createSearchScope(IFile file, int scope, String workingSetName,
IResource[] filter, String[] patterns) {
switch (scope) {
case SCOPE_WORKSPACE:
return defineSearchScope(file.getWorkspace().getRoot(), patterns);
return defineSearchScope(file.getWorkspace().getRoot(), filter, patterns);
case SCOPE_SINGLE_PROJECT:
return defineSearchScope(file.getProject(), patterns);
return defineSearchScope(file.getProject(), filter, patterns);
case SCOPE_FILE:
return defineSearchScope(file, patterns);
return defineSearchScope(file, filter, patterns);
case SCOPE_WORKING_SET: {
TextSearchScope result= defineWorkingSetAsSearchScope(workingSetName, patterns);
TextSearchScope result= defineWorkingSetAsSearchScope(workingSetName, filter, patterns);
if (result == null) {
result= defineSearchScope(file.getWorkspace().getRoot(), patterns);
result= defineSearchScope(file.getWorkspace().getRoot(), filter, patterns);
}
return result;
}
}
return defineRelatedProjectsAsSearchScope(file.getProject(), patterns);
return defineRelatedProjectsAsSearchScope(file.getProject(), filter, patterns);
}
private TextSearchScope defineRelatedProjectsAsSearchScope(IProject project, String[] patterns) {
private TextSearchScope defineRelatedProjectsAsSearchScope(IProject project, IResource[] filter, String[] patterns) {
HashSet<IProject> projects= new HashSet<IProject>();
LinkedList<IProject> workThrough= new LinkedList<IProject>();
workThrough.add(project);
@ -190,20 +216,20 @@ public class TextSearchWrapper {
}
}
}
IResource[] resources= projects.toArray(new IResource[projects.size()]);
return defineSearchScope(resources, patterns);
IResource[] roots= projects.toArray(new IResource[projects.size()]);
return defineSearchScope(roots, filter, patterns);
}
private TextSearchScope defineWorkingSetAsSearchScope(String wsName, String[] patterns) {
if (wsName == null) {
private TextSearchScope defineWorkingSetAsSearchScope(String workingSetName, IResource[] filter, String[] patterns) {
if (workingSetName == null) {
return null;
}
IWorkingSetManager wsManager= PlatformUI.getWorkbench().getWorkingSetManager();
IWorkingSet ws= wsManager.getWorkingSet(wsName);
IWorkingSet ws= wsManager.getWorkingSet(workingSetName);
if (ws == null) {
return null;
}
SearchScope result= SearchScope.newSearchScope(ws);
SearchScope result= SearchScope.newSearchScope(ws, filter);
applyFilePatterns(result, patterns);
return result;
}
@ -215,22 +241,32 @@ public class TextSearchWrapper {
}
}
private TextSearchScope defineSearchScope(IResource resource, String[] patterns) {
SearchScope result= SearchScope.newSearchScope(new IResource[] { resource }, false);
private TextSearchScope defineSearchScope(IResource root, IResource[] filter, String[] patterns) {
SearchScope result= SearchScope.newSearchScope(new IResource[] { root }, filter);
applyFilePatterns(result, patterns);
return result;
}
private TextSearchScope defineSearchScope(IResource[] resources, String[] patterns) {
SearchScope result= SearchScope.newSearchScope(resources, true);
private TextSearchScope defineSearchScope(IResource[] roots, IResource[] filter, String[] patterns) {
SearchScope result= SearchScope.newSearchScope(roots, filter);
applyFilePatterns(result, patterns);
return result;
}
/**
* @param monitor
* Searches for a given word.
*
* @param scope One of SCOPE_FILE, SCOPE_WORKSPACE, SCOPE_RELATED_PROJECTS, SCOPE_SINGLE_PROJECT,
* or SCOPE_WORKING_SET.
* @param file The file used as an anchor for the scope.
* @param workingSet The name of a working set. Ignored is scope is not SCOPE_WORKING_SET.
* @param filter If not null, further limits the scope of the search.
* @param patterns File name patterns.
* @param word The word to search for.
* @param monitor A progress monitor.
* @param target The list that gets populated with search results.
*/
public IStatus searchWord(int scope, IFile resource, String workingSet, String[] patterns,
public IStatus searchWord(int scope, IFile file, String workingSet, IResource[] filter, String[] patterns,
String word, IProgressMonitor monitor, final List<CRefactoringMatch> target) {
int startPos= target.size();
TextSearchEngine engine= TextSearchEngine.create();
@ -243,7 +279,7 @@ public class TextSearchWrapper {
Pattern pattern= Pattern.compile(searchPattern.toString());
TextSearchScope searchscope= createSearchScope(resource, scope, workingSet, patterns);
TextSearchScope searchscope= createSearchScope(file, scope, workingSet, filter, patterns);
TextSearchRequestor requestor= new TextSearchRequestor() {
@Override
public boolean acceptPatternMatch(TextSearchMatchAccess access) {