diff --git a/src/Workspaces/Core/Portable/FindSymbols/SymbolTree/SymbolTreeInfo.cs b/src/Workspaces/Core/Portable/FindSymbols/SymbolTree/SymbolTreeInfo.cs index 7284be192a654de2227732724770c58d75f8b85c..b7bd6d9184ed32cbc6fd1a4c51d421ec567674e8 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/SymbolTree/SymbolTreeInfo.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/SymbolTree/SymbolTreeInfo.cs @@ -323,7 +323,13 @@ private int BinarySearch(string name) // for non-fuzzy searches, and soon afterwards it will be able to perform // fuzzy searches as well. return Task.Run(() => LoadOrCreateSpellCheckerAsync(solution, checksum, filePath, - () => new SpellChecker(checksum, sortedNodes.Select(n => new StringSlice(concatenatedNames, n.NameSpan))))); + () => CreateSpellCheckerAsync(checksum, concatenatedNames, sortedNodes))); + } + + private static Task CreateSpellCheckerAsync(Checksum checksum, string concatenatedNames, Node[] sortedNodes) + { + return Task.FromResult(new SpellChecker( + checksum, sortedNodes.Select(n => new StringSlice(concatenatedNames, n.NameSpan)))); } private static void SortNodes( diff --git a/src/Workspaces/Core/Portable/FindSymbols/SymbolTree/SymbolTreeInfo_Metadata.cs b/src/Workspaces/Core/Portable/FindSymbols/SymbolTree/SymbolTreeInfo_Metadata.cs index 269128f5231396511ee9ab3c039f2b916bf70398..680635d5627ea2dd09fedc641df0776968266d6e 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/SymbolTree/SymbolTreeInfo_Metadata.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/SymbolTree/SymbolTreeInfo_Metadata.cs @@ -161,20 +161,20 @@ private static Metadata GetMetadataNoThrow(PortableExecutableReference reference checksum, filePath, loadOnly, - create: () => CreateMetadataSymbolTreeInfo(solution, checksum, reference, cancellationToken), + createAsync: () => CreateMetadataSymbolTreeInfoAsync(solution, checksum, reference, cancellationToken), keySuffix: "_Metadata", getPersistedChecksum: info => info.Checksum, readObject: reader => ReadSymbolTreeInfo(reader, (names, nodes) => GetSpellCheckerTask(solution, checksum, filePath, names, nodes)), cancellationToken: cancellationToken); } - private static SymbolTreeInfo CreateMetadataSymbolTreeInfo( + private static Task CreateMetadataSymbolTreeInfoAsync( Solution solution, Checksum checksum, PortableExecutableReference reference, CancellationToken cancellationToken) { var creator = new MetadataInfoCreator(solution, checksum, reference, cancellationToken); - return creator.Create(); + return Task.FromResult(creator.Create()); } private struct MetadataInfoCreator : IDisposable diff --git a/src/Workspaces/Core/Portable/FindSymbols/SymbolTree/SymbolTreeInfo_Serialization.cs b/src/Workspaces/Core/Portable/FindSymbols/SymbolTree/SymbolTreeInfo_Serialization.cs index bcc01dfa6b1f77fc6366929c38de7a83fc4daa84..d7a9b48c474f5f2f4f71aef6f6d0cb6d884eafb4 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/SymbolTree/SymbolTreeInfo_Serialization.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/SymbolTree/SymbolTreeInfo_Serialization.cs @@ -24,22 +24,17 @@ internal partial class SymbolTreeInfo : IObjectWritable /// info can't be loaded, it will be created (and persisted if possible). /// private static Task LoadOrCreateSourceSymbolTreeInfoAsync( - Solution solution, - IAssemblySymbol assembly, - Checksum checksum, - string filePath, - bool loadOnly, - CancellationToken cancellationToken) + Project project, Checksum checksum, bool loadOnly, CancellationToken cancellationToken) { return LoadOrCreateAsync( - solution, + project.Solution, checksum, - filePath, + project.FilePath, loadOnly, - create: () => CreateSourceSymbolTreeInfo(solution, checksum, assembly, filePath, cancellationToken), + createAsync: () => CreateSourceSymbolTreeInfoAsync(project, checksum, cancellationToken), keySuffix: "_Source", getPersistedChecksum: info => info.Checksum, - readObject: reader => ReadSymbolTreeInfo(reader, (names, nodes) => GetSpellCheckerTask(solution, checksum, filePath, names, nodes)), + readObject: reader => ReadSymbolTreeInfo(reader, (names, nodes) => GetSpellCheckerTask(project.Solution, checksum, project.FilePath, names, nodes)), cancellationToken: cancellationToken); } @@ -51,14 +46,14 @@ internal partial class SymbolTreeInfo : IObjectWritable Solution solution, Checksum checksum, string filePath, - Func create) + Func> createAsync) { return LoadOrCreateAsync( solution, checksum, filePath, loadOnly: false, - create: create, + createAsync: createAsync, keySuffix: "_SpellChecker", getPersistedChecksum: s => s.Checksum, readObject: SpellChecker.ReadFrom, @@ -74,7 +69,7 @@ internal partial class SymbolTreeInfo : IObjectWritable Checksum checksum, string filePath, bool loadOnly, - Func create, + Func> createAsync, string keySuffix, Func getPersistedChecksum, Func readObject, @@ -82,7 +77,7 @@ internal partial class SymbolTreeInfo : IObjectWritable { if (checksum == null) { - return loadOnly ? null : create(); + return loadOnly ? null : await createAsync().ConfigureAwait(false); } // Ok, we can use persistence. First try to load from the persistence service. @@ -120,7 +115,7 @@ internal partial class SymbolTreeInfo : IObjectWritable } // Now, try to create a new instance and write it to the persistence service. - result = create(); + result = await createAsync().ConfigureAwait(false); if (result != null) { using (var stream = SerializableBytes.CreateWritableStream()) diff --git a/src/Workspaces/Core/Portable/FindSymbols/SymbolTree/SymbolTreeInfo_Source.cs b/src/Workspaces/Core/Portable/FindSymbols/SymbolTree/SymbolTreeInfo_Source.cs index 3993bef464d00004da9881b748ad305030abd645..ef70350e1803e9278edbf4ee0a45496a908f2025 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/SymbolTree/SymbolTreeInfo_Source.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/SymbolTree/SymbolTreeInfo_Source.cs @@ -28,14 +28,11 @@ private static void FreeSymbolMap(MultiDictionary symbolMap) s_symbolMapPool.Free(symbolMap); } - public static async Task GetInfoForSourceAssemblyAsync( + public static Task GetInfoForSourceAssemblyAsync( Project project, Checksum checksum, CancellationToken cancellationToken) { - var compilation = await project.GetCompilationAsync(cancellationToken).ConfigureAwait(false); - - return await LoadOrCreateSourceSymbolTreeInfoAsync( - project.Solution, compilation.Assembly, checksum, project.FilePath, - loadOnly: false, cancellationToken: cancellationToken).ConfigureAwait(false); + return LoadOrCreateSourceSymbolTreeInfoAsync( + project, checksum, loadOnly: false, cancellationToken: cancellationToken); } public static async Task GetSourceSymbolsChecksumAsync(Project project, CancellationToken cancellationToken) @@ -49,7 +46,9 @@ public static async Task GetSourceSymbolsChecksumAsync(Project project var serializer = new Serializer(project.Solution.Workspace); var projectStateChecksums = await project.State.GetStateChecksumsAsync(cancellationToken).ConfigureAwait(false); - var textChecksumsTasks = project.Documents.Select(async d => + // Order the documents by FilePath. Default ordering in the RemoteWorkspace is + // to be ordered by Guid (which is not consistent across VS sessions). + var textChecksumsTasks = project.Documents.OrderBy(d => d.FilePath).Select(async d => { var documentStateChecksum = await d.State.GetStateChecksumsAsync(cancellationToken).ConfigureAwait(false); return documentStateChecksum.Text; @@ -75,10 +74,11 @@ public static async Task GetSourceSymbolsChecksumAsync(Project project } } - internal static SymbolTreeInfo CreateSourceSymbolTreeInfo( - Solution solution, Checksum checksum, IAssemblySymbol assembly, - string filePath, CancellationToken cancellationToken) + internal static async Task CreateSourceSymbolTreeInfoAsync( + Project project, Checksum checksum, CancellationToken cancellationToken) { + var compilation = await project.GetCompilationAsync(cancellationToken).ConfigureAwait(false); + var assembly = compilation.Assembly; if (assembly == null) { return null; @@ -90,7 +90,7 @@ public static async Task GetSourceSymbolsChecksumAsync(Project project GenerateSourceNodes(assembly.GlobalNamespace, unsortedNodes, s_getMembersNoPrivate); return CreateSymbolTreeInfo( - solution, checksum, filePath, unsortedNodes.ToImmutableAndFree(), + project.Solution, checksum, project.FilePath, unsortedNodes.ToImmutableAndFree(), inheritanceMap: new OrderPreservingMultiDictionary()); } diff --git a/src/Workspaces/CoreTest/FindAllDeclarationsTests.cs b/src/Workspaces/CoreTest/FindAllDeclarationsTests.cs index 193edcce5cada9caf9d21d5b54114dd008cd02fb..af5f62459c334739d07b71d1b83b37e71f352e5b 100644 --- a/src/Workspaces/CoreTest/FindAllDeclarationsTests.cs +++ b/src/Workspaces/CoreTest/FindAllDeclarationsTests.cs @@ -537,13 +537,11 @@ public async Task FindSourceDeclarationsAsync_Solution_Func_Test_Cancellation() public async Task TestSymbolTreeInfoSerialization() { var solution = GetSolution(WorkspaceKind.SingleClass); - var compilation = await solution.Projects.First().GetCompilationAsync(); - var assembly = compilation.GetSpecialType(SpecialType.System_Byte).ContainingAssembly; - ////var assembly = compilation.Assembly; + var project = solution.Projects.First(); // create symbol tree info from assembly - var info = SymbolTreeInfo.CreateSourceSymbolTreeInfo( - solution, Checksum.Null, assembly, "", cancellationToken: CancellationToken.None); + var info = await SymbolTreeInfo.CreateSourceSymbolTreeInfoAsync( + project, Checksum.Null, cancellationToken: CancellationToken.None); using (var writerStream = new MemoryStream()) {