Turn on #nullable enable across the AST consumer layer: the output visitor, the
IL-to-C# builders (statement, call and expression builders, CSharpDecompiler,
TypeSystemAstBuilder), the translation-result wrappers, the sequence-point and
required-namespace collectors, and the annotation helpers. Optional inputs,
fields and returns are typed nullable, detector out-parameters use
[NotNullWhen(true)], and structurally-guaranteed dereferences use the
null-forgiving operator. A few public parameters that already tolerate null are
widened to match their downstream callers. The annotations emit no IL, so the
Pretty suite stays byte-identical.
Assisted-by: Claude:claude-opus-4-8:Claude Code
TokenRole was a printer-side descriptor whose only jobs were holding a token's
text and giving the writers an identity to single out specific tokens. The text
becomes plain const strings on the nodes, and the few identity checks are
reexpressed as node-stack context: interpolation braces are recognized by an
Interpolation on the writer's stack, record class versus struct coloring keys
off TypeDeclaration.ClassType, and the accessor/this/base/override cases fall
out of the surrounding node. WriteKeyword/WriteToken drop the descriptor
parameter. The constants are named for what the token is: a keyword, a symbol
token, or a modifier.
Assisted-by: Claude:claude-opus-4-8:Claude Code
The token writers and the UI syntax highlighter only need a token's identity (to
single out structural braces, the constructor this/base keyword, the override
modifier, and to colour keywords) -- not the AST child-role machinery. Make
TokenRole a standalone printer-side descriptor instead of a Role, turn the
modifier marker into a TokenRole, and change the WriteKeyword/WriteToken
signatures from Role to TokenRole across the writer hierarchy and the highlighter.
This lets the child Role hierarchy be removed without disturbing token output.
The dead OptionalComma/OptionalSemicolon bodies (no comma/semicolon/whitespace
children exist since the token drop) become no-ops, and the few sites that handed
the writer a child role for a keyword now pass none. Output is unchanged across
the decompiler suite, and the UI builds.
Assisted-by: Claude:claude-opus-4-8:Claude Code