public async Task IncrementalSourceGeneratorInvokedCorrectNumberOfTimes() { using var workspace = CreateWorkspace(); var generator = new GenerateFileForEachAdditionalFileWithContentsCommented(); var analyzerReference = new TestGeneratorReference(generator); var project = WithPreviewLanguageVersion(AddEmptyProject(workspace.CurrentSolution)) .AddAnalyzerReference(analyzerReference) .AddAdditionalDocument("Test.txt", "Hello, world!").Project .AddAdditionalDocument("Test2.txt", "Hello, world!").Project; var compilation = await project.GetRequiredCompilationAsync(CancellationToken.None); Assert.Equal(2, compilation.SyntaxTrees.Count()); Assert.Equal(2, generator.AdditionalFilesConvertedCount); // Change one of the additional documents, and rerun; we should only reprocess that one change, since this // is an incremental generator. project = project.AdditionalDocuments.First().WithAdditionalDocumentText(SourceText.From("Changed text!")).Project; compilation = await project.GetRequiredCompilationAsync(CancellationToken.None); Assert.Equal(2, compilation.SyntaxTrees.Count()); // We should now have converted three additional files -- the two from the original run and then the one that was changed. // The other one should have been kept constant because that didn't change. Assert.Equal(3, generator.AdditionalFilesConvertedCount); // Change one of the source documents, and rerun; we should again only reprocess that one change. project = project.AddDocument("Source.cs", SourceText.From("")).Project; compilation = await project.GetRequiredCompilationAsync(CancellationToken.None); // We have one extra syntax tree now, but it did not require any invocations of the incremental generator. Assert.Equal(3, compilation.SyntaxTrees.Count()); Assert.Equal(3, generator.AdditionalFilesConvertedCount); }
public async Task IncrementalSourceGeneratorInvokedCorrectNumberOfTimes() { using var workspace = CreateWorkspace(new[] { typeof(TestCSharpCompilationFactoryServiceWithIncrementalGeneratorTracking) }); var generator = new GenerateFileForEachAdditionalFileWithContentsCommented(); var analyzerReference = new TestGeneratorReference(generator); var project = AddEmptyProject(workspace.CurrentSolution) .AddAnalyzerReference(analyzerReference) .AddAdditionalDocument("Test.txt", "Hello, world!").Project .AddAdditionalDocument("Test2.txt", "Hello, world!").Project; var compilation = await project.GetRequiredCompilationAsync(CancellationToken.None); var generatorDriver = project.Solution.State.GetTestAccessor().GetGeneratorDriver(project) !; var runResult = generatorDriver !.GetRunResult().Results[0]; Assert.Equal(2, compilation.SyntaxTrees.Count()); Assert.Equal(2, runResult.TrackedSteps[GenerateFileForEachAdditionalFileWithContentsCommented.StepName].Length); Assert.All(runResult.TrackedSteps[GenerateFileForEachAdditionalFileWithContentsCommented.StepName], step => { Assert.Collection(step.Inputs, source => Assert.Equal(IncrementalStepRunReason.New, source.Source.Outputs[source.OutputIndex].Reason)); Assert.Collection(step.Outputs, output => Assert.Equal(IncrementalStepRunReason.New, output.Reason)); }); // Change one of the additional documents, and rerun; we should only reprocess that one change, since this // is an incremental generator. project = project.AdditionalDocuments.First().WithAdditionalDocumentText(SourceText.From("Changed text!")).Project; compilation = await project.GetRequiredCompilationAsync(CancellationToken.None); generatorDriver = project.Solution.State.GetTestAccessor().GetGeneratorDriver(project) !; runResult = generatorDriver.GetRunResult().Results[0]; Assert.Equal(2, compilation.SyntaxTrees.Count()); Assert.Equal(2, runResult.TrackedSteps[GenerateFileForEachAdditionalFileWithContentsCommented.StepName].Length); Assert.Contains(runResult.TrackedSteps[GenerateFileForEachAdditionalFileWithContentsCommented.StepName], step => { return(step.Inputs.Length == 1 && step.Inputs[0].Source.Outputs[step.Inputs[0].OutputIndex].Reason == IncrementalStepRunReason.Modified && step.Outputs.Length == 1 && step.Outputs[0].Reason == IncrementalStepRunReason.Modified); }); Assert.Contains(runResult.TrackedSteps[GenerateFileForEachAdditionalFileWithContentsCommented.StepName], step => { return(step.Inputs.Length == 1 && step.Inputs[0].Source.Outputs[step.Inputs[0].OutputIndex].Reason == IncrementalStepRunReason.Cached && step.Outputs.Length == 1 && step.Outputs[0].Reason == IncrementalStepRunReason.Cached); }); // Change one of the source documents, and rerun; we should again only reprocess that one change. project = project.AddDocument("Source.cs", SourceText.From("")).Project; compilation = await project.GetRequiredCompilationAsync(CancellationToken.None); generatorDriver = project.Solution.State.GetTestAccessor().GetGeneratorDriver(project) !; runResult = generatorDriver.GetRunResult().Results[0]; // We have one extra syntax tree now, but it did not require any invocations of the incremental generator. Assert.Equal(3, compilation.SyntaxTrees.Count()); Assert.Equal(2, runResult.TrackedSteps[GenerateFileForEachAdditionalFileWithContentsCommented.StepName].Length); Assert.All(runResult.TrackedSteps[GenerateFileForEachAdditionalFileWithContentsCommented.StepName], step => { Assert.Collection(step.Inputs, source => Assert.Equal(IncrementalStepRunReason.Cached, source.Source.Outputs[source.OutputIndex].Reason)); Assert.Collection(step.Outputs, output => Assert.Equal(IncrementalStepRunReason.Cached, output.Reason)); }); }