You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Code written by WriteSourceFile has nullable disabled: every string? it emits raises CS8669, and non-annotated members are null-oblivious to consumers #55
GeneratorBase.WriteFileHeader (SourceGeneratorToolkit/GeneratorBase.cs, around lines 133–147) writes the copyright lines, then // <auto-generated />, then a blank line. WriteSourceFile (around lines 158–164) then calls codeBlocker.AddSourceFile(...) immediately.
Nothing on this path writes a #nullable directive. CodeBlocker.AddSourceFile emits the namespace, usings and types, but not #nullable enable; CodeBlocker has a separate WriteNullableEnable() for that.
Roslyn treats any file carrying an <auto-generated marker as generated code. Generated code runs with the nullable context disabled unless the file opts in with a directive, whatever <Nullable>enable</Nullable> the consuming project sets. And because WriteSourceFile writes the header and the body in one call, a caller can't put the directive between them.
Failure scenario
A generator built on the toolkit writes a class through WriteSourceFile with public string? Description; and public string Name = "";. The output is:
That output is compiled with NullableContextOptions.Enable alongside a user file containing t.Name = null; int n = t.Description.Length;. The compiler reports:
Thing.g.cs(8,15): warning CS8669: The annotation for nullable reference types should only be used in code within a '#nullable' annotations context. Auto-generated code requires an explicit '#nullable' directive in source.
User.cs(1,75): warning CS8602: Dereference of a possibly null reference.
t.Name = null produces no CS8625, because Name is nullable-oblivious.
Consequences:
With TreatWarningsAsErrors, which ktsu repositories use, any consuming generator that emits a ? annotation breaks the consumer's build.
Without annotations, every reference-typed member in the generated API is oblivious, so consumers silently lose null checking on it.
Have WriteFileHeader write #nullable enable after the // <auto-generated /> marker, so WriteSourceFile inherits it. Alternatively, add a parameter or overload that opts in. Enabled-by-default suits the ktsu convention of nullable-enabled projects.
Acceptance criteria
The output of WriteSourceFile and WriteFileHeader contains #nullable enable after the generated-file marker, or does so when the new option is chosen.
A test compiles WriteSourceFile output that contains a string? member under nullable enable and asserts there is no CS8669.
A test asserts that assigning null to a non-annotated generated string member raises CS8625.
Priority: High. Every ktsu consumer builds with TreatWarningsAsErrors, so any generator on the toolkit that emits a ? annotation breaks its consumer's build (CS8669). Generated members are also silently null-oblivious. The fix is a single line in the shared header.
Area / suggested assignee:SourceGeneratorToolkit/GeneratorBase.cs: WriteFileHeader (~133–147) and WriteSourceFile (~158–164). Owner: @matt-edmondson
Next step: emit #nullable enable after // <auto-generated /> in WriteFileHeader. Add the CS8669-absent and CS8625-present compile tests. Check downstream generators (e.g. Semantics) for any that already add their own #nullable line and would then emit it twice.
Activity
matt-edmondson commentedon Oct 29, 2026
Triage
TreatWarningsAsErrors, so any generator on the toolkit that emits a?annotation breaks its consumer's build (CS8669). Generated members are also silently null-oblivious. The fix is a single line in the shared header.SourceGeneratorToolkit/GeneratorBase.cs:WriteFileHeader(~133–147) andWriteSourceFile(~158–164). Owner: @matt-edmondson#nullable enableafter// <auto-generated />inWriteFileHeader. Add the CS8669-absent and CS8625-present compile tests. Check downstream generators (e.g. Semantics) for any that already add their own#nullableline and would then emit it twice.Generated by Claude Code