Skip to content
This repository was archived by the owner on Oct 16, 2020. It is now read-only.

Commit 2d2362d

Browse files
committed
Merge branch 'issue357_2'
2 parents d4ca990 + d018886 commit 2d2362d

2 files changed

Lines changed: 94 additions & 55 deletions

File tree

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

Lines changed: 90 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
using System.Threading;
2525
using System.Threading.Tasks;
2626

27+
using ICSharpCode.NRefactory.Analysis;
2728
using CSharpBinding.Parser;
2829
using ICSharpCode.AvalonEdit.Document;
2930
using ICSharpCode.AvalonEdit.Highlighting;
@@ -56,22 +57,44 @@ public class CSharpSymbolSearch : ISymbolSearch
5657
FindReferences fr = new FindReferences();
5758
IList<IFindReferenceSearchScope> searchScopes;
5859
IList<string>[] interestingFileNames;
60+
Dictionary<string, IList<IFindReferenceSearchScope>> searchScopesPerFile;
5961
int workAmount;
6062
double workAmountInverse;
6163

6264
public CSharpSymbolSearch(IProject project, ISymbol entity)
6365
{
6466
this.project = project;
65-
searchScopes = fr.GetSearchScopes(entity);
6667
compilation = SD.ParserService.GetCompilation(project);
68+
var relatedSymbols = GetRelatedSymbols(entity);
69+
if ((relatedSymbols != null) && relatedSymbols.Any()) {
70+
searchScopes = relatedSymbols.SelectMany(e => fr.GetSearchScopes(e)).ToList();
71+
} else {
72+
searchScopes = fr.GetSearchScopes(entity);
73+
}
74+
75+
searchScopesPerFile = new Dictionary<string, IList<IFindReferenceSearchScope>>();
6776
interestingFileNames = new IList<string>[searchScopes.Count];
6877
for (int i = 0; i < searchScopes.Count; i++) {
69-
interestingFileNames[i] = fr.GetInterestingFiles(searchScopes[i], compilation).Select(f => f.FileName).ToList();
70-
workAmount += interestingFileNames[i].Count;
78+
var thisSearchScope = searchScopes[i];
79+
var interestingFiles = fr.GetInterestingFiles(thisSearchScope, compilation).Select(f => f.FileName).ToList();
80+
foreach (var file in interestingFiles) {
81+
if (!searchScopesPerFile.ContainsKey(file))
82+
searchScopesPerFile[file] = new List<IFindReferenceSearchScope>();
83+
searchScopesPerFile[file].Add(thisSearchScope);
84+
}
85+
interestingFileNames[i] = interestingFiles.ToList();
86+
workAmount += interestingFiles.Count;
7187
}
7288
workAmountInverse = 1.0 / workAmount;
7389
}
7490

91+
IEnumerable<ISymbol> GetRelatedSymbols(ISymbol entity)
92+
{
93+
TypeGraph typeGraph = new TypeGraph(new [] { compilation.MainAssembly });
94+
var symbolCollector = new SymbolCollector();
95+
return symbolCollector.GetRelatedSymbols(typeGraph, entity);
96+
}
97+
7598
public double WorkAmount {
7699
get { return workAmount; }
77100
}
@@ -83,40 +106,38 @@ public Task FindReferencesAsync(SymbolSearchArgs args, Action<SearchedFile> call
83106
var cancellationToken = args.ProgressMonitor.CancellationToken;
84107
return Task.Run(
85108
() => {
86-
for (int i = 0; i < searchScopes.Count; i++) {
87-
IFindReferenceSearchScope searchScope = searchScopes[i];
88-
object progressLock = new object();
89-
Parallel.ForEach(
90-
interestingFileNames[i],
91-
new ParallelOptions {
92-
MaxDegreeOfParallelism = Environment.ProcessorCount,
93-
CancellationToken = cancellationToken
94-
},
95-
delegate (string fileName) {
96-
try {
97-
FindReferencesInFile(args, searchScope, FileName.Create(fileName), callback, cancellationToken);
98-
} catch (OperationCanceledException) {
99-
throw;
100-
} catch (Exception ex) {
101-
throw new ApplicationException("Error searching in file '" + fileName + "'", ex);
102-
}
103-
lock (progressLock)
104-
args.ProgressMonitor.Progress += workAmountInverse;
105-
});
106-
}
109+
object progressLock = new object();
110+
Parallel.ForEach(
111+
searchScopesPerFile.Keys,
112+
new ParallelOptions {
113+
MaxDegreeOfParallelism = Environment.ProcessorCount,
114+
CancellationToken = cancellationToken
115+
},
116+
delegate (string fileName) {
117+
try {
118+
FindReferencesInFile(args, searchScopesPerFile[fileName], FileName.Create(fileName), callback, cancellationToken);
119+
} catch (OperationCanceledException) {
120+
throw;
121+
} catch (Exception ex) {
122+
throw new ApplicationException("Error searching in file '" + fileName + "'", ex);
123+
}
124+
lock (progressLock)
125+
args.ProgressMonitor.Progress += workAmountInverse;
126+
});
107127
}, cancellationToken
108128
);
109129
}
110130

111-
void FindReferencesInFile(SymbolSearchArgs args, IFindReferenceSearchScope searchScope, FileName fileName, Action<SearchedFile> callback, CancellationToken cancellationToken)
131+
void FindReferencesInFile(SymbolSearchArgs args, IList<IFindReferenceSearchScope> searchScopeList, FileName fileName, Action<SearchedFile> callback, CancellationToken cancellationToken)
112132
{
113133
ITextSource textSource = args.ParseableFileContentFinder.Create(fileName);
114134
if (textSource == null)
115135
return;
116-
if (searchScope.SearchTerm != null) {
117-
if (textSource.IndexOf(searchScope.SearchTerm, 0, textSource.TextLength, StringComparison.Ordinal) < 0)
118-
return;
119-
}
136+
// TODO Reactivate somehow!
137+
// if (searchScope.SearchTerm != null) {
138+
// if (textSource.IndexOf(searchScope.SearchTerm, 0, textSource.TextLength, StringComparison.Ordinal) < 0)
139+
// return;
140+
// }
120141

121142
var parseInfo = SD.ParserService.Parse(fileName, textSource) as CSharpFullParseInformation;
122143
if (parseInfo == null)
@@ -134,7 +155,7 @@ void FindReferencesInFile(SymbolSearchArgs args, IFindReferenceSearchScope searc
134155
}
135156

136157
fr.FindReferencesInFile(
137-
searchScope, unresolvedFile, parseInfo.SyntaxTree, compilation,
158+
searchScopeList, unresolvedFile, parseInfo.SyntaxTree, compilation,
138159
delegate (AstNode node, ResolveResult result) {
139160
if (document == null) {
140161
document = new ReadOnlyDocument(textSource, fileName);
@@ -154,8 +175,18 @@ void FindReferencesInFile(SymbolSearchArgs args, IFindReferenceSearchScope searc
154175
if (highlighter != null) {
155176
highlighter.Dispose();
156177
}
157-
if (results.Count > 0)
158-
callback(new SearchedFile(fileName, results));
178+
if (results.Count > 0) {
179+
// Remove overlapping results
180+
List<SearchResultMatch> fixedResults = new List<SearchResultMatch>();
181+
int lastEndOffset = 0;
182+
foreach (var result in results.OrderBy(m => m.StartOffset)) {
183+
if (result.StartOffset >= lastEndOffset) {
184+
fixedResults.Add(result);
185+
lastEndOffset = result.EndOffset;
186+
}
187+
}
188+
callback(new SearchedFile(fileName, fixedResults));
189+
}
159190
}
160191

161192
public Task RenameAsync(SymbolRenameArgs args, Action<PatchedFile> callback, Action<Error> errorCallback)
@@ -166,34 +197,32 @@ public Task RenameAsync(SymbolRenameArgs args, Action<PatchedFile> callback, Act
166197
return Task.Run(
167198
() => {
168199
bool isNameValid = Mono.CSharp.Tokenizer.IsValidIdentifier(args.NewName);
169-
for (int i = 0; i < searchScopes.Count; i++) {
170-
IFindReferenceSearchScope searchScope = searchScopes[i];
171-
object progressLock = new object();
172-
Parallel.ForEach(
173-
interestingFileNames[i],
174-
new ParallelOptions {
175-
MaxDegreeOfParallelism = Environment.ProcessorCount,
176-
CancellationToken = cancellationToken
177-
},
178-
delegate (string fileName) {
179-
RenameReferencesInFile(args, searchScope, FileName.Create(fileName), callback, errorCallback, isNameValid, cancellationToken);
180-
lock (progressLock)
181-
args.ProgressMonitor.Progress += workAmountInverse;
182-
});
183-
}
200+
object progressLock = new object();
201+
Parallel.ForEach(
202+
searchScopesPerFile.Keys,
203+
new ParallelOptions {
204+
MaxDegreeOfParallelism = Environment.ProcessorCount,
205+
CancellationToken = cancellationToken
206+
},
207+
delegate (string fileName) {
208+
RenameReferencesInFile(args, searchScopesPerFile[fileName], FileName.Create(fileName), callback, errorCallback, isNameValid, cancellationToken);
209+
lock (progressLock)
210+
args.ProgressMonitor.Progress += workAmountInverse;
211+
});
184212
}, cancellationToken
185213
);
186214
}
187215

188-
void RenameReferencesInFile(SymbolRenameArgs args, IFindReferenceSearchScope searchScope, FileName fileName, Action<PatchedFile> callback, Action<Error> errorCallback, bool isNameValid, CancellationToken cancellationToken)
216+
void RenameReferencesInFile(SymbolRenameArgs args, IList<IFindReferenceSearchScope> searchScopeList, FileName fileName, Action<PatchedFile> callback, Action<Error> errorCallback, bool isNameValid, CancellationToken cancellationToken)
189217
{
190218
ITextSource textSource = args.ParseableFileContentFinder.Create(fileName);
191219
if (textSource == null)
192220
return;
193-
if (searchScope.SearchTerm != null) {
194-
if (textSource.IndexOf(searchScope.SearchTerm, 0, textSource.TextLength, StringComparison.Ordinal) < 0)
195-
return;
196-
}
221+
// TODO Reactivate somehow!
222+
// if (searchScope.SearchTerm != null) {
223+
// if (textSource.IndexOf(searchScope.SearchTerm, 0, textSource.TextLength, StringComparison.Ordinal) < 0)
224+
// return;
225+
// }
197226

198227
var parseInfo = SD.ParserService.Parse(fileName, textSource) as CSharpFullParseInformation;
199228
if (parseInfo == null)
@@ -213,7 +242,7 @@ void RenameReferencesInFile(SymbolRenameArgs args, IFindReferenceSearchScope sea
213242
CSharpAstResolver resolver = new CSharpAstResolver(compilation, parseInfo.SyntaxTree, unresolvedFile);
214243

215244
fr.RenameReferencesInFile(
216-
new[] { searchScope }, args.NewName, resolver,
245+
searchScopeList, args.NewName, resolver,
217246
delegate (RenameCallbackArguments callbackArgs) {
218247
var node = callbackArgs.NodeToReplace;
219248
string newCode = callbackArgs.NewNode.ToString();
@@ -249,10 +278,16 @@ void RenameReferencesInFile(SymbolRenameArgs args, IFindReferenceSearchScope sea
249278
}
250279
IDocument changedDocument = new TextDocument(document);
251280
var oldVersion = changedDocument.Version;
281+
List<SearchResultMatch> fixedResults = new List<SearchResultMatch>();
282+
int lastStartOffset = changedDocument.TextLength + 1;
252283
foreach (var result in results.OrderByDescending(m => m.StartOffset)) {
253-
changedDocument.Replace(result.StartOffset, result.Length, result.NewCode);
284+
if (result.EndOffset <= lastStartOffset) {
285+
changedDocument.Replace(result.StartOffset, result.Length, result.NewCode);
286+
fixedResults.Add(result);
287+
lastStartOffset = result.StartOffset;
288+
}
254289
}
255-
callback(new PatchedFile(fileName, results, oldVersion, changedDocument.Version));
290+
callback(new PatchedFile(fileName, fixedResults, oldVersion, changedDocument.Version));
256291
}
257292
}
258293
}

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@ public class RenameSymbolCommand : ResolveResultMenuCommand
5353
public override void Run(ResolveResult symbol)
5454
{
5555
var entity = GetSymbol(symbol);
56+
if ((entity is IMember) && ((entity.SymbolKind == SymbolKind.Constructor) || (entity.SymbolKind == SymbolKind.Destructor))) {
57+
// Don't rename constructors/destructors, rename their declaring type instead
58+
entity = ((IMember) entity).DeclaringType.GetDefinition();
59+
}
5660
if (entity != null) {
5761
var project = GetProjectFromSymbol(entity);
5862
if (project != null) {

0 commit comments

Comments
 (0)