public static DiagnosticAnalysisResultMap <DiagnosticAnalyzer, DiagnosticAnalysisResult> Deserialize(
            ObjectReader reader, IDictionary <string, DiagnosticAnalyzer> analyzerMap, Project project, VersionStamp version, CancellationToken cancellationToken)
        {
            var diagnosticDataSerializer = new DiagnosticDataSerializer(VersionStamp.Default, VersionStamp.Default);

            var analysisMap = ImmutableDictionary.CreateBuilder <DiagnosticAnalyzer, DiagnosticAnalysisResult>();

            var analysisCount = reader.ReadInt32();

            for (var i = 0; i < analysisCount; i++)
            {
                var analyzer = analyzerMap[reader.ReadString()];

                var syntaxLocalMap   = Deserialize(reader, diagnosticDataSerializer, project, cancellationToken);
                var semanticLocalMap = Deserialize(reader, diagnosticDataSerializer, project, cancellationToken);
                var nonLocalMap      = Deserialize(reader, diagnosticDataSerializer, project, cancellationToken);

                var others = diagnosticDataSerializer.ReadFrom(reader, project, cancellationToken);

                var analysisResult = new DiagnosticAnalysisResult(
                    project.Id, version,
                    syntaxLocalMap, semanticLocalMap, nonLocalMap, GetOrDefault(others),
                    documentIds: null, fromBuild: false);

                analysisMap.Add(analyzer, analysisResult);
            }

            var telemetryMap = ImmutableDictionary.CreateBuilder <DiagnosticAnalyzer, AnalyzerTelemetryInfo>();

            var telemetryCount = reader.ReadInt32();

            for (var i = 0; i < telemetryCount; i++)
            {
                var analyzer      = analyzerMap[reader.ReadString()];
                var telemetryInfo = Deserialize(reader, cancellationToken);

                telemetryMap.Add(analyzer, telemetryInfo);
            }

            var exceptionMap = ImmutableDictionary.CreateBuilder <DiagnosticAnalyzer, ImmutableArray <DiagnosticData> >();

            var exceptionCount = reader.ReadInt32();

            for (var i = 0; i < exceptionCount; i++)
            {
                var analyzer   = analyzerMap[reader.ReadString()];
                var exceptions = diagnosticDataSerializer.ReadFrom(reader, project, cancellationToken);

                exceptionMap.Add(analyzer, GetOrDefault(exceptions));
            }

            return(DiagnosticAnalysisResultMap.Create(analysisMap.ToImmutable(), telemetryMap.ToImmutable(), exceptionMap.ToImmutable()));
        }
            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);
            }
            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 static void Serialize(
     ObjectWriter writer,
     DiagnosticDataSerializer serializer,
     ImmutableDictionary <DocumentId, ImmutableArray <DiagnosticData> > diagnostics,
     CancellationToken cancellationToken)
 {
     writer.WriteInt32(diagnostics.Count);
     foreach (var kv in diagnostics)
     {
         Serializer.SerializeDocumentId(kv.Key, writer, cancellationToken);
         serializer.WriteTo(writer, kv.Value, cancellationToken);
     }
 }
            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, version);

                if (!await TryDeserializeAsync(serializer, project, project.Id, _owner.NonLocalStateName, s_addOthers, builder, cancellationToken).ConfigureAwait(false))
                {
                    return(DiagnosticAnalysisResult.CreateEmpty(project.Id, VersionStamp.Default));
                }

                return(builder.ToResult());
            }
Exemple #6
0
        public static (int diagnostics, int telemetry) WriteDiagnosticAnalysisResults(
            ObjectWriter writer,
            AnalysisKind?analysisKind,
            DiagnosticAnalysisResultMap <string, DiagnosticAnalysisResultBuilder> result,
            CancellationToken cancellationToken)
        {
            var diagnosticCount      = 0;
            var diagnosticSerializer = new DiagnosticDataSerializer(VersionStamp.Default, VersionStamp.Default);

            writer.WriteInt32(result.AnalysisResult.Count);
            foreach (var(analyzerId, analyzerResults) in result.AnalysisResult)
            {
                writer.WriteString(analyzerId);

                switch (analysisKind)
                {
                case AnalysisKind.Syntax:
                    diagnosticCount += WriteDiagnosticDataMap(writer, diagnosticSerializer, analyzerResults.SyntaxLocals, cancellationToken);
                    break;

                case AnalysisKind.Semantic:
                    diagnosticCount += WriteDiagnosticDataMap(writer, diagnosticSerializer, analyzerResults.SemanticLocals, cancellationToken);
                    break;

                case null:
                    diagnosticCount += WriteDiagnosticDataMap(writer, diagnosticSerializer, analyzerResults.SyntaxLocals, cancellationToken);
                    diagnosticCount += WriteDiagnosticDataMap(writer, diagnosticSerializer, analyzerResults.SemanticLocals, cancellationToken);
                    diagnosticCount += WriteDiagnosticDataMap(writer, diagnosticSerializer, analyzerResults.NonLocals, cancellationToken);

                    diagnosticSerializer.WriteDiagnosticData(writer, analyzerResults.Others, cancellationToken);
                    diagnosticCount += analyzerResults.Others.Length;
                    break;

                default:
                    throw ExceptionUtilities.UnexpectedValue(analysisKind.Value);
                }
            }

            writer.WriteInt32(result.TelemetryInfo.Count);
            foreach (var(analyzerId, analyzerTelemetry) in result.TelemetryInfo)
            {
                writer.WriteString(analyzerId);
                WriteTelemetry(writer, analyzerTelemetry, cancellationToken);
            }

            // report how many data has been sent
            return(diagnosticCount, result.TelemetryInfo.Count);
        }
            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);
            }
            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);
            }
            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());
            }
Exemple #10
0
        public static DiagnosticAnalysisResultMap <DiagnosticAnalyzer, DiagnosticAnalysisResult> ReadDiagnosticAnalysisResults(
            ObjectReader reader, IDictionary <string, DiagnosticAnalyzer> analyzerMap, Project project, VersionStamp version, CancellationToken cancellationToken)
        {
            var diagnosticDataSerializer = new DiagnosticDataSerializer(VersionStamp.Default, VersionStamp.Default);

            var analysisMap = ImmutableDictionary.CreateBuilder <DiagnosticAnalyzer, DiagnosticAnalysisResult>();

            var analysisCount = reader.ReadInt32();

            for (var i = 0; i < analysisCount; i++)
            {
                var analyzer = analyzerMap[reader.ReadString()];

                var syntaxLocalMap   = ReadDiagnosticDataMap(reader, diagnosticDataSerializer, project, cancellationToken);
                var semanticLocalMap = ReadDiagnosticDataMap(reader, diagnosticDataSerializer, project, cancellationToken);
                var nonLocalMap      = ReadDiagnosticDataMap(reader, diagnosticDataSerializer, project, cancellationToken);

                var others = diagnosticDataSerializer.ReadDiagnosticData(reader, project, document: null, cancellationToken);

                var analysisResult = DiagnosticAnalysisResult.Create(
                    project,
                    version,
                    syntaxLocalMap,
                    semanticLocalMap,
                    nonLocalMap,
                    others.NullToEmpty(),
                    documentIds: null);

                analysisMap.Add(analyzer, analysisResult);
            }

            var telemetryMap = ImmutableDictionary.CreateBuilder <DiagnosticAnalyzer, AnalyzerTelemetryInfo>();

            var telemetryCount = reader.ReadInt32();

            for (var i = 0; i < telemetryCount; i++)
            {
                var analyzer      = analyzerMap[reader.ReadString()];
                var telemetryInfo = ReadTelemetry(reader, cancellationToken);

                telemetryMap.Add(analyzer, telemetryInfo);
            }

            return(DiagnosticAnalysisResultMap.Create(analysisMap.ToImmutable(), telemetryMap.ToImmutable()));
        }
        private static int Serialize(
            ObjectWriter writer,
            DiagnosticDataSerializer serializer,
            ImmutableDictionary <DocumentId, ImmutableArray <DiagnosticData> > diagnostics,
            CancellationToken cancellationToken)
        {
            var count = 0;

            writer.WriteInt32(diagnostics.Count);
            foreach (var kv in diagnostics)
            {
                kv.Key.WriteTo(writer);
                serializer.WriteTo(writer, kv.Value, cancellationToken);

                count += kv.Value.Length;
            }

            return(count);
        }
        private static ImmutableDictionary <DocumentId, ImmutableArray <DiagnosticData> > Deserialize(
            ObjectReader reader,
            DiagnosticDataSerializer serializer,
            Project project,
            CancellationToken cancellationToken)
        {
            var count = reader.ReadInt32();
            var map   = ImmutableDictionary.CreateBuilder <DocumentId, ImmutableArray <DiagnosticData> >();

            for (var i = 0; i < count; i++)
            {
                var documentId  = Serializer.DeserializeDocumentId(reader, cancellationToken);
                var diagnostics = serializer.ReadFrom(reader, project.GetDocument(documentId), cancellationToken);

                map.Add(documentId, GetOrDefault(diagnostics));
            }

            return(map.ToImmutable());
        }
Exemple #13
0
        private static int WriteDiagnosticDataMap(
            ObjectWriter writer,
            DiagnosticDataSerializer serializer,
            ImmutableDictionary <DocumentId, ImmutableArray <DiagnosticData> > diagnostics,
            CancellationToken cancellationToken)
        {
            var count = 0;

            writer.WriteInt32(diagnostics.Count);
            foreach (var(documentId, data) in diagnostics)
            {
                documentId.WriteTo(writer);
                serializer.WriteDiagnosticData(writer, data, cancellationToken);

                count += data.Length;
            }

            return(count);
        }
        public static (int diagnostics, int telemetry, int exceptions) Serialize(
            ObjectWriter writer, DiagnosticAnalysisResultMap <string, DiagnosticAnalysisResultBuilder> result, CancellationToken cancellationToken)
        {
            var diagnosticCount      = 0;
            var diagnosticSerializer = new DiagnosticDataSerializer(VersionStamp.Default, VersionStamp.Default);

            var analysisResult = result.AnalysisResult;

            writer.WriteInt32(analysisResult.Count);
            foreach (var kv in analysisResult)
            {
                writer.WriteString(kv.Key);

                diagnosticCount += Serialize(writer, diagnosticSerializer, kv.Value.SyntaxLocals, cancellationToken);
                diagnosticCount += Serialize(writer, diagnosticSerializer, kv.Value.SemanticLocals, cancellationToken);
                diagnosticCount += Serialize(writer, diagnosticSerializer, kv.Value.NonLocals, cancellationToken);

                diagnosticSerializer.WriteTo(writer, kv.Value.Others, cancellationToken);
                diagnosticCount += kv.Value.Others.Length;
            }

            var telemetryInfo = result.TelemetryInfo;

            writer.WriteInt32(telemetryInfo.Count);
            foreach (var kv in telemetryInfo)
            {
                writer.WriteString(kv.Key);
                Serialize(writer, kv.Value, cancellationToken);
            }

            var exceptions = result.Exceptions;

            writer.WriteInt32(exceptions.Count);
            foreach (var kv in exceptions)
            {
                writer.WriteString(kv.Key);
                diagnosticSerializer.WriteTo(writer, kv.Value, cancellationToken);
            }

            // report how many data has been sent
            return(diagnosticCount, telemetryInfo.Count, exceptions.Count);
        }
        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);
            }
        }
            /// <summary>
            /// Return all diagnostics for the given document stored in this state including non local diagnostics for this document
            /// </summary>
            public async Task <DiagnosticAnalysisResult> GetAnalysisDataAsync(Document 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(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 TryDeserializeDocumentAsync(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());
            }
            /// <summary>
            /// Return all no location diagnostics for the given project stored in this state
            /// </summary>
            public async Task <DiagnosticAnalysisResult> 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(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 TryDeserializeAsync(serializer, project, project.Id, _owner.NonLocalStateName, s_addOthers, 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());
            }
        public static void Serialize(ObjectWriter writer, DiagnosticAnalysisResultMap <string, DiagnosticAnalysisResultBuilder> result, CancellationToken cancellationToken)
        {
            var diagnosticSerializer = new DiagnosticDataSerializer(VersionStamp.Default, VersionStamp.Default);

            var analysisResult = result.AnalysisResult;

            writer.WriteInt32(analysisResult.Count);
            foreach (var kv in analysisResult)
            {
                writer.WriteString(kv.Key);

                Serialize(writer, diagnosticSerializer, kv.Value.SyntaxLocals, cancellationToken);
                Serialize(writer, diagnosticSerializer, kv.Value.SemanticLocals, cancellationToken);
                Serialize(writer, diagnosticSerializer, kv.Value.NonLocals, cancellationToken);

                diagnosticSerializer.WriteTo(writer, kv.Value.Others, cancellationToken);
            }

            var telemetryInfo = result.TelemetryInfo;

            writer.WriteInt32(telemetryInfo.Count);
            foreach (var kv in telemetryInfo)
            {
                writer.WriteString(kv.Key);
                Serialize(writer, kv.Value, cancellationToken);
            }

            var exceptions = result.Exceptions;

            writer.WriteInt32(exceptions.Count);
            foreach (var kv in exceptions)
            {
                writer.WriteString(kv.Key);
                diagnosticSerializer.WriteTo(writer, kv.Value, cancellationToken);
            }
        }
Exemple #19
0
        public static (int diagnostics, int telemetry, int exceptions) WriteDiagnosticAnalysisResults(
            ObjectWriter writer, DiagnosticAnalysisResultMap <string, DiagnosticAnalysisResultBuilder> result, CancellationToken cancellationToken)
        {
            var diagnosticCount      = 0;
            var diagnosticSerializer = new DiagnosticDataSerializer(VersionStamp.Default, VersionStamp.Default);

            writer.WriteInt32(result.AnalysisResult.Count);
            foreach (var(analyzerId, analyzerResults) in result.AnalysisResult)
            {
                writer.WriteString(analyzerId);

                diagnosticCount += WriteDiagnosticDataMap(writer, diagnosticSerializer, analyzerResults.SyntaxLocals, cancellationToken);
                diagnosticCount += WriteDiagnosticDataMap(writer, diagnosticSerializer, analyzerResults.SemanticLocals, cancellationToken);
                diagnosticCount += WriteDiagnosticDataMap(writer, diagnosticSerializer, analyzerResults.NonLocals, cancellationToken);

                diagnosticSerializer.WriteDiagnosticData(writer, analyzerResults.Others, cancellationToken);
                diagnosticCount += analyzerResults.Others.Length;
            }

            writer.WriteInt32(result.TelemetryInfo.Count);
            foreach (var(analyzerId, analyzerTelemetry) in result.TelemetryInfo)
            {
                writer.WriteString(analyzerId);
                WriteTelemetry(writer, analyzerTelemetry, cancellationToken);
            }

            writer.WriteInt32(result.Exceptions.Count);
            foreach (var(analyzerId, analyzerExceptions) in result.Exceptions)
            {
                writer.WriteString(analyzerId);
                diagnosticSerializer.WriteDiagnosticData(writer, analyzerExceptions, cancellationToken);
            }

            // report how many data has been sent
            return(diagnosticCount, result.TelemetryInfo.Count, result.Exceptions.Count);
        }
            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 static bool TryReadDiagnosticAnalysisResults(
            ObjectReader reader,
            IDictionary <string, DiagnosticAnalyzer> analyzerMap,
            DocumentAnalysisScope?documentAnalysisScope,
            Project project,
            VersionStamp version,
            CancellationToken cancellationToken,
            [NotNullWhen(returnValue: true)] out DiagnosticAnalysisResultMap <DiagnosticAnalyzer, DiagnosticAnalysisResult>?result)
        {
            result = null;

            try
            {
                var diagnosticDataSerializer = new DiagnosticDataSerializer(VersionStamp.Default, VersionStamp.Default);

                var analysisMap = ImmutableDictionary.CreateBuilder <DiagnosticAnalyzer, DiagnosticAnalysisResult>();
                var documentIds = documentAnalysisScope != null?ImmutableHashSet.Create(documentAnalysisScope.TextDocument.Id) : null;

                var analysisCount = reader.ReadInt32();
                for (var i = 0; i < analysisCount; i++)
                {
                    var analyzer = analyzerMap[reader.ReadString()];

                    DiagnosticAnalysisResult analysisResult;
                    if (documentAnalysisScope != null)
                    {
                        ImmutableDictionary <DocumentId, ImmutableArray <DiagnosticData> >?syntaxLocalMap, semanticLocalMap;
                        if (documentAnalysisScope.Kind == AnalysisKind.Syntax)
                        {
                            if (!TryReadDiagnosticDataMap(reader, diagnosticDataSerializer, project, cancellationToken, out syntaxLocalMap))
                            {
                                return(false);
                            }

                            semanticLocalMap = ImmutableDictionary <DocumentId, ImmutableArray <DiagnosticData> > .Empty;
                        }
                        else
                        {
                            Debug.Assert(documentAnalysisScope.Kind == AnalysisKind.Semantic);
                            if (!TryReadDiagnosticDataMap(reader, diagnosticDataSerializer, project, cancellationToken, out semanticLocalMap))
                            {
                                return(false);
                            }

                            syntaxLocalMap = ImmutableDictionary <DocumentId, ImmutableArray <DiagnosticData> > .Empty;
                        }

                        analysisResult = DiagnosticAnalysisResult.Create(
                            project,
                            version,
                            syntaxLocalMap,
                            semanticLocalMap,
                            nonLocalMap: ImmutableDictionary <DocumentId, ImmutableArray <DiagnosticData> > .Empty,
                            others: ImmutableArray <DiagnosticData> .Empty,
                            documentIds);
                    }
                    else
                    {
                        if (!TryReadDiagnosticDataMap(reader, diagnosticDataSerializer, project, cancellationToken, out var syntaxLocalMap) ||
                            !TryReadDiagnosticDataMap(reader, diagnosticDataSerializer, project, cancellationToken, out var semanticLocalMap) ||
                            !TryReadDiagnosticDataMap(reader, diagnosticDataSerializer, project, cancellationToken, out var nonLocalMap) ||
                            !diagnosticDataSerializer.TryReadDiagnosticData(reader, project, document: null, cancellationToken, out var others))
                        {
                            return(false);
                        }

                        analysisResult = DiagnosticAnalysisResult.Create(
                            project,
                            version,
                            syntaxLocalMap,
                            semanticLocalMap,
                            nonLocalMap,
                            others.NullToEmpty(),
                            documentIds: null);
                    }

                    analysisMap.Add(analyzer, analysisResult);
                }

                var telemetryMap = ImmutableDictionary.CreateBuilder <DiagnosticAnalyzer, AnalyzerTelemetryInfo>();

                var telemetryCount = reader.ReadInt32();
                for (var i = 0; i < telemetryCount; i++)
                {
                    var analyzer      = analyzerMap[reader.ReadString()];
                    var telemetryInfo = ReadTelemetry(reader, cancellationToken);

                    telemetryMap.Add(analyzer, telemetryInfo);
                }

                result = DiagnosticAnalysisResultMap.Create(analysisMap.ToImmutable(), telemetryMap.ToImmutable());
                return(true);
            }
            catch (Exception ex) when(FatalError.ReportWithoutCrashUnlessCanceled(ex))
            {
                return(false);
            }
        }
Exemple #22
0
        public static DiagnosticAnalysisResultMap <DiagnosticAnalyzer, DiagnosticAnalysisResult> ReadDiagnosticAnalysisResults(
            ObjectReader reader,
            IDictionary <string, DiagnosticAnalyzer> analyzerMap,
            DocumentAnalysisScope?documentAnalysisScope,
            Project project,
            VersionStamp version,
            CancellationToken cancellationToken)
        {
            var diagnosticDataSerializer = new DiagnosticDataSerializer(VersionStamp.Default, VersionStamp.Default);

            var analysisMap = ImmutableDictionary.CreateBuilder <DiagnosticAnalyzer, DiagnosticAnalysisResult>();
            var documentIds = documentAnalysisScope != null?ImmutableHashSet.Create(documentAnalysisScope.TextDocument.Id) : null;

            var analysisCount = reader.ReadInt32();

            for (var i = 0; i < analysisCount; i++)
            {
                var analyzer = analyzerMap[reader.ReadString()];

                DiagnosticAnalysisResult analysisResult;
                if (documentAnalysisScope != null)
                {
                    ImmutableDictionary <DocumentId, ImmutableArray <DiagnosticData> > syntaxLocalMap, semanticLocalMap;
                    if (documentAnalysisScope.Kind == AnalysisKind.Syntax)
                    {
                        syntaxLocalMap   = ReadDiagnosticDataMap(reader, diagnosticDataSerializer, project, cancellationToken);
                        semanticLocalMap = ImmutableDictionary <DocumentId, ImmutableArray <DiagnosticData> > .Empty;
                    }
                    else
                    {
                        Debug.Assert(documentAnalysisScope.Kind == AnalysisKind.Semantic);
                        semanticLocalMap = ReadDiagnosticDataMap(reader, diagnosticDataSerializer, project, cancellationToken);
                        syntaxLocalMap   = ImmutableDictionary <DocumentId, ImmutableArray <DiagnosticData> > .Empty;
                    }

                    analysisResult = DiagnosticAnalysisResult.Create(
                        project,
                        version,
                        syntaxLocalMap,
                        semanticLocalMap,
                        nonLocalMap: ImmutableDictionary <DocumentId, ImmutableArray <DiagnosticData> > .Empty,
                        others: ImmutableArray <DiagnosticData> .Empty,
                        documentIds);
                }
                else
                {
                    var syntaxLocalMap   = ReadDiagnosticDataMap(reader, diagnosticDataSerializer, project, cancellationToken);
                    var semanticLocalMap = ReadDiagnosticDataMap(reader, diagnosticDataSerializer, project, cancellationToken);
                    var nonLocalMap      = ReadDiagnosticDataMap(reader, diagnosticDataSerializer, project, cancellationToken);

                    var others = diagnosticDataSerializer.ReadDiagnosticData(reader, project, document: null, cancellationToken);

                    analysisResult = DiagnosticAnalysisResult.Create(
                        project,
                        version,
                        syntaxLocalMap,
                        semanticLocalMap,
                        nonLocalMap,
                        others.NullToEmpty(),
                        documentIds: null);
                }

                analysisMap.Add(analyzer, analysisResult);
            }

            var telemetryMap = ImmutableDictionary.CreateBuilder <DiagnosticAnalyzer, AnalyzerTelemetryInfo>();

            var telemetryCount = reader.ReadInt32();

            for (var i = 0; i < telemetryCount; i++)
            {
                var analyzer      = analyzerMap[reader.ReadString()];
                var telemetryInfo = ReadTelemetry(reader, cancellationToken);

                telemetryMap.Add(analyzer, telemetryInfo);
            }

            return(DiagnosticAnalysisResultMap.Create(analysisMap.ToImmutable(), telemetryMap.ToImmutable()));
        }
            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));
            }