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()); }
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()); }
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()); }
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); } }
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); } }
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)); }