private async Task ProcessAsync(
            ConcurrentDictionary<Document, ConcurrentQueue<ValueTuple<SymbolAndProjectId, IReferenceFinder>>> documentMap)
        {
            using (Logger.LogBlock(FunctionId.FindReference_ProcessAsync, _cancellationToken))
            {
                // quick exit
                if (documentMap.Count == 0)
                {
                    return;
                }

                var wrapper = new ProgressWrapper(_progress, documentMap.Count);

                // Get the connected components of the dependency graph and process each individually.
                // That way once a component is done we can throw away all the memory associated with
                // it.
                var connectedProjects = _dependencyGraph.GetDependencySets(_cancellationToken);
                var projectMap = CreateProjectMap(documentMap);

                await _progressTracker.AddItemsAsync(connectedProjects.Flatten().Count()).ConfigureAwait(false);
                foreach (var projectSet in connectedProjects)
                {
                    _cancellationToken.ThrowIfCancellationRequested();

                    await ProcessProjectsAsync(projectSet, projectMap, wrapper).ConfigureAwait(false);
                }
            }
        }
        private async Task ProcessProjectsAsync(
            IEnumerable<ProjectId> projectSet,
            Dictionary<Project, Dictionary<Document, List<ValueTuple<ISymbol, IReferenceFinder>>>> projectMap,
            ProgressWrapper wrapper)
        {
            var visitedProjects = new HashSet<ProjectId>();

            // Make sure we process each project in the set.  Process each project in depth first
            // order.  That way when we process a project, the compilations for all projects that it
            // depends on will have been created already.
            foreach (var projectId in projectSet)
            {
                this.cancellationToken.ThrowIfCancellationRequested();

                await ProcessProjectAsync(projectId, projectMap, visitedProjects, wrapper).ConfigureAwait(false);
            }
        }
        private async Task ProcessDocumentQueueAsync(
            Document document,
            List<ValueTuple<ISymbol, IReferenceFinder>> documentQueue,
            ProgressWrapper wrapper)
        {
            this.progress.OnFindInDocumentStarted(document);

            SemanticModel model = null;
            try
            {
                model = await document.GetSemanticModelAsync(this.cancellationToken).ConfigureAwait(false);

                // start cache for this semantic model
                FindReferenceCache.Start(model);

#if PARALLEL
                Roslyn.Utilities.TaskExtensions.RethrowIncorrectAggregateExceptions(cancellationToken, () =>
                    {
                        documentQueue.AsParallel().WithCancellation(cancellationToken).ForAll(symbolAndFinder =>
                        {
                            var symbol = symbolAndFinder.Item1;
                            var finder = symbolAndFinder.Item2;

                            ProcessDocument(document, symbol, finder, wrapper);
                        });
                    });
#else
                foreach (var symbolAndFinder in documentQueue)
                {
                    var symbol = symbolAndFinder.Item1;
                    var finder = symbolAndFinder.Item2;

                    await ProcessDocumentAsync(document, symbol, finder, wrapper).ConfigureAwait(false);
                }
#endif
            }
            finally
            {
                FindReferenceCache.Stop(model);

                this.progress.OnFindInDocumentCompleted(document);
            }
        }
        private async Task ProcessProjectAsync(
            Project project,
            Dictionary<Project, Dictionary<Document, List<ValueTuple<ISymbol, IReferenceFinder>>>> projectMap,
            ProgressWrapper wrapper)
        {
            Dictionary<Document, List<ValueTuple<ISymbol, IReferenceFinder>>> map;
            if (!projectMap.TryGetValue(project, out map))
            {
                // No files in this project to process.  We can bail here.  We'll have cached our
                // compilation if there are any projects left to process that depend on us.
                return;
            }

            // Now actually process the project.
            await ProcessProjectAsync(project, map, wrapper).ConfigureAwait(false);

            // We've now finished working on the project.  Remove it from the set of remaining items.
            projectMap.Remove(project);
        }
 private async Task ProcessDocumentAsync(
     Document document,
     ISymbol symbol,
     IReferenceFinder finder,
     ProgressWrapper wrapper)
 {
     using (Logger.LogBlock(FunctionId.FindReference_ProcessDocumentAsync, logDocument, document, symbol, this.cancellationToken))
     {
         try
         {
             var references = await finder.FindReferencesInDocumentAsync(symbol, document, cancellationToken).ConfigureAwait(false) ?? SpecializedCollections.EmptyEnumerable<ReferenceLocation>();
             foreach (var location in references)
             {
                 HandleLocation(symbol, location);
             }
         }
         finally
         {
             wrapper.Increment();
         }
     }
 }
 private async Task ProcessDocumentAsync(
     Document document,
     SymbolAndProjectId symbolAndProjectId,
     IReferenceFinder finder,
     ProgressWrapper wrapper)
 {
     using (Logger.LogBlock(FunctionId.FindReference_ProcessDocumentAsync, s_logDocument, document, symbolAndProjectId.Symbol, _cancellationToken))
     {
         try
         {
             var references = await finder.FindReferencesInDocumentAsync(symbolAndProjectId, document, _cancellationToken).ConfigureAwait(false);
             foreach (var location in references)
             {
                 await HandleLocationAsync(symbolAndProjectId, location).ConfigureAwait(false);
             }
         }
         finally
         {
             await wrapper.IncrementAsync().ConfigureAwait(false);
         }
     }
 }
        private async Task ProcessProjectAsync(
            ProjectId projectId,
            Dictionary<Project, Dictionary<Document, List<ValueTuple<ISymbol, IReferenceFinder>>>> projectMap,
            HashSet<ProjectId> visitedProjects,
            ProgressWrapper wrapper)
        {
            // Don't visit projects more than once.  
            if (visitedProjects.Add(projectId))
            {
                var project = _solution.GetProject(projectId);

                // Visit dependencies first.  That way the compilation for a project that we depend
                // on is already ready for us when we need it.
                foreach (var dependent in project.ProjectReferences)
                {
                    _cancellationToken.ThrowIfCancellationRequested();

                    await ProcessProjectAsync(dependent.ProjectId, projectMap, visitedProjects, wrapper).ConfigureAwait(false);
                }

                await ProcessProjectAsync(project, projectMap, wrapper).ConfigureAwait(false);
            }
        }
        private async Task ProcessProjectAsync(
            Project project,
            Dictionary<Document, List<ValueTuple<ISymbol, IReferenceFinder>>> map,
            ProgressWrapper wrapper)
        {
            using (Logger.LogBlock(FunctionId.FindReference_ProcessProjectAsync, project.Name, _cancellationToken))
            {
                // make sure we hold onto compilation while we search documents belong to this project
                var compilation = await project.GetCompilationAsync(_cancellationToken).ConfigureAwait(false);

                var documentTasks = new List<Task>();
                foreach (var kvp in map)
                {
                    var document = kvp.Key;
                    var documentQueue = kvp.Value;

                    documentTasks.Add(Task.Run(async () => await ProcessDocumentQueueAsync(document, documentQueue, wrapper).ConfigureAwait(false), _cancellationToken));
                }

                await Task.WhenAll(documentTasks).ConfigureAwait(false);

                GC.KeepAlive(compilation);
            }
        }