private static ImmutableDictionary <DocumentId, SyntaxTree> AddOrUpdateNewTreeToOldMap( Project newProject, Compilation newCompilation, CompilationSet oldSet, CancellationToken cancellationToken) { if (!oldSet.Compilation.TryGetValue(out var oldCompilation)) { return(ImmutableDictionary.CreateRange(GetNewTreeMap(newProject, newCompilation))); } var map = oldSet.Trees; foreach (var newTree in newCompilation.SyntaxTrees) { cancellationToken.ThrowIfCancellationRequested(); if (oldCompilation.ContainsSyntaxTree(newTree)) { continue; } var documentId = newProject.GetDocumentId(newTree); // GetDocumentId will return null for #load'ed trees. // TODO: Remove this check and add logic to fetch the #load'ed tree's // Document once https://github.com/dotnet/roslyn/issues/5260 is fixed. if (documentId == null) { Debug.Assert(newProject.Solution.Workspace.Kind == WorkspaceKind.Interactive || newProject.Solution.Workspace.Kind == WorkspaceKind.MiscellaneousFiles); continue; } map = map.SetItem(documentId, newTree); } return(map); }
private static ImmutableDictionary <DocumentId, SyntaxTree> AddOrUpdateNewTreeToOldMap( Project newProject, Compilation newCompilation, CompilationSet oldSet, CancellationToken cancellationToken) { Compilation oldCompilation; if (!oldSet.Compilation.TryGetValue(out oldCompilation)) { return(ImmutableDictionary.CreateRange(GetNewTreeMap(newProject, newCompilation))); } var map = oldSet.Trees; foreach (var newTree in newCompilation.SyntaxTrees) { cancellationToken.ThrowIfCancellationRequested(); if (oldCompilation.ContainsSyntaxTree(newTree)) { continue; } var documentId = newProject.GetDocumentId(newTree); Contract.Requires(documentId != null); map = map.SetItem(documentId, newTree); } return(map); }
private async Task UpdateVersionCacheAsync(Project project, VersionStamp version, CompilationSet primarySet, CancellationToken cancellationToken) { var versionMap = GetVersionMapFromBranch(project.Solution.Workspace, project.Solution.BranchId); if (!AlreadyHasLatestCompilationSet(versionMap, project.Id, version, out var compilationSet) || !compilationSet.Compilation.TryGetValue(out var compilation)) { var newSet = await CompilationSet.CreateAsync(project, compilationSet ?? primarySet, cancellationToken).ConfigureAwait(false); using (_gate.DisposableWrite()) { // we still don't have it or if someone has beaten us, check what we have is newer if (!versionMap.TryGetValue(project.Id, out compilationSet) || version != compilationSet.Version) { versionMap[project.Id] = newSet; } } } }
private static ImmutableDictionary <DocumentId, SyntaxTree> GetTreeMap(Project project, Compilation compilation, CompilationSet oldCompilationSet, CancellationToken cancellationToken) { // enumerable count should take a quick path since ImmutableArray implements ICollection var newTreeCount = compilation.SyntaxTrees.Count(); // TODO: all this could go away if this is maintained by project itself and one can just get the map from it. if (oldCompilationSet == null || Math.Abs(oldCompilationSet.Trees.Count - newTreeCount) > RebuildThreshold) { return(ImmutableDictionary.CreateRange(GetNewTreeMap(project, compilation))); } var map = AddOrUpdateNewTreeToOldMap(project, compilation, oldCompilationSet, cancellationToken); // check simple case. most of typing case should hit this. // number of items in the map is same as number of new trees and old compilation doesn't have // more trees than current one if (map.Count == newTreeCount && oldCompilationSet.Trees.Count <= newTreeCount) { return(map); } // a bit more expensive case where there is a document in oldCompilationSet that doesn't exist in new compilation return(RemoveOldTreeFromMap(compilation, oldCompilationSet.Trees, map, cancellationToken)); }
public static async Task <CompilationSet> CreateAsync(Project project, CompilationSet oldCompilationSet, CancellationToken cancellationToken) { var compilation = await project.GetCompilationAsync(cancellationToken).ConfigureAwait(false); var version = await project.GetDependentSemanticVersionAsync(cancellationToken).ConfigureAwait(false); var map = GetTreeMap(project, compilation, oldCompilationSet, cancellationToken); ValidateTreeMap(map, project, compilation); return(new CompilationSet(version, GetCompilation(project, compilation), map)); }
private bool AlreadyHasLatestCompilationSet( Dictionary <ProjectId, CompilationSet> versionMap, ProjectId projectId, VersionStamp version, out CompilationSet compilationSet) { using (gate.DisposableRead()) { // we still don't have it or if someone has beaten us, check what we have is newer return(versionMap.TryGetValue(projectId, out compilationSet) && version == compilationSet.Version); } }
private static ImmutableDictionary<DocumentId, SyntaxTree> AddOrUpdateNewTreeToOldMap( Project newProject, Compilation newCompilation, CompilationSet oldSet, CancellationToken cancellationToken) { Compilation oldCompilation; if (!oldSet.Compilation.TryGetValue(out oldCompilation)) { return ImmutableDictionary.CreateRange(GetNewTreeMap(newProject, newCompilation)); } var map = oldSet.Trees; foreach (var newTree in newCompilation.SyntaxTrees) { cancellationToken.ThrowIfCancellationRequested(); if (oldCompilation.ContainsSyntaxTree(newTree)) { continue; } var documentId = newProject.GetDocumentId(newTree); Contract.Requires(documentId != null); map = map.SetItem(documentId, newTree); } return map; }
private static ImmutableDictionary<DocumentId, SyntaxTree> GetTreeMap(Project project, Compilation compilation, CompilationSet oldCompilationSet, CancellationToken cancellationToken) { // enumerable count should take a quick path since ImmutableArray implements ICollection var newTreeCount = compilation.SyntaxTrees.Count(); // TODO: all this could go away if this is maintained by project itself and one can just get the map from it. if (oldCompilationSet == null || Math.Abs(oldCompilationSet.Trees.Count - newTreeCount) > RebuildThreshold) { return ImmutableDictionary.CreateRange(GetNewTreeMap(project, compilation)); } var map = AddOrUpdateNewTreeToOldMap(project, compilation, oldCompilationSet, cancellationToken); // check simple case. most of typing case should hit this. // number of items in the map is same as number of new trees and old compilation doesn't have // more trees than current one if (map.Count == newTreeCount && oldCompilationSet.Trees.Count <= newTreeCount) { return map; } // a bit more expensive case where there is a document in oldCompilationSet that doesn't exist in new compilation return RemoveOldTreeFromMap(compilation, oldCompilationSet.Trees, map, cancellationToken); }
public static async Task<CompilationSet> CreateAsync(Project project, CompilationSet oldCompilationSet, CancellationToken cancellationToken) { var compilation = await project.GetCompilationAsync(cancellationToken).ConfigureAwait(false); var version = await project.GetDependentSemanticVersionAsync(cancellationToken).ConfigureAwait(false); var map = GetTreeMap(project, compilation, oldCompilationSet, cancellationToken); ValidateTreeMap(map, project, compilation); return new CompilationSet(version, GetCompilation(project, compilation), map); }
private bool AlreadyHasLatestCompilationSet( Dictionary<ProjectId, CompilationSet> versionMap, ProjectId projectId, VersionStamp version, out CompilationSet compilationSet) { using (gate.DisposableRead()) { // we still don't have it or if someone has beaten us, check what we have is newer return versionMap.TryGetValue(projectId, out compilationSet) && version == compilationSet.Version; } }
private async Task UpdateVersionCacheAsync(Project project, VersionStamp version, CompilationSet primarySet, CancellationToken cancellationToken) { var versionMap = GetVersionMapFromBranch(project.Solution.Workspace, project.Solution.BranchId); CompilationSet compilationSet; Compilation compilation; if (!AlreadyHasLatestCompilationSet(versionMap, project.Id, version, out compilationSet) || !compilationSet.Compilation.TryGetValue(out compilation)) { var newSet = await CompilationSet.CreateAsync(project, compilationSet ?? primarySet, cancellationToken).ConfigureAwait(false); using (gate.DisposableWrite()) { // we still don't have it or if someone has beaten us, check what we have is newer if (!versionMap.TryGetValue(project.Id, out compilationSet) || version != compilationSet.Version) { versionMap[project.Id] = newSet; } } } }
private static ImmutableDictionary<DocumentId, SyntaxTree> AddOrUpdateNewTreeToOldMap( Project newProject, Compilation newCompilation, CompilationSet oldSet, CancellationToken cancellationToken) { if (!oldSet.Compilation.TryGetValue(out var oldCompilation)) { return ImmutableDictionary.CreateRange(GetNewTreeMap(newProject, newCompilation)); } var map = oldSet.Trees; foreach (var newTree in newCompilation.SyntaxTrees) { cancellationToken.ThrowIfCancellationRequested(); if (oldCompilation.ContainsSyntaxTree(newTree)) { continue; } var documentId = newProject.GetDocumentId(newTree); // GetDocumentId will return null for #load'ed trees. // TODO: Remove this check and add logic to fetch the #load'ed tree's // Document once https://github.com/dotnet/roslyn/issues/5260 is fixed. if (documentId == null) { Debug.Assert(newProject.Solution.Workspace.Kind == "Interactive"); continue; } map = map.SetItem(documentId, newTree); } return map; }