Ejemplo n.º 1
0
            /// <summary>
            /// Return all diagnostics for the given project stored in this state
            /// </summary>
            public async Task <AnalysisResult> GetAnalysisDataAsync(Project project, bool avoidLoadingData, CancellationToken cancellationToken)
            {
                // make a copy of last result.
                var lastResult = _lastResult;

                Contract.ThrowIfFalse(lastResult.ProjectId == project.Id);

                if (lastResult.IsDefault)
                {
                    return(await LoadInitialAnalysisDataAsync(project, cancellationToken).ConfigureAwait(false));
                }

                // PERF: avoid loading data if version is not right one.
                // avoid loading data flag is there as a strictly perf optimization.
                var version = await GetDiagnosticVersionAsync(project, cancellationToken).ConfigureAwait(false);

                if (avoidLoadingData && lastResult.Version != version)
                {
                    return(lastResult);
                }

                // if given project doesnt have any diagnostics, return empty.
                if (lastResult.IsEmpty)
                {
                    return(new AnalysisResult(lastResult.ProjectId, lastResult.Version));
                }

                // loading data can be cancelled any time.
                var serializer = new DiagnosticDataSerializer(_owner.AnalyzerVersion, lastResult.Version);
                var builder    = new Builder(project.Id, lastResult.Version, lastResult.DocumentIds);

                foreach (var documentId in lastResult.DocumentIds)
                {
                    cancellationToken.ThrowIfCancellationRequested();

                    var document = project.GetDocument(documentId);
                    if (document == null)
                    {
                        continue;
                    }

                    if (!await TryDeserializeDocumentAsync(serializer, document, builder, cancellationToken).ConfigureAwait(false))
                    {
                        Contract.Requires(false, "How this can happen?");
                        continue;
                    }
                }

                if (!await TryDeserializeAsync(serializer, project, project.Id, _owner.NonLocalStateName, builder.AddOthers, cancellationToken).ConfigureAwait(false))
                {
                    Contract.Requires(false, "How this can happen?");
                }

                return(builder.ToResult());
            }
Ejemplo n.º 2
0
            private async Task <bool> TryDeserializeDocumentAsync(DiagnosticDataSerializer serializer, Document document, Builder builder, CancellationToken cancellationToken)
            {
                var result = true;

                result &= await TryDeserializeAsync(serializer, document, document.Id, _owner.SyntaxStateName, s_addSyntaxLocals, builder, cancellationToken).ConfigureAwait(false);

                result &= await TryDeserializeAsync(serializer, document, document.Id, _owner.SemanticStateName, s_addSemanticLocals, builder, cancellationToken).ConfigureAwait(false);

                result &= await TryDeserializeAsync(serializer, document, document.Id, _owner.NonLocalStateName, s_addNonLocals, builder, cancellationToken).ConfigureAwait(false);

                return(result);
            }
Ejemplo n.º 3
0
            private async Task SerializeAsync(DiagnosticDataSerializer serializer, object documentOrProject, object key, string stateKey, ImmutableArray <DiagnosticData> diagnostics)
            {
                // try to serialize it
                if (await serializer.SerializeAsync(documentOrProject, stateKey, diagnostics, CancellationToken.None).ConfigureAwait(false))
                {
                    // we succeeded saving it to persistent storage. remove it from in memory cache if it exists
                    RemoveInMemoryCacheEntry(key, stateKey);
                    return;
                }

                // if serialization fail, hold it in the memory
                InMemoryStorage.Cache(_owner.Analyzer, ValueTuple.Create(key, stateKey), new CacheEntry(serializer.Version, diagnostics));
            }
            private async Task <ImmutableArray <DiagnosticData> > DeserializeAsync(DiagnosticDataSerializer serializer, object documentOrProject, object key, string stateKey, CancellationToken cancellationToken)
            {
                // check cache first
                CacheEntry entry;

                if (InMemoryStorage.TryGetValue(_owner.Analyzer, ValueTuple.Create(key, stateKey), out entry) && serializer.Version == entry.Version)
                {
                    return(entry.Diagnostics);
                }

                // try to deserialize it
                return(await serializer.DeserializeAsync(documentOrProject, stateKey, cancellationToken).ConfigureAwait(false));
            }
            private async Task <DiagnosticAnalysisResult> LoadInitialProjectAnalysisDataAsync(Project project, CancellationToken cancellationToken)
            {
                // loading data can be cancelled any time.
                var version = await GetDiagnosticVersionAsync(project, cancellationToken).ConfigureAwait(false);

                var serializer = new DiagnosticDataSerializer(_owner.AnalyzerVersion, version);
                var builder    = new Builder(project.Id, version);

                if (!await TryDeserializeAsync(serializer, project, project.Id, _owner.NonLocalStateName, s_addOthers, builder, cancellationToken).ConfigureAwait(false))
                {
                    return(new DiagnosticAnalysisResult(project.Id, VersionStamp.Default, ImmutableHashSet <DocumentId> .Empty, isEmpty: true, fromBuild: false));
                }

                return(builder.ToResult());
            }
            private async Task <DiagnosticAnalysisResult> LoadInitialProjectAnalysisDataAsync(IPersistentStorageService persistentService, Project project, CancellationToken cancellationToken)
            {
                // loading data can be cancelled any time.
                var version = await GetDiagnosticVersionAsync(project, cancellationToken).ConfigureAwait(false);

                var serializer = new DiagnosticDataSerializer(_owner.AnalyzerVersion, version);
                var builder    = new Builder(project, version);

                if (!await TryDeserializeProjectDiagnosticsAsync(persistentService, serializer, project, builder, cancellationToken).ConfigureAwait(false))
                {
                    return(DiagnosticAnalysisResult.CreateEmpty(project.Id, VersionStamp.Default));
                }

                return(builder.ToResult());
            }
            private async Task <bool> TryDeserializeAsync <T>(
                DiagnosticDataSerializer serializer,
                object documentOrProject, T key, string stateKey,
                Action <T, ImmutableArray <DiagnosticData> > add,
                CancellationToken cancellationToken) where T : class
            {
                var diagnostics = await DeserializeAsync(serializer, documentOrProject, key, stateKey, cancellationToken).ConfigureAwait(false);

                if (diagnostics.IsDefault)
                {
                    return(false);
                }

                add(key, diagnostics);
                return(true);
            }
Ejemplo n.º 8
0
            public async Task MergeAsync(ActiveFileState state, Document document)
            {
                Contract.ThrowIfFalse(state.DocumentId == document.Id);

                // merge active file state to project state
                var lastResult = _lastResult;

                var syntax   = state.GetAnalysisData(AnalysisKind.Syntax);
                var semantic = state.GetAnalysisData(AnalysisKind.Semantic);

                AnalyzerABTestLogger.LogDocumentDiagnostics(document, _owner.StateName, syntax.Items, semantic.Items);

                var project = document.Project;

                // if project didn't successfully loaded, then it is same as FSA off
                var fullAnalysis = ServiceFeatureOnOffOptions.IsClosedFileDiagnosticsEnabled(project) &&
                                   await project.HasSuccessfullyLoadedAsync(CancellationToken.None).ConfigureAwait(false);

                // keep from build flag if full analysis is off
                var fromBuild = fullAnalysis ? false : lastResult.FromBuild;

                var openFileOnlyAnalyzer = _owner.Analyzer.IsOpenFileOnly(document.Project.Solution.Workspace);

                // if it is allowed to keep project state, check versions and if they are same, bail out.
                // if full solution analysis is off or we are asked to reset document state, we always merge.
                if (fullAnalysis && !openFileOnlyAnalyzer &&
                    syntax.Version != VersionStamp.Default &&
                    syntax.Version == semantic.Version &&
                    syntax.Version == lastResult.Version)
                {
                    // all data is in sync already.
                    return;
                }

                // we have mixed versions or full analysis is off, set it to default so that it can be re-calculated next time so data can be in sync.
                var version = VersionStamp.Default;

                // serialization can't be cancelled.
                var serializer = new DiagnosticDataSerializer(_owner.AnalyzerVersion, version);

                // save active file diagnostics back to project state
                await SerializeAsync(serializer, document, document.Id, _owner.SyntaxStateName, syntax.Items).ConfigureAwait(false);
                await SerializeAsync(serializer, document, document.Id, _owner.SemanticStateName, semantic.Items).ConfigureAwait(false);

                // save last aggregated form of analysis result
                _lastResult = _lastResult.UpdateAggregatedResult(version, state.DocumentId, fromBuild);
            }
Ejemplo n.º 9
0
            private async Task <bool> TryDeserializeAsync <TKey, TArg>(
                DiagnosticDataSerializer serializer,
                object documentOrProject, TKey key, string stateKey,
                Action <TArg, TKey, ImmutableArray <DiagnosticData> > add,
                TArg arg,
                CancellationToken cancellationToken) where TKey : class
            {
                var diagnostics = await DeserializeAsync(serializer, documentOrProject, key, stateKey, cancellationToken).ConfigureAwait(false);

                if (diagnostics == null)
                {
                    return(false);
                }

                add(arg, key, diagnostics.Value);
                return(true);
            }
Ejemplo n.º 10
0
            private async Task <DiagnosticAnalysisResult> LoadInitialAnalysisDataAsync(Document document, CancellationToken cancellationToken)
            {
                // loading data can be cancelled any time.
                var project = document.Project;

                var version = await GetDiagnosticVersionAsync(project, cancellationToken).ConfigureAwait(false);

                var serializer = new DiagnosticDataSerializer(_owner.AnalyzerVersion, version);
                var builder    = new Builder(project, version);

                if (!await TryDeserializeDocumentAsync(serializer, document, builder, cancellationToken).ConfigureAwait(false))
                {
                    return(DiagnosticAnalysisResult.CreateEmpty(project.Id, VersionStamp.Default));
                }

                return(builder.ToResult());
            }
Ejemplo n.º 11
0
        public async Task SerializationTest_Document()
        {
            using (var workspace = new TestWorkspace(TestExportProvider.ExportProviderWithCSharpAndVisualBasic, workspaceKind: "DiagnosticDataSerializerTest"))
            {
                var document = workspace.CurrentSolution.AddProject("TestProject", "TestProject", LanguageNames.CSharp).AddDocument("TestDocument", "");

                var diagnostics = new[]
                {
                    new DiagnosticData(
                        "test1", "Test", "test1 message", "test1 message format",
                        DiagnosticSeverity.Info, DiagnosticSeverity.Info, false, 1,
                        ImmutableArray<string>.Empty, ImmutableDictionary<string, string>.Empty,
                        workspace, document.Project.Id, new DiagnosticDataLocation(document.Id,
                            new TextSpan(10, 20), "originalFile1", 30, 30, 40, 40, "mappedFile1", 10, 10, 20, 20)),
                    new DiagnosticData(
                        "test2", "Test", "test2 message", "test2 message format",
                        DiagnosticSeverity.Warning, DiagnosticSeverity.Warning, true, 0,
                        ImmutableArray.Create<string>("Test2"), ImmutableDictionary<string, string>.Empty.Add("propertyKey", "propertyValue"),
                        workspace, document.Project.Id, new DiagnosticDataLocation(document.Id,
                            new TextSpan(30, 40), "originalFile2", 70, 70, 80, 80, "mappedFile2", 50, 50, 60, 60), title: "test2 title", description: "test2 description", helpLink: "http://test2link"),
                    new DiagnosticData(
                        "test3", "Test", "test3 message", "test3 message format",
                        DiagnosticSeverity.Error, DiagnosticSeverity.Warning, true, 2,
                        ImmutableArray.Create<string>("Test3", "Test3_2"), ImmutableDictionary<string, string>.Empty.Add("p1Key", "p1Value").Add("p2Key", "p2Value"),
                        workspace, document.Project.Id, new DiagnosticDataLocation(document.Id,
                            new TextSpan(50, 60), "originalFile3", 110, 110, 120, 120, "mappedFile3", 90, 90, 100, 100), title: "test3 title", description: "test3 description", helpLink: "http://test3link"),
                }.ToImmutableArray();

                var utcTime = DateTime.UtcNow;
                var analyzerVersion = VersionStamp.Create(utcTime);
                var version = VersionStamp.Create(utcTime.AddDays(1));

                var key = "document";
                var serializer = new DiagnosticDataSerializer(analyzerVersion, version);

                Assert.True(await serializer.SerializeAsync(document, key, diagnostics, CancellationToken.None).ConfigureAwait(false));
                var recovered = await serializer.DeserializeAsync(document, key, CancellationToken.None);

                AssertDiagnostics(diagnostics, recovered);
            }
        }
Ejemplo n.º 12
0
            public async Task MergeAsync(ActiveFileState state, Document document)
            {
                Contract.ThrowIfFalse(state.DocumentId == document.Id);

                // merge active file state to project state
                var lastResult = _lastResult;

                var syntax   = state.GetAnalysisData(AnalysisKind.Syntax);
                var semantic = state.GetAnalysisData(AnalysisKind.Semantic);

                var project      = document.Project;
                var fullAnalysis = ServiceFeatureOnOffOptions.IsClosedFileDiagnosticsEnabled(project);

                // keep from build flag if full analysis is off
                var fromBuild = fullAnalysis ? false : lastResult.FromBuild;

                // if it is allowed to keep project state, check versions and if they are same, bail out
                // if full solution analysis is off or we are asked to reset document state, we always merge.
                if (fullAnalysis &&
                    syntax.Version != VersionStamp.Default &&
                    syntax.Version == semantic.Version &&
                    syntax.Version == lastResult.Version)
                {
                    // all data is in sync already.
                    return;
                }

                // we have mixed versions or full analysis is off, set it to default so that it can be re-calculated next time so data can be in sync.
                var version = VersionStamp.Default;

                // serialization can't be cancelled.
                var serializer = new DiagnosticDataSerializer(_owner.AnalyzerVersion, version);

                // save active file diagnostics back to project state
                await SerializeAsync(serializer, document, document.Id, _owner.SyntaxStateName, syntax.Items).ConfigureAwait(false);
                await SerializeAsync(serializer, document, document.Id, _owner.SemanticStateName, semantic.Items).ConfigureAwait(false);

                // save last aggregated form of analysis result
                _lastResult = new DiagnosticAnalysisResult(_lastResult.ProjectId, version, _lastResult.DocumentIdsOrEmpty.Add(state.DocumentId), isEmpty: false, fromBuild: fromBuild);
            }
            public async Task <DiagnosticAnalysisResult> GetAnalysisDataAsync(IPersistentStorageService persistentService, TextDocument document, bool avoidLoadingData, CancellationToken cancellationToken)
            {
                // make a copy of last result.
                var lastResult = _lastResult;

                Contract.ThrowIfFalse(lastResult.ProjectId == document.Project.Id);

                if (lastResult.IsDefault)
                {
                    return(await LoadInitialAnalysisDataAsync(persistentService, document, cancellationToken).ConfigureAwait(false));
                }

                var version = await GetDiagnosticVersionAsync(document.Project, cancellationToken).ConfigureAwait(false);

                if (avoidLoadingData && lastResult.Version != version)
                {
                    return(lastResult);
                }

                // if given document doesnt have any diagnostics, return empty.
                if (IsEmpty(lastResult, document.Id))
                {
                    return(DiagnosticAnalysisResult.CreateEmpty(lastResult.ProjectId, lastResult.Version));
                }

                // loading data can be cancelled any time.
                var serializer = new DiagnosticDataSerializer(_owner.AnalyzerVersion, lastResult.Version);
                var builder    = new Builder(document.Project, lastResult.Version);

                if (!await TryDeserializeDocumentDiagnosticsAsync(persistentService, serializer, document, builder, cancellationToken).ConfigureAwait(false))
                {
                    Debug.Assert(lastResult.Version == VersionStamp.Default);

                    // this can happen if we merged back active file diagnostics back to project state but
                    // project state didn't have diagnostics for the file yet. (since project state was staled)
                }

                return(builder.ToResult());
            }
            private async Task SerializeAsync(
                IPersistentStorageService?persistentService,
                DiagnosticDataSerializer serializer,
                Project project,
                TextDocument?document,
                object key,
                string stateKey,
                ImmutableArray <DiagnosticData> diagnostics
                )
            {
                Contract.ThrowIfFalse(document == null || document.Project == project);

                // try to serialize it
                if (
                    persistentService != null &&
                    await serializer
                    .SerializeAsync(
                        persistentService,
                        project,
                        document,
                        stateKey,
                        diagnostics,
                        CancellationToken.None
                        )
                    .ConfigureAwait(false)
                    )
                {
                    // we succeeded saving it to persistent storage. remove it from in memory cache if it exists
                    RemoveInMemoryCacheEntry(key, stateKey);
                    return;
                }

                // if serialization fail, hold it in the memory
                InMemoryStorage.Cache(
                    _owner.Analyzer,
                    (key, stateKey),
                    new CacheEntry(serializer.Version, diagnostics)
                    );
            }
            public async Task <DiagnosticAnalysisResult> GetProjectAnalysisDataAsync(IPersistentStorageService persistentService, Project project, bool avoidLoadingData, CancellationToken cancellationToken)
            {
                // make a copy of last result.
                var lastResult = _lastResult;

                Contract.ThrowIfFalse(lastResult.ProjectId == project.Id);

                if (lastResult.IsDefault)
                {
                    return(await LoadInitialProjectAnalysisDataAsync(persistentService, project, cancellationToken).ConfigureAwait(false));
                }

                var version = await GetDiagnosticVersionAsync(project, cancellationToken).ConfigureAwait(false);

                if (avoidLoadingData && lastResult.Version != version)
                {
                    return(lastResult);
                }

                // if given document doesnt have any diagnostics, return empty.
                if (lastResult.IsEmpty)
                {
                    return(DiagnosticAnalysisResult.CreateEmpty(lastResult.ProjectId, lastResult.Version));
                }

                // loading data can be cancelled any time.
                var serializer = new DiagnosticDataSerializer(_owner.AnalyzerVersion, lastResult.Version);
                var builder    = new Builder(project, lastResult.Version);

                if (!await TryDeserializeProjectDiagnosticsAsync(persistentService, serializer, project, builder, cancellationToken).ConfigureAwait(false))
                {
                    // this can happen if SaveAsync is not yet called but active file merge happened. one of case is if user did build before the very first
                    // analysis happened.
                }

                return(builder.ToResult());
            }
            /// <summary>
            /// Return all no location diagnostics for the given project stored in this state
            /// </summary>
            public async Task <AnalysisResult> GetProjectAnalysisDataAsync(Project project, bool avoidLoadingData, CancellationToken cancellationToken)
            {
                // make a copy of last result.
                var lastResult = _lastResult;

                Contract.ThrowIfFalse(lastResult.ProjectId == project.Id);

                if (lastResult.IsDefault)
                {
                    return(await LoadInitialProjectAnalysisDataAsync(project, cancellationToken).ConfigureAwait(false));
                }

                var version = await GetDiagnosticVersionAsync(project, cancellationToken).ConfigureAwait(false);

                if (avoidLoadingData && lastResult.Version != version)
                {
                    return(lastResult);
                }

                // if given document doesnt have any diagnostics, return empty.
                if (lastResult.IsEmpty)
                {
                    return(new AnalysisResult(lastResult.ProjectId, lastResult.Version));
                }

                // loading data can be cancelled any time.
                var serializer = new DiagnosticDataSerializer(_owner.AnalyzerVersion, lastResult.Version);
                var builder    = new Builder(project.Id, lastResult.Version);

                if (!await TryDeserializeAsync(serializer, project, project.Id, _owner.NonLocalStateName, builder.AddOthers, cancellationToken).ConfigureAwait(false))
                {
                    Contract.Requires(false, "How this can happen?");
                }

                return(builder.ToResult());
            }
            public async Task SaveAsync(Project project, AnalysisResult result)
            {
                Contract.ThrowIfTrue(result.IsAggregatedForm);

                RemoveInMemoryCache(_lastResult);

                // save last aggregated form of analysis result
                _lastResult = result.ToAggregatedForm();

                // serialization can't be cancelled.
                var serializer = new DiagnosticDataSerializer(_owner.AnalyzerVersion, result.Version);

                foreach (var documentId in result.DocumentIds)
                {
                    var document = project.GetDocument(documentId);
                    Contract.ThrowIfNull(document);

                    await SerializeAsync(serializer, document, document.Id, _owner.SyntaxStateName, GetResult(result, AnalysisKind.Syntax, document.Id)).ConfigureAwait(false);
                    await SerializeAsync(serializer, document, document.Id, _owner.SemanticStateName, GetResult(result, AnalysisKind.Semantic, document.Id)).ConfigureAwait(false);
                    await SerializeAsync(serializer, document, document.Id, _owner.NonLocalStateName, GetResult(result, AnalysisKind.NonLocal, document.Id)).ConfigureAwait(false);
                }

                await SerializeAsync(serializer, project, result.ProjectId, _owner.NonLocalStateName, result.Others).ConfigureAwait(false);
            }
Ejemplo n.º 18
0
            public async Task SaveAsync(Project project, DiagnosticAnalysisResult result)
            {
                Contract.ThrowIfTrue(result.IsAggregatedForm);

                RemoveInMemoryCache(_lastResult);

                // save last aggregated form of analysis result
                _lastResult = result.ToAggregatedForm();

                // serialization can't be cancelled.
                var serializer = new DiagnosticDataSerializer(_owner.AnalyzerVersion, result.Version);

                foreach (var documentId in result.DocumentIds)
                {
                    var document = project.GetDocument(documentId);
                    if (document == null)
                    {
                        // it can happen with build synchronization since, in build case,
                        // we don't have actual snapshot (we have no idea what sources out of proc build has picked up)
                        // so we might be out of sync.
                        // example of such cases will be changing anything about solution while building is going on.
                        // it can be user explict actions such as unloading project, deleting a file, but also it can be
                        // something project system or roslyn workspace does such as populating workspace right after
                        // solution is loaded.
                        continue;
                    }

                    await SerializeAsync(serializer, document, document.Id, _owner.SyntaxStateName, GetResult(result, AnalysisKind.Syntax, document.Id)).ConfigureAwait(false);
                    await SerializeAsync(serializer, document, document.Id, _owner.SemanticStateName, GetResult(result, AnalysisKind.Semantic, document.Id)).ConfigureAwait(false);
                    await SerializeAsync(serializer, document, document.Id, _owner.NonLocalStateName, GetResult(result, AnalysisKind.NonLocal, document.Id)).ConfigureAwait(false);
                }

                await SerializeAsync(serializer, project, result.ProjectId, _owner.NonLocalStateName, result.Others).ConfigureAwait(false);

                AnalyzerABTestLogger.LogProjectDiagnostics(project, _owner.StateName, result);
            }
            public async Task <DiagnosticAnalysisResult> GetAnalysisDataAsync(IPersistentStorageService persistentService, Project project, bool avoidLoadingData, CancellationToken cancellationToken)
            {
                // make a copy of last result.
                var lastResult = _lastResult;

                Contract.ThrowIfFalse(lastResult.ProjectId == project.Id);

                if (lastResult.IsDefault)
                {
                    return(await LoadInitialAnalysisDataAsync(persistentService, project, cancellationToken).ConfigureAwait(false));
                }

                RoslynDebug.Assert(lastResult.DocumentIds != null);

                // PERF: avoid loading data if version is not right one.
                // avoid loading data flag is there as a strictly perf optimization.
                var version = await GetDiagnosticVersionAsync(project, cancellationToken).ConfigureAwait(false);

                if (avoidLoadingData && lastResult.Version != version)
                {
                    return(lastResult);
                }

                // if given project doesnt have any diagnostics, return empty.
                if (lastResult.IsEmpty)
                {
                    return(DiagnosticAnalysisResult.CreateEmpty(lastResult.ProjectId, lastResult.Version));
                }

                // loading data can be cancelled any time.
                var serializer = new DiagnosticDataSerializer(_owner.AnalyzerVersion, lastResult.Version);
                var builder    = new Builder(project, lastResult.Version, lastResult.DocumentIds);

                foreach (var documentId in lastResult.DocumentIds)
                {
                    cancellationToken.ThrowIfCancellationRequested();

                    var document = project.GetDocument(documentId);
                    if (document == null)
                    {
                        continue;
                    }

                    if (!await TryDeserializeDocumentDiagnosticsAsync(persistentService, serializer, document, builder, cancellationToken).ConfigureAwait(false))
                    {
                        Debug.Assert(lastResult.Version == VersionStamp.Default);

                        // this can happen if we merged back active file diagnostics back to project state but
                        // project state didn't have diagnostics for the file yet. (since project state was staled)
                        continue;
                    }
                }

                if (!await TryDeserializeProjectDiagnosticsAsync(persistentService, serializer, project, builder, cancellationToken).ConfigureAwait(false))
                {
                    // this can happen if SaveAsync is not yet called but active file merge happened. one of case is if user did build before the very first
                    // analysis happened.
                }

                return(builder.ToResult());
            }
            private ValueTask <ImmutableArray <DiagnosticData> > DeserializeDiagnosticsAsync(IPersistentStorageService persistentService, DiagnosticDataSerializer serializer, Project project, TextDocument?document, object key, string stateKey, CancellationToken cancellationToken)
            {
                Contract.ThrowIfFalse(document == null || document.Project == project);

                if (InMemoryStorage.TryGetValue(_owner.Analyzer, (key, stateKey), out var entry) && serializer.Version == entry.Version)
                {
                    return(new ValueTask <ImmutableArray <DiagnosticData> >(entry.Diagnostics));
                }

                return(serializer.DeserializeAsync(persistentService, project, document, stateKey, cancellationToken));
            }
            private async Task <bool> TryDeserializeProjectDiagnosticsAsync(IPersistentStorageService persistentService, DiagnosticDataSerializer serializer, Project project, Builder builder, CancellationToken cancellationToken)
            {
                var diagnostics = await DeserializeDiagnosticsAsync(persistentService, serializer, project, document : null, project.Id, _owner.NonLocalStateName, cancellationToken).ConfigureAwait(false);

                if (!diagnostics.IsDefault)
                {
                    builder.AddOthers(diagnostics);
                    return(true);
                }

                return(false);
            }
            private async Task <bool> TryDeserializeDocumentDiagnosticsAsync(IPersistentStorageService persistentService, DiagnosticDataSerializer serializer, TextDocument document, Builder builder, CancellationToken cancellationToken)
            {
                var success    = true;
                var project    = document.Project;
                var documentId = document.Id;

                var diagnostics = await DeserializeDiagnosticsAsync(persistentService, serializer, project, document, documentId, _owner.SyntaxStateName, cancellationToken).ConfigureAwait(false);

                if (!diagnostics.IsDefault)
                {
                    builder.AddSyntaxLocals(documentId, diagnostics);
                }
                else
                {
                    success = false;
                }

                diagnostics = await DeserializeDiagnosticsAsync(persistentService, serializer, project, document, documentId, _owner.SemanticStateName, cancellationToken).ConfigureAwait(false);

                if (!diagnostics.IsDefault)
                {
                    builder.AddSemanticLocals(documentId, diagnostics);
                }
                else
                {
                    success = false;
                }

                diagnostics = await DeserializeDiagnosticsAsync(persistentService, serializer, project, document, documentId, _owner.NonLocalStateName, cancellationToken).ConfigureAwait(false);

                if (!diagnostics.IsDefault)
                {
                    builder.AddNonLocals(documentId, diagnostics);
                }
                else
                {
                    success = false;
                }

                return(success);
            }
Ejemplo n.º 23
0
            private Task <StrongBox <ImmutableArray <DiagnosticData> > > DeserializeAsync(DiagnosticDataSerializer serializer, object documentOrProject, object key, string stateKey, CancellationToken cancellationToken)
            {
                // when VS is loading new solution, we will try to find out all diagnostics persisted from previous VS session.
                // in that situation, it is possible that we have a lot of deserialization returning empty result. previously we used to
                // return default(ImmutableArray) for such case, but it turns out async/await framework has allocation issues with returning
                // default(value type), so we are using StrongBox to return no data as null. async/await has optimization where it will return
                // cached empty task if given value is null for reference type. (see AsyncMethodBuilder.GetTaskForResult)
                //
                // right now, we can't use Nullable either, since it is not one of value type the async/await will reuse cached task. in future,
                // if they do, we can change it to return Nullable<ImmutableArray>
                //
                // after initial deserialization, we track actual document/project that actually have diagnostics so no data won't be a common
                // case.
                // check cache first
                if (InMemoryStorage.TryGetValue(_owner.Analyzer, (key, stateKey), out var entry) && serializer.Version == entry.Version)
                {
                    if (entry.Diagnostics.Length == 0)
                    {
                        // if there is no result, use cached task
                        return(s_emptyResultTaskCache);
                    }

                    return(Task.FromResult(new StrongBox <ImmutableArray <DiagnosticData> >(entry.Diagnostics)));
                }

                // try to deserialize it
                return(serializer.DeserializeAsync(documentOrProject, stateKey, cancellationToken));
            }