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)); }
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(ValueTaskFactory.FromResult(entry.Diagnostics)); } return(serializer.DeserializeAsync( persistentService, project, document, stateKey, cancellationToken )); }
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)); }
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); } }