private async Task ProcessAsync(ProjectToDocumentMap projectToDocumentMap)
        {
            using (Logger.LogBlock(FunctionId.FindReference_ProcessAsync, _cancellationToken))
            {
                // quick exit
                if (projectToDocumentMap.Count == 0)
                {
                    return;
                }

                // Add a progress item for each (document, symbol, finder) set that we will execute.
                // We'll mark the item as completed in "ProcessDocumentAsync".
                var totalFindCount = projectToDocumentMap.Sum(
                    kvp1 => kvp1.Value.Sum(kvp2 => kvp2.Value.Count));
                await _progressTracker.AddItemsAsync(totalFindCount).ConfigureAwait(false);

                using var _ = ArrayBuilder <Task> .GetInstance(out var tasks);

                foreach (var(project, documentMap) in projectToDocumentMap)
                {
                    tasks.Add(Task.Factory.StartNew(() => ProcessProjectAsync(project, documentMap), _cancellationToken, TaskCreationOptions.None, _scheduler).Unwrap());
                }

                await Task.WhenAll(tasks).ConfigureAwait(false);
            }
        }
        private async Task ProcessProjectAsync(
            Project project,
            ProjectToDocumentMap projectToDocumentMap)
        {
            if (!projectToDocumentMap.TryGetValue(project, out var documentMap))
            {
                // 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;
            }


            projectToDocumentMap.Remove(project);

            // Now actually process the project.
            await ProcessProjectAsync(project, documentMap).ConfigureAwait(false);
        }
        private async Task ProcessProjectsAsync(
            IEnumerable<ProjectId> connectedProjectSet,
            ProjectToDocumentMap projectToDocumentMap)
        {
            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 connectedProjectSet)
            {
                _cancellationToken.ThrowIfCancellationRequested();

                await ProcessProjectAsync(
                    projectId, projectToDocumentMap, visitedProjects).ConfigureAwait(false);
            }
        }
Exemplo n.º 4
0
        private static void ValidateProjectToDocumentMap(ProjectToDocumentMap projectToDocumentMap)
        {
            var set = new HashSet <(SymbolGroup group, ISymbol symbol, IReferenceFinder finder)>();

            foreach (var documentMap in projectToDocumentMap.Values)
            {
                foreach (var documentToFinderList in documentMap)
                {
                    set.Clear();

                    foreach (var tuple in documentToFinderList.Value)
                    {
                        Debug.Assert(set.Add(tuple));
                    }
                }
            }
        }
Exemplo n.º 5
0
        private static void ValidateProjectToDocumentMap(
            ProjectToDocumentMap projectToDocumentMap)
        {
            var set = new HashSet <(SymbolAndProjectId symbolAndProjectId, IReferenceFinder finder)>();

            foreach (var documentMap in projectToDocumentMap.Values)
            {
                foreach (var documentToFinderList in documentMap)
                {
                    set.Clear();

                    foreach (var finder in documentToFinderList.Value)
                    {
                        Contract.Requires(set.Add(finder));
                    }
                }
            }
        }
        private async Task<ProjectToDocumentMap> CreateProjectToDocumentMapAsync(ProjectMap projectMap)
        {
            using (Logger.LogBlock(FunctionId.FindReference_CreateDocumentMapAsync, _cancellationToken))
            {
                var finalMap = new ProjectToDocumentMap();

                foreach (var kvp in projectMap)
                {
                    var project = kvp.Key;
                    var projectQueue = kvp.Value;

                    var documentMap = new DocumentMap();

                    foreach (var symbolAndFinder in projectQueue)
                    {
                        _cancellationToken.ThrowIfCancellationRequested();

                        var symbolAndProjectId = symbolAndFinder.symbolAndProjectId;
                        var symbol = symbolAndProjectId.Symbol;
                        var finder = symbolAndFinder.finder;

                        var documents = await finder.DetermineDocumentsToSearchAsync(symbol, project, _documents, _cancellationToken).ConfigureAwait(false);
                        foreach (var document in documents.Distinct().WhereNotNull())
                        {
                            if (_documents == null || _documents.Contains(document))
                            {
                                documentMap.Add(document, symbolAndFinder);
                            }
                        }
                    }

                    Contract.ThrowIfTrue(documentMap.Any(kvp1 => kvp1.Value.Count != kvp1.Value.ToSet().Count));

                    if (documentMap.Count > 0)
                    {
                        finalMap.Add(project, documentMap);
                    }
                }

                return finalMap;
            }
        }
Exemplo n.º 7
0
        private async Task ProcessAsync(ProjectToDocumentMap projectToDocumentMap)
        {
            using (Logger.LogBlock(FunctionId.FindReference_ProcessAsync, _cancellationToken))
            {
                // quick exit
                if (projectToDocumentMap.Count == 0)
                {
                    return;
                }

                // 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.
                // For each connected component, we'll process the individual projects from bottom to
                // top.  i.e. we'll first process the projects with no dependencies.  Then the projects
                // that depend on those projects, and so and.  This way we always have creates the
                // dependent compilations when they're needed by later projects.  If we went the other
                // way (i.e. processed the projects with lots of project dependencies first), then we'd
                // have to create all their depedent compilations in order to get their compilation.
                // This would be very expensive and would take a lot of time before we got our first
                // result.
                var connectedProjects = _dependencyGraph.GetDependencySets(_cancellationToken);

                // Add a progress item for each (document, symbol, finder) set that we will execute.
                // We'll mark the item as completed in "ProcessDocumentAsync".
                var totalFindCount = projectToDocumentMap.Sum(
                    kvp1 => kvp1.Value.Sum(kvp2 => kvp2.Value.Count));
                await _progressTracker.AddItemsAsync(totalFindCount).ConfigureAwait(false);

                // Now, go through each connected project set and process it independently.
                foreach (var connectedProjectSet in connectedProjects)
                {
                    _cancellationToken.ThrowIfCancellationRequested();

                    await ProcessProjectsAsync(
                        connectedProjectSet, projectToDocumentMap).ConfigureAwait(false);
                }
            }
        }
        private async Task ProcessProjectAsync(
            ProjectId projectId,
            ProjectToDocumentMap projectToDocumentMap,
            HashSet<ProjectId> visitedProjects)
        {
            // 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, projectToDocumentMap, visitedProjects).ConfigureAwait(false);
                }

                await ProcessProjectAsync(project, projectToDocumentMap).ConfigureAwait(false);
            }
        }
        private async Task <ProjectToDocumentMap> CreateProjectToDocumentMapAsync(ProjectMap projectMap, CancellationToken cancellationToken)
        {
            using (Logger.LogBlock(FunctionId.FindReference_CreateDocumentMapAsync, cancellationToken))
            {
                using var _ = ArrayBuilder <Task <(ImmutableArray <Document>, ISymbol)> > .GetInstance(out var tasks);

                foreach (var(project, projectQueue) in projectMap)
                {
                    foreach (var symbol in projectQueue)
                    {
                        tasks.Add(Task.Factory.StartNew(() =>
                                                        DetermineDocumentsToSearchAsync(project, symbol, cancellationToken), cancellationToken, TaskCreationOptions.None, _scheduler).Unwrap());
                    }
                }

                var results = await Task.WhenAll(tasks).ConfigureAwait(false);

                var finalMap = new ProjectToDocumentMap();
                foreach (var(documents, symbol) in results)
                {
                    foreach (var document in documents)
                    {
                        finalMap.GetOrAdd(document.Project, s_createDocumentMap)
                        .MultiAdd(document, symbol);
                    }
                }

#if DEBUG
                foreach (var(project, documentMap) in finalMap)
                {
                    Contract.ThrowIfTrue(documentMap.Any(kvp1 => kvp1.Value.Count != kvp1.Value.ToSet().Count));
                }
#endif

                return(finalMap);
            }
        }