Exemple #1
0
        public async Task GeneratorOutputCachedBetweenAcrossCompileTimeSolutions()
        {
            var workspace = new TestWorkspace(composition: FeaturesTestCompositions.Features);
            var projectId = ProjectId.CreateNewId();

            var generatorInvocations = 0;

            var generator = new PipelineCallbackGenerator(context =>
            {
                // We'll replicate a simple example of how the razor generator handles disabling here so the test
                // functions similar to the real world
                var isDisabled = context.AnalyzerConfigOptionsProvider.Select(
                    (o, ct) => o.GlobalOptions.TryGetValue("build_property.SuppressRazorSourceGenerator", out var value) && bool.Parse(value));

                var sources = context.AdditionalTextsProvider.Combine(isDisabled).Select((pair, ct) =>
                {
                    var(additionalText, isDisabledFlag) = pair;

                    if (isDisabledFlag)
                    {
                        return(null);
                    }

                    Interlocked.Increment(ref generatorInvocations);
                    return("// " + additionalText.GetText(ct) !.ToString());
                });

                context.RegisterSourceOutput(sources, (context, s) =>
                {
                    if (s != null)
                    {
                        context.AddSource("hint", SourceText.From(s));
                    }
                });
            });

            var analyzerConfigId     = DocumentId.CreateNewId(projectId);
            var additionalDocumentId = DocumentId.CreateNewId(projectId);

            var analyzerConfigText = "is_global = true\r\nbuild_property.SuppressRazorSourceGenerator = true";

            workspace.SetCurrentSolution(s => s.
                                         AddProject(ProjectInfo.Create(projectId, VersionStamp.Default, "proj", "proj", LanguageNames.CSharp)).
                                         AddAnalyzerReference(projectId, new TestGeneratorReference(generator)).
                                         AddAdditionalDocument(additionalDocumentId, "additional", SourceText.From(""), filePath: "additional.razor").
                                         AddAnalyzerConfigDocument(analyzerConfigId, "config", SourceText.From(analyzerConfigText), filePath: "Z:\\RazorSourceGenerator.razorencconfig"),
                                         WorkspaceChangeKind.SolutionAdded);

            // Fetch a compilation first for the base solution; we're doing this because currently if we try to move the
            // cached generator state to a snapshot that has no CompilationTracker at all, we won't update the state.
            _ = await workspace.CurrentSolution.GetRequiredProject(projectId).GetCompilationAsync();

            var provider             = workspace.Services.GetRequiredService <ICompileTimeSolutionProvider>();
            var compileTimeSolution1 = provider.GetCompileTimeSolution(workspace.CurrentSolution);

            _ = await compileTimeSolution1.GetRequiredProject(projectId).GetCompilationAsync();

            Assert.Equal(1, generatorInvocations);

            // Now do something that shouldn't force the generator to rerun; we must change this through the workspace since the
            // service itself uses versions that won't change otherwise
            var documentId = DocumentId.CreateNewId(projectId);

            workspace.SetCurrentSolution(
                s => s.AddDocument(documentId, "Test.cs", "// source file"),
                WorkspaceChangeKind.DocumentAdded,
                projectId,
                documentId);

            var compileTimeSolution2 = provider.GetCompileTimeSolution(workspace.CurrentSolution);

            Assert.NotSame(compileTimeSolution1, compileTimeSolution2);

            _ = await compileTimeSolution2.GetRequiredProject(projectId).GetCompilationAsync();

            Assert.Equal(1, generatorInvocations);
        }