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