diff --git a/src/Features/Core/Portable/IncrementalCaches/SymbolTreeInfoIncrementalAnalyzerProvider.cs b/src/Features/Core/Portable/IncrementalCaches/SymbolTreeInfoIncrementalAnalyzerProvider.cs index 609887b7f97b53f597fab67b7637ab85bffbaa99..b17c08f6eec3c29e53e5abfc16f2eb5a4f8fadad 100644 --- a/src/Features/Core/Portable/IncrementalCaches/SymbolTreeInfoIncrementalAnalyzerProvider.cs +++ b/src/Features/Core/Portable/IncrementalCaches/SymbolTreeInfoIncrementalAnalyzerProvider.cs @@ -165,13 +165,6 @@ public override Task AnalyzeDocumentAsync(Document document, SyntaxNode bodyOpt, return SpecializedTasks.EmptyTask; } - if (bodyOpt != null) - { - // This was a method level edit. This can't change the symbol tree info - // for this project. Bail immediately. - return SpecializedTasks.EmptyTask; - } - return UpdateSymbolTreeInfoAsync(document.Project, cancellationToken); } @@ -220,10 +213,17 @@ private async Task UpdateSourceSymbolTreeInfoAsync(Project project, Cancellation private Task UpdateReferencesAync(Project project, CancellationToken cancellationToken) { - // Process all metadata references in parallel. - var tasks = project.MetadataReferences.OfType() - .Select(r => UpdateReferenceAsync(project, r, cancellationToken)) - .ToArray(); + // Process all metadata references. If it remote workspace, do this in parallel. + var tasks = new List(); + var isRemoteWorkspace = project.Solution.Workspace.Kind == WorkspaceKind.RemoteWorkspace || + project.Solution.Workspace.Kind == WorkspaceKind.RemoteTemporaryWorkspace; + + foreach (var reference in project.MetadataReferences.OfType()) + { + tasks.Add(isRemoteWorkspace + ? Task.Run(() => UpdateReferenceAsync(project, reference, cancellationToken), cancellationToken) + : UpdateReferenceAsync(project, reference, cancellationToken)); + } return Task.WhenAll(tasks); } diff --git a/src/Workspaces/Core/Portable/FindSymbols/SymbolTree/SymbolTreeInfo_Metadata.cs b/src/Workspaces/Core/Portable/FindSymbols/SymbolTree/SymbolTreeInfo_Metadata.cs index 0a43a1f7065236e8b4b6b249fd0f62b76f2d1a66..7652e27f7d7c7b5f5c6c4c82ffcb0a0881c9595c 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/SymbolTree/SymbolTreeInfo_Metadata.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/SymbolTree/SymbolTreeInfo_Metadata.cs @@ -151,9 +151,12 @@ private static Metadata GetMetadataNoThrow(PortableExecutableReference reference { // We can reuse the index for any given reference as long as it hasn't changed. // So our checksum is just the checksum for the PEReference itself. - var serializer = new Serializer(solution.Workspace); - var checksum = serializer.CreateChecksum(reference, cancellationToken); - return checksum; + return ChecksumCache.GetOrCreate(reference, _ => + { + var serializer = new Serializer(solution.Workspace); + var checksum = serializer.CreateChecksum(reference, cancellationToken); + return checksum; + }); } private static Task TryLoadOrCreateMetadataSymbolTreeInfoAsync( diff --git a/src/Workspaces/Core/Portable/FindSymbols/SymbolTree/SymbolTreeInfo_Source.cs b/src/Workspaces/Core/Portable/FindSymbols/SymbolTree/SymbolTreeInfo_Source.cs index 7e73afddfb7065d7e8a02050f1e29043f759a804..87c5e611e64993feefd12eb05e764826c9bcabea 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/SymbolTree/SymbolTreeInfo_Source.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/SymbolTree/SymbolTreeInfo_Source.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; +using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Collections; @@ -42,7 +43,22 @@ private static void FreeSymbolMap(MultiDictionary symbolMap) return result; } - public static async Task GetSourceSymbolsChecksumAsync(Project project, CancellationToken cancellationToken) + /// + /// Cache of project to the checksum for it so that we don't have to expensively recompute + /// this each time we get a project. + /// + private static ConditionalWeakTable> s_projectToSourceChecksum = + new ConditionalWeakTable>(); + + public static Task GetSourceSymbolsChecksumAsync(Project project, CancellationToken cancellationToken) + { + var lazy = s_projectToSourceChecksum.GetValue( + project, p => new AsyncLazy(c => ComputeSourceSymbolsChecksumAsync(p, c), cacheResult: true)); + + return lazy.GetValueAsync(cancellationToken); + } + + private static async Task ComputeSourceSymbolsChecksumAsync(Project project, CancellationToken cancellationToken) { // The SymbolTree for source is built from the source-symbols from the project's compilation's // assembly. Specifically, we only get the name, kind and parent/child relationship of all the