From 25cfa1e2cc0673458f88444ebb0d4a19941416ae Mon Sep 17 00:00:00 2001 From: Jan Jones Date: Thu, 22 Jan 2026 17:43:14 +0100 Subject: [PATCH 1/3] Validate generator diagnostics after incremental updates --- .../SourceGeneration/GeneratorDriverTests.cs | 51 ++++++++++++++++++- .../SourceGeneration/GeneratorDriver.cs | 9 ++++ 2 files changed, 58 insertions(+), 2 deletions(-) diff --git a/src/Compilers/CSharp/Test/Semantic/SourceGeneration/GeneratorDriverTests.cs b/src/Compilers/CSharp/Test/Semantic/SourceGeneration/GeneratorDriverTests.cs index 4da9b403db163..59ec111c0ee6e 100644 --- a/src/Compilers/CSharp/Test/Semantic/SourceGeneration/GeneratorDriverTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/SourceGeneration/GeneratorDriverTests.cs @@ -20,11 +20,14 @@ using Roslyn.Test.Utilities.TestGenerators; using Roslyn.Utilities; using Xunit; +using Xunit.Abstractions; namespace Microsoft.CodeAnalysis.CSharp.Semantic.UnitTests.SourceGeneration { - public class GeneratorDriverTests + public class GeneratorDriverTests(ITestOutputHelper output) : CSharpTestBase { + private readonly ITestOutputHelper _output = output; + [Fact] public void Running_With_No_Changes_Is_NoOp() { @@ -3891,6 +3894,48 @@ public void Diagnostic_SpanOutsideRange_Incremental() compilation.VerifyDiagnostics(); } + [Fact] + [WorkItem("https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1805836")] + [WorkItem("https://github.com/dotnet/roslyn/issues/82032")] + public void Diagnostic_SpanOutsideRange_Incremental_Update() + { + var source = "class SomewhatLongClassName {}"; + var parseOptions = TestOptions.RegularPreview; + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions, sourceFileName: "/original"); + compilation.VerifyDiagnostics(); + + var generator = new PipelineCallbackGenerator(ctx => + { + var inputs = ctx.SyntaxProvider.CreateSyntaxProvider( + static (node, ct) => node.IsKind(SyntaxKind.ClassDeclaration), + static (ctx, ct) => 0); + ctx.RegisterSourceOutput(inputs, (ctx, input) => + { + var tree = compilation.SyntaxTrees.Single(); + ctx.ReportDiagnostic(CodeAnalysis.Diagnostic.Create( + "TEST0001", + "Test", + "Test diagnostic", + DiagnosticSeverity.Warning, + DiagnosticSeverity.Warning, + isEnabledByDefault: true, + warningLevel: 1, + location: Location.Create(tree, TextSpan.FromBounds(20, 21)))); + }); + }).AsSourceGenerator(); + + GeneratorDriver driver = CSharpGeneratorDriver.Create(new[] { generator }, parseOptions: parseOptions); + driver = driver.RunGeneratorsAndUpdateCompilation(compilation, out compilation, out var diagnostics); + diagnostics.Verify(Diagnostic("TEST0001", "a").WithLocation(1, 21)); + + source = "class C {}"; + compilation = compilation.ReplaceSyntaxTree(compilation.SyntaxTrees.Single(), CSharpSyntaxTree.ParseText(source, parseOptions, path: "/original")); + driver = driver.RunGeneratorsAndUpdateCompilation(compilation, out compilation, out diagnostics); + + VerifyArgumentExceptionDiagnostic(diagnostics.Single(), nameof(PipelineCallbackGenerator), string.Format(CodeAnalysisResources.InvalidDiagnosticLocationReported, "TEST0001", "/original"), "diagnostic"); + compilation.VerifyDiagnostics(); + } + [ConditionalFact(typeof(IsEnglishLocal))] [WorkItem("https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1805836")] public void Diagnostic_SpanOutsideRange_Incremental_AdditionalLocations() @@ -4237,13 +4282,15 @@ static void replace(ref Compilation compilation, CSharpParseOptions parseOptions } } - private static void VerifyArgumentExceptionDiagnostic( + private void VerifyArgumentExceptionDiagnostic( Diagnostic diagnostic, string generatorName, string message, string parameterName, bool initialization = false) { + _output.WriteLine(diagnostic.ToString()); + var expectedMessage = #if NET $"{message} (Parameter '{parameterName}')"; diff --git a/src/Compilers/Core/Portable/SourceGeneration/GeneratorDriver.cs b/src/Compilers/Core/Portable/SourceGeneration/GeneratorDriver.cs index 2f4ca8f8c6052..1da3d4e378f5a 100644 --- a/src/Compilers/Core/Portable/SourceGeneration/GeneratorDriver.cs +++ b/src/Compilers/Core/Portable/SourceGeneration/GeneratorDriver.cs @@ -427,6 +427,15 @@ private static ImmutableArray FilterDiagnostics(Compilation compilat ArrayBuilder filteredDiagnostics = ArrayBuilder.GetInstance(); foreach (var diag in generatorDiagnostics) { + try + { + DiagnosticAnalysisContextHelpers.VerifyArguments(diag, compilation, isSupportedDiagnostic: static (_, _) => true, cancellationToken); + } + catch (ArgumentException ex) + { + throw new UserFunctionException(ex); + } + if (compilation.Options.FilterDiagnostic(diag, cancellationToken) is { } filtered && suppressMessageState.ApplySourceSuppressions(filtered) is { } effective) { From b293df39cd39146c6d14395f9baa3a466dac06ab Mon Sep 17 00:00:00 2001 From: Jan Jones Date: Thu, 22 Jan 2026 20:26:59 +0100 Subject: [PATCH 2/3] Improve formatting Co-authored-by: Cyrus Najmabadi --- .../Test/Semantic/SourceGeneration/GeneratorDriverTests.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Compilers/CSharp/Test/Semantic/SourceGeneration/GeneratorDriverTests.cs b/src/Compilers/CSharp/Test/Semantic/SourceGeneration/GeneratorDriverTests.cs index 59ec111c0ee6e..7763f4f5fea49 100644 --- a/src/Compilers/CSharp/Test/Semantic/SourceGeneration/GeneratorDriverTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/SourceGeneration/GeneratorDriverTests.cs @@ -21,6 +21,7 @@ using Roslyn.Utilities; using Xunit; using Xunit.Abstractions; + namespace Microsoft.CodeAnalysis.CSharp.Semantic.UnitTests.SourceGeneration { public class GeneratorDriverTests(ITestOutputHelper output) From f09e19f960155b2dfbb84d223d6d7b4f8e448ac1 Mon Sep 17 00:00:00 2001 From: Jan Jones Date: Fri, 23 Jan 2026 11:32:06 +0100 Subject: [PATCH 3/3] Simplify expected exception message computation Also should make it work under non-English locales. --- .../Test/Semantic/SourceGeneration/GeneratorDriverTests.cs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/Compilers/CSharp/Test/Semantic/SourceGeneration/GeneratorDriverTests.cs b/src/Compilers/CSharp/Test/Semantic/SourceGeneration/GeneratorDriverTests.cs index 7763f4f5fea49..0d155ae492098 100644 --- a/src/Compilers/CSharp/Test/Semantic/SourceGeneration/GeneratorDriverTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/SourceGeneration/GeneratorDriverTests.cs @@ -4292,12 +4292,7 @@ private void VerifyArgumentExceptionDiagnostic( { _output.WriteLine(diagnostic.ToString()); - var expectedMessage = -#if NET - $"{message} (Parameter '{parameterName}')"; -#else - $"{message}{Environment.NewLine}Parameter name: {parameterName}"; -#endif + var expectedMessage = new ArgumentException(message: message, paramName: parameterName).Message; VerifyGeneratorExceptionDiagnostic(diagnostic, generatorName, expectedMessage, initialization); }