Esempio n. 1
0
        private async Task FindResultsInUnreferencedMetadataSymbolsAsync(
            ConcurrentDictionary <PortableExecutableReference, Compilation> referenceToCompilation,
            Project project, List <SymbolReference> allSymbolReferences, SymbolReferenceFinder finder, bool exact,
            CancellationToken cancellationToken)
        {
            if (allSymbolReferences.Count > 0)
            {
                // Only do this if none of the project searches produced any results.  We may have
                // a lot of metadata to search through, and it would be good to avoid that if we
                // can.
                return;
            }

            // Keep track of the references we've seen (so that we don't process them multiple times
            // across many sibling projects).  Prepopulate it with our own metadata references since
            // we know we don't need to search in that.
            var seenReferences = new HashSet <PortableExecutableReference>(comparer: this);

            seenReferences.AddAll(project.MetadataReferences.OfType <PortableExecutableReference>());

            var newReferences =
                project.Solution.Projects.Where(p => p != project)
                .SelectMany(p => p.MetadataReferences.OfType <PortableExecutableReference>())
                .Distinct(comparer: this)
                .Where(r => !seenReferences.Contains(r))
                .Where(r => !IsInPackagesDirectory(r));

            // Search all metadata references in parallel.
            var findTasks = new HashSet <Task <List <SymbolReference> > >();

            // Create another cancellation token so we can both search all projects in parallel,
            // but also stop any searches once we get enough results.
            using (var nestedTokenSource = new CancellationTokenSource())
                using (var linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(nestedTokenSource.Token, cancellationToken))
                {
                    foreach (var reference in newReferences)
                    {
                        var compilation = referenceToCompilation.GetOrAdd(reference, r => CreateCompilation(project, r));

                        // Ignore netmodules.  First, they're incredibly esoteric and barely used.
                        // Second, the SymbolFinder api doesn't even support searching them.
                        var assembly = compilation.GetAssemblyOrModuleSymbol(reference) as IAssemblySymbol;
                        if (assembly != null)
                        {
                            findTasks.Add(finder.FindInMetadataAsync(project.Solution, assembly, reference, exact, linkedTokenSource.Token));
                        }
                    }

                    await WaitForTasksAsync(allSymbolReferences, findTasks, nestedTokenSource, cancellationToken).ConfigureAwait(false);
                }
        }
        private async Task FindResultsInMetadataReferences(
            Project otherProject,
            List <SymbolReference> allSymbolReferences,
            SymbolReferenceFinder finder,
            HashSet <PortableExecutableReference> seenReferences,
            bool exact,
            CancellationToken cancellationToken)
        {
            // See if this project has a metadata reference we haven't already looked at.
            var newMetadataReferences = otherProject.MetadataReferences.OfType <PortableExecutableReference>();

            Compilation compilation = null;

            foreach (var reference in newMetadataReferences)
            {
                // Make sure we don't check the same metadata reference multiple times from
                // different projects.
                if (seenReferences.Add(reference))
                {
                    // Defer making the compilation until necessary.
                    compilation = compilation ?? await otherProject.GetCompilationAsync(cancellationToken).ConfigureAwait(false);

                    // Ignore netmodules.  First, they're incredibly esoteric and barely used.
                    // Second, the SymbolFinder api doesn't even support searching them.
                    var assembly = compilation.GetAssemblyOrModuleSymbol(reference) as IAssemblySymbol;
                    if (assembly != null)
                    {
                        AddRange(allSymbolReferences, await finder.FindInMetadataAsync(otherProject.Solution, assembly, reference, exact).ConfigureAwait(false));
                    }
                }

                if (allSymbolReferences.Count >= MaxResults)
                {
                    break;
                }
            }
        }
Esempio n. 3
0
        private async Task FindResultsInUnreferencedMetadataSymbolsAsync(
            ConcurrentDictionary <PortableExecutableReference, Compilation> referenceToCompilation,
            Project project, List <SymbolReference> allSymbolReferences, SymbolReferenceFinder finder, bool exact,
            CancellationToken cancellationToken)
        {
            if (allSymbolReferences.Count > 0)
            {
                // Only do this if none of the project searches produced any results.  We may have
                // a lot of metadata to search through, and it would be good to avoid that if we
                // can.
                return;
            }

            // Keep track of the references we've seen (so that we don't process them multiple times
            // across many sibling projects).  Prepopulate it with our own metadata references since
            // we know we don't need to search in that.
            var seenReferences = new HashSet <PortableExecutableReference>(comparer: this);

            seenReferences.AddAll(project.MetadataReferences.OfType <PortableExecutableReference>());

            var newReferences =
                project.Solution.Projects.Where(p => p != project)
                .SelectMany(p => p.MetadataReferences.OfType <PortableExecutableReference>())
                .Distinct(comparer: this)
                .Where(r => !seenReferences.Contains(r));

            // Search all metadata references in parallel.
            var findTasks = new HashSet <Task <List <SymbolReference> > >();

            foreach (var reference in newReferences)
            {
                var compilation = referenceToCompilation.GetOrAdd(reference, r => CreateCompilation(project, r));

                // Ignore netmodules.  First, they're incredibly esoteric and barely used.
                // Second, the SymbolFinder api doesn't even support searching them.
                var assembly = compilation.GetAssemblyOrModuleSymbol(reference) as IAssemblySymbol;
                if (assembly != null)
                {
                    findTasks.Add(finder.FindInMetadataAsync(project.Solution, assembly, reference, exact));
                }
            }

            while (findTasks.Count > 0)
            {
                // Keep on looping through the 'find' tasks, processing each when they finish.
                cancellationToken.ThrowIfCancellationRequested();
                var doneTask = await Task.WhenAny(findTasks).ConfigureAwait(false);

                // One of the tasks finished.  Remove it from the list we're waiting on.
                findTasks.Remove(doneTask);

                // Add its results to the final result set we're keeping.
                AddRange(allSymbolReferences, await doneTask.ConfigureAwait(false));

                // If we've got enough, no need to keep searching.
                // Note: We do not cancel the existing tasks that are still executing.  These tasks will
                // cause our indices to be created if necessary.  And that's good for future searches which
                // we will invariably perform.
                if (allSymbolReferences.Count >= MaxResults)
                {
                    break;
                }
            }
        }