Browse Source

Merge branch 'issue357_2'

pull/507/head
Andreas Weizel 11 years ago
parent
commit
2d2362d181
  1. 145
      src/AddIns/BackendBindings/CSharpBinding/Project/Src/Parser/CSharpSymbolSearch.cs
  2. 4
      src/Main/Base/Project/Src/Editor/Commands/FindReferencesCommand.cs

145
src/AddIns/BackendBindings/CSharpBinding/Project/Src/Parser/CSharpSymbolSearch.cs

@ -24,6 +24,7 @@ using System.Runtime.InteropServices;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using ICSharpCode.NRefactory.Analysis;
using CSharpBinding.Parser; using CSharpBinding.Parser;
using ICSharpCode.AvalonEdit.Document; using ICSharpCode.AvalonEdit.Document;
using ICSharpCode.AvalonEdit.Highlighting; using ICSharpCode.AvalonEdit.Highlighting;
@ -56,22 +57,44 @@ namespace CSharpBinding
FindReferences fr = new FindReferences(); FindReferences fr = new FindReferences();
IList<IFindReferenceSearchScope> searchScopes; IList<IFindReferenceSearchScope> searchScopes;
IList<string>[] interestingFileNames; IList<string>[] interestingFileNames;
Dictionary<string, IList<IFindReferenceSearchScope>> searchScopesPerFile;
int workAmount; int workAmount;
double workAmountInverse; double workAmountInverse;
public CSharpSymbolSearch(IProject project, ISymbol entity) public CSharpSymbolSearch(IProject project, ISymbol entity)
{ {
this.project = project; this.project = project;
searchScopes = fr.GetSearchScopes(entity);
compilation = SD.ParserService.GetCompilation(project); compilation = SD.ParserService.GetCompilation(project);
var relatedSymbols = GetRelatedSymbols(entity);
if ((relatedSymbols != null) && relatedSymbols.Any()) {
searchScopes = relatedSymbols.SelectMany(e => fr.GetSearchScopes(e)).ToList();
} else {
searchScopes = fr.GetSearchScopes(entity);
}
searchScopesPerFile = new Dictionary<string, IList<IFindReferenceSearchScope>>();
interestingFileNames = new IList<string>[searchScopes.Count]; interestingFileNames = new IList<string>[searchScopes.Count];
for (int i = 0; i < searchScopes.Count; i++) { for (int i = 0; i < searchScopes.Count; i++) {
interestingFileNames[i] = fr.GetInterestingFiles(searchScopes[i], compilation).Select(f => f.FileName).ToList(); var thisSearchScope = searchScopes[i];
workAmount += interestingFileNames[i].Count; var interestingFiles = fr.GetInterestingFiles(thisSearchScope, compilation).Select(f => f.FileName).ToList();
foreach (var file in interestingFiles) {
if (!searchScopesPerFile.ContainsKey(file))
searchScopesPerFile[file] = new List<IFindReferenceSearchScope>();
searchScopesPerFile[file].Add(thisSearchScope);
}
interestingFileNames[i] = interestingFiles.ToList();
workAmount += interestingFiles.Count;
} }
workAmountInverse = 1.0 / workAmount; workAmountInverse = 1.0 / workAmount;
} }
IEnumerable<ISymbol> GetRelatedSymbols(ISymbol entity)
{
TypeGraph typeGraph = new TypeGraph(new [] { compilation.MainAssembly });
var symbolCollector = new SymbolCollector();
return symbolCollector.GetRelatedSymbols(typeGraph, entity);
}
public double WorkAmount { public double WorkAmount {
get { return workAmount; } get { return workAmount; }
} }
@ -83,40 +106,38 @@ namespace CSharpBinding
var cancellationToken = args.ProgressMonitor.CancellationToken; var cancellationToken = args.ProgressMonitor.CancellationToken;
return Task.Run( return Task.Run(
() => { () => {
for (int i = 0; i < searchScopes.Count; i++) { object progressLock = new object();
IFindReferenceSearchScope searchScope = searchScopes[i]; Parallel.ForEach(
object progressLock = new object(); searchScopesPerFile.Keys,
Parallel.ForEach( new ParallelOptions {
interestingFileNames[i], MaxDegreeOfParallelism = Environment.ProcessorCount,
new ParallelOptions { CancellationToken = cancellationToken
MaxDegreeOfParallelism = Environment.ProcessorCount, },
CancellationToken = cancellationToken delegate (string fileName) {
}, try {
delegate (string fileName) { FindReferencesInFile(args, searchScopesPerFile[fileName], FileName.Create(fileName), callback, cancellationToken);
try { } catch (OperationCanceledException) {
FindReferencesInFile(args, searchScope, FileName.Create(fileName), callback, cancellationToken); throw;
} catch (OperationCanceledException) { } catch (Exception ex) {
throw; throw new ApplicationException("Error searching in file '" + fileName + "'", ex);
} catch (Exception ex) { }
throw new ApplicationException("Error searching in file '" + fileName + "'", ex); lock (progressLock)
} args.ProgressMonitor.Progress += workAmountInverse;
lock (progressLock) });
args.ProgressMonitor.Progress += workAmountInverse;
});
}
}, cancellationToken }, cancellationToken
); );
} }
void FindReferencesInFile(SymbolSearchArgs args, IFindReferenceSearchScope searchScope, FileName fileName, Action<SearchedFile> callback, CancellationToken cancellationToken) void FindReferencesInFile(SymbolSearchArgs args, IList<IFindReferenceSearchScope> searchScopeList, FileName fileName, Action<SearchedFile> callback, CancellationToken cancellationToken)
{ {
ITextSource textSource = args.ParseableFileContentFinder.Create(fileName); ITextSource textSource = args.ParseableFileContentFinder.Create(fileName);
if (textSource == null) if (textSource == null)
return; return;
if (searchScope.SearchTerm != null) { // TODO Reactivate somehow!
if (textSource.IndexOf(searchScope.SearchTerm, 0, textSource.TextLength, StringComparison.Ordinal) < 0) // if (searchScope.SearchTerm != null) {
return; // if (textSource.IndexOf(searchScope.SearchTerm, 0, textSource.TextLength, StringComparison.Ordinal) < 0)
} // return;
// }
var parseInfo = SD.ParserService.Parse(fileName, textSource) as CSharpFullParseInformation; var parseInfo = SD.ParserService.Parse(fileName, textSource) as CSharpFullParseInformation;
if (parseInfo == null) if (parseInfo == null)
@ -134,7 +155,7 @@ namespace CSharpBinding
} }
fr.FindReferencesInFile( fr.FindReferencesInFile(
searchScope, unresolvedFile, parseInfo.SyntaxTree, compilation, searchScopeList, unresolvedFile, parseInfo.SyntaxTree, compilation,
delegate (AstNode node, ResolveResult result) { delegate (AstNode node, ResolveResult result) {
if (document == null) { if (document == null) {
document = new ReadOnlyDocument(textSource, fileName); document = new ReadOnlyDocument(textSource, fileName);
@ -154,8 +175,18 @@ namespace CSharpBinding
if (highlighter != null) { if (highlighter != null) {
highlighter.Dispose(); highlighter.Dispose();
} }
if (results.Count > 0) if (results.Count > 0) {
callback(new SearchedFile(fileName, results)); // Remove overlapping results
List<SearchResultMatch> fixedResults = new List<SearchResultMatch>();
int lastEndOffset = 0;
foreach (var result in results.OrderBy(m => m.StartOffset)) {
if (result.StartOffset >= lastEndOffset) {
fixedResults.Add(result);
lastEndOffset = result.EndOffset;
}
}
callback(new SearchedFile(fileName, fixedResults));
}
} }
public Task RenameAsync(SymbolRenameArgs args, Action<PatchedFile> callback, Action<Error> errorCallback) public Task RenameAsync(SymbolRenameArgs args, Action<PatchedFile> callback, Action<Error> errorCallback)
@ -166,34 +197,32 @@ namespace CSharpBinding
return Task.Run( return Task.Run(
() => { () => {
bool isNameValid = Mono.CSharp.Tokenizer.IsValidIdentifier(args.NewName); bool isNameValid = Mono.CSharp.Tokenizer.IsValidIdentifier(args.NewName);
for (int i = 0; i < searchScopes.Count; i++) { object progressLock = new object();
IFindReferenceSearchScope searchScope = searchScopes[i]; Parallel.ForEach(
object progressLock = new object(); searchScopesPerFile.Keys,
Parallel.ForEach( new ParallelOptions {
interestingFileNames[i], MaxDegreeOfParallelism = Environment.ProcessorCount,
new ParallelOptions { CancellationToken = cancellationToken
MaxDegreeOfParallelism = Environment.ProcessorCount, },
CancellationToken = cancellationToken delegate (string fileName) {
}, RenameReferencesInFile(args, searchScopesPerFile[fileName], FileName.Create(fileName), callback, errorCallback, isNameValid, cancellationToken);
delegate (string fileName) { lock (progressLock)
RenameReferencesInFile(args, searchScope, FileName.Create(fileName), callback, errorCallback, isNameValid, cancellationToken); args.ProgressMonitor.Progress += workAmountInverse;
lock (progressLock) });
args.ProgressMonitor.Progress += workAmountInverse;
});
}
}, cancellationToken }, cancellationToken
); );
} }
void RenameReferencesInFile(SymbolRenameArgs args, IFindReferenceSearchScope searchScope, FileName fileName, Action<PatchedFile> callback, Action<Error> errorCallback, bool isNameValid, CancellationToken cancellationToken) void RenameReferencesInFile(SymbolRenameArgs args, IList<IFindReferenceSearchScope> searchScopeList, FileName fileName, Action<PatchedFile> callback, Action<Error> errorCallback, bool isNameValid, CancellationToken cancellationToken)
{ {
ITextSource textSource = args.ParseableFileContentFinder.Create(fileName); ITextSource textSource = args.ParseableFileContentFinder.Create(fileName);
if (textSource == null) if (textSource == null)
return; return;
if (searchScope.SearchTerm != null) { // TODO Reactivate somehow!
if (textSource.IndexOf(searchScope.SearchTerm, 0, textSource.TextLength, StringComparison.Ordinal) < 0) // if (searchScope.SearchTerm != null) {
return; // if (textSource.IndexOf(searchScope.SearchTerm, 0, textSource.TextLength, StringComparison.Ordinal) < 0)
} // return;
// }
var parseInfo = SD.ParserService.Parse(fileName, textSource) as CSharpFullParseInformation; var parseInfo = SD.ParserService.Parse(fileName, textSource) as CSharpFullParseInformation;
if (parseInfo == null) if (parseInfo == null)
@ -213,7 +242,7 @@ namespace CSharpBinding
CSharpAstResolver resolver = new CSharpAstResolver(compilation, parseInfo.SyntaxTree, unresolvedFile); CSharpAstResolver resolver = new CSharpAstResolver(compilation, parseInfo.SyntaxTree, unresolvedFile);
fr.RenameReferencesInFile( fr.RenameReferencesInFile(
new[] { searchScope }, args.NewName, resolver, searchScopeList, args.NewName, resolver,
delegate (RenameCallbackArguments callbackArgs) { delegate (RenameCallbackArguments callbackArgs) {
var node = callbackArgs.NodeToReplace; var node = callbackArgs.NodeToReplace;
string newCode = callbackArgs.NewNode.ToString(); string newCode = callbackArgs.NewNode.ToString();
@ -249,10 +278,16 @@ namespace CSharpBinding
} }
IDocument changedDocument = new TextDocument(document); IDocument changedDocument = new TextDocument(document);
var oldVersion = changedDocument.Version; var oldVersion = changedDocument.Version;
List<SearchResultMatch> fixedResults = new List<SearchResultMatch>();
int lastStartOffset = changedDocument.TextLength + 1;
foreach (var result in results.OrderByDescending(m => m.StartOffset)) { foreach (var result in results.OrderByDescending(m => m.StartOffset)) {
changedDocument.Replace(result.StartOffset, result.Length, result.NewCode); if (result.EndOffset <= lastStartOffset) {
changedDocument.Replace(result.StartOffset, result.Length, result.NewCode);
fixedResults.Add(result);
lastStartOffset = result.StartOffset;
}
} }
callback(new PatchedFile(fileName, results, oldVersion, changedDocument.Version)); callback(new PatchedFile(fileName, fixedResults, oldVersion, changedDocument.Version));
} }
} }
} }

4
src/Main/Base/Project/Src/Editor/Commands/FindReferencesCommand.cs

@ -53,6 +53,10 @@ namespace ICSharpCode.SharpDevelop.Editor.Commands
public override void Run(ResolveResult symbol) public override void Run(ResolveResult symbol)
{ {
var entity = GetSymbol(symbol); var entity = GetSymbol(symbol);
if ((entity is IMember) && ((entity.SymbolKind == SymbolKind.Constructor) || (entity.SymbolKind == SymbolKind.Destructor))) {
// Don't rename constructors/destructors, rename their declaring type instead
entity = ((IMember) entity).DeclaringType.GetDefinition();
}
if (entity != null) { if (entity != null) {
var project = GetProjectFromSymbol(entity); var project = GetProjectFromSymbol(entity);
if (project != null) { if (project != null) {

Loading…
Cancel
Save