diff --git a/src/Compilers/CSharp/Test/Semantic/SourceGeneration/GeneratorDriverTests.cs b/src/Compilers/CSharp/Test/Semantic/SourceGeneration/GeneratorDriverTests.cs index 4f3db6d4cd2d7..828c0590d3560 100644 --- a/src/Compilers/CSharp/Test/Semantic/SourceGeneration/GeneratorDriverTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/SourceGeneration/GeneratorDriverTests.cs @@ -2053,6 +2053,68 @@ class C { } }); } + [Fact, WorkItem(61162, "https://github.com/dotnet/roslyn/issues/61162")] + public void IncrementalGenerator_Collect_SyntaxProvider() + { + var generator = new IncrementalGeneratorWrapper(new PipelineCallbackGenerator(static ctx => + { + var invokedMethodsProvider = ctx.SyntaxProvider + .CreateSyntaxProvider( + static (node, _) => node is InvocationExpressionSyntax, + static (ctx, ct) => ctx.SemanticModel.GetSymbolInfo(ctx.Node, ct).Symbol?.Name ?? "(method not found)") + .Collect(); + + ctx.RegisterSourceOutput(invokedMethodsProvider, static (spc, invokedMethods) => + { + spc.AddSource("InvokedMethods.g.cs", string.Join(Environment.NewLine, + invokedMethods.Select(m => $"// {m}"))); + }); + })); + + var source = """ + System.Console.WriteLine(); + System.Console.WriteLine(); + System.Console.WriteLine(); + System.Console.WriteLine(); + """; + var parseOptions = TestOptions.RegularPreview; + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugExeThrowing, parseOptions: parseOptions); + + GeneratorDriver driver = CSharpGeneratorDriver.Create(new[] { generator }, parseOptions: parseOptions); + verify(ref driver, compilation, """ + // WriteLine + // WriteLine + // WriteLine + // WriteLine + """); + + replace(ref compilation, parseOptions, """ + System.Console.WriteLine(); + System.Console.WriteLine(); + """); + verify(ref driver, compilation, """ + // WriteLine + // WriteLine + """); + + replace(ref compilation, parseOptions, "_ = 0;"); + verify(ref driver, compilation, ""); + + static void verify(ref GeneratorDriver driver, Compilation compilation, string generatedContent) + { + driver = driver.RunGeneratorsAndUpdateCompilation(compilation, out var outputCompilation, out var generatorDiagnostics); + outputCompilation.VerifyDiagnostics(); + generatorDiagnostics.Verify(); + var generatedTree = driver.GetRunResult().GeneratedTrees.Single(); + AssertEx.EqualOrDiff(generatedContent, generatedTree.ToString()); + } + + static void replace(ref Compilation compilation, CSharpParseOptions parseOptions, string source) + { + compilation = compilation.ReplaceSyntaxTree(compilation.SyntaxTrees.Single(), CSharpSyntaxTree.ParseText(source, parseOptions)); + } + } + [Fact] public void IncrementalGenerator_Register_End_Node_Only_Once_Through_Combines() { diff --git a/src/Compilers/CSharp/Test/Semantic/SourceGeneration/StateTableTests.cs b/src/Compilers/CSharp/Test/Semantic/SourceGeneration/StateTableTests.cs index e19feab7f40b8..76919f93c9a8f 100644 --- a/src/Compilers/CSharp/Test/Semantic/SourceGeneration/StateTableTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/SourceGeneration/StateTableTests.cs @@ -585,6 +585,43 @@ public void Batch_Node_Records_InputModified_Step_When_Inputs_Are_Changed() }); } + [Fact, WorkItem(61162, "https://github.com/dotnet/roslyn/issues/61162")] + public void Batch_Node_Remove_From_Beginning() + { + // [A], [B] + var input = new[] { ("A", EntryState.Added), ("B", EntryState.Added) }; + var inputNode = new CallbackNode((_, _) => + { + // Simulate syntax node. + var builder = NodeStateTable.Empty.ToBuilder(null, false); + foreach (var (value, state) in input) + { + builder.AddEntry(value, state, TimeSpan.Zero, default, state); + } + return builder.ToImmutableAndFree(); + }); + var dstBuilder = GetBuilder(DriverStateTable.Empty); + var table1 = dstBuilder.GetLatestStateTableForNode(inputNode); + AssertTableEntries(table1, new[] { ("A", EntryState.Added, 0), ("B", EntryState.Added, 0) }); + AssertTableEntries(table1.AsCached(), new[] { ("A", EntryState.Cached, 0), ("B", EntryState.Cached, 0) }); + + // batch => [[A, B]] + var batchNode = new BatchNode(inputNode); + var table2 = dstBuilder.GetLatestStateTableForNode(batchNode); + AssertTableEntries(table2, new[] { (ImmutableArray.Create("A", "B"), EntryState.Added, 0) }); + AssertTableEntries(table2.AsCached(), new[] { (ImmutableArray.Create("A", "B"), EntryState.Cached, 0) }); + + // [B] + input = new[] { ("B", EntryState.Cached) }; + dstBuilder = GetBuilder(dstBuilder.ToImmutable()); + table1 = dstBuilder.GetLatestStateTableForNode(inputNode); + + // batch => [[B]] + table2 = dstBuilder.GetLatestStateTableForNode(batchNode); + AssertTableEntries(table2, new[] { (ImmutableArray.Create("B"), EntryState.Modified, 0) }); + AssertTableEntries(table2.AsCached(), new[] { (ImmutableArray.Create("B"), EntryState.Cached, 0) }); + } + [Fact] [WorkItem(54832, "https://github.com/dotnet/roslyn/issues/54832")] public void Transform_Node_Records_NewInput_OnFirst_Run()