// 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)); } } }