// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using CSharpBinding.Parser;
using ICSharpCode.AvalonEdit.Highlighting;
using ICSharpCode.Core;
using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.CSharp.Resolver;
using ICSharpCode.NRefactory.CSharp.TypeSystem;
using ICSharpCode.NRefactory.Editor;
using ICSharpCode.NRefactory.Semantics;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.NRefactory.Utils;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Editor;
using ICSharpCode.SharpDevelop.Editor.Search;
using ICSharpCode.SharpDevelop.Gui;
using ICSharpCode.SharpDevelop.Parser;
using ICSharpCode.SharpDevelop.Project;
using ICSharpCode.SharpDevelop.Refactoring;
namespace CSharpBinding
{
///
/// C# backend implementation for 'find references'.
///
public class CSharpSymbolSearch : ISymbolSearch
{
IProject project;
ICompilation compilation;
FindReferences fr = new FindReferences();
IList searchScopes;
IList[] interestingFileNames;
int workAmount;
double workAmountInverse;
public CSharpSymbolSearch(IProject project, IEntity entity)
{
this.project = project;
searchScopes = fr.GetSearchScopes(entity);
compilation = SD.ParserService.GetCompilation(project);
interestingFileNames = new IList[searchScopes.Count];
for (int i = 0; i < searchScopes.Count; i++) {
interestingFileNames[i] = fr.GetInterestingFiles(searchScopes[i], compilation).Select(f => f.FileName).ToList();
workAmount += interestingFileNames[i].Count;
}
workAmountInverse = 1.0 / workAmount;
}
public double WorkAmount {
get { return workAmount; }
}
public Task FindReferencesAsync(SymbolSearchArgs args, Action callback)
{
if (callback == null)
throw new ArgumentNullException("callback");
var cancellationToken = args.ProgressMonitor.CancellationToken;
return Task.Run(
() => {
for (int i = 0; i < searchScopes.Count; i++) {
IFindReferenceSearchScope searchScope = searchScopes[i];
object progressLock = new object();
Parallel.ForEach(
interestingFileNames[i],
new ParallelOptions {
MaxDegreeOfParallelism = Environment.ProcessorCount,
CancellationToken = cancellationToken
},
delegate (string fileName) {
FindReferencesInFile(args, searchScope, FileName.Create(fileName), callback, cancellationToken);
lock (progressLock)
args.ProgressMonitor.Progress += workAmountInverse;
});
}
}, cancellationToken
);
}
void FindReferencesInFile(SymbolSearchArgs args, IFindReferenceSearchScope searchScope, FileName fileName, Action callback, CancellationToken cancellationToken)
{
ITextSource textSource = args.ParseableFileContentFinder.Create(fileName);
if (textSource == null)
return;
if (searchScope.SearchTerm != null) {
if (textSource.IndexOf(searchScope.SearchTerm, 0, textSource.TextLength, StringComparison.Ordinal) < 0)
return;
}
var parseInfo = SD.ParserService.Parse(fileName, textSource) as CSharpFullParseInformation;
if (parseInfo == null)
return;
ReadOnlyDocument document = null;
IHighlighter highlighter = null;
List results = new List();
fr.FindReferencesInFile(
searchScope, parseInfo.UnresolvedFile, parseInfo.SyntaxTree, compilation,
delegate (AstNode node, ResolveResult result) {
if (document == null) {
document = new ReadOnlyDocument(textSource, fileName);
highlighter = SD.EditorControlService.CreateHighlighter(document);
}
Identifier identifier = node.GetChildByRole(Roles.Identifier);
if (!identifier.IsNull)
node = identifier;
var region = new DomRegion(fileName, node.StartLocation, node.EndLocation);
int offset = document.GetOffset(node.StartLocation);
int length = document.GetOffset(node.EndLocation) - offset;
var builder = SearchResultsPad.CreateInlineBuilder(node.StartLocation, node.EndLocation, document, highlighter);
var defaultTextColor = highlighter != null ? highlighter.DefaultTextColor : null;
results.Add(new Reference(region, result, offset, length, builder, defaultTextColor));
}, cancellationToken);
if (results.Count > 0)
callback(new SearchedFile(fileName, results));
}
}
}