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
A multi-line expression body from a Method/Constructor/Operator BodyFactory drops its => to the next line, unlike PropertyTemplate.ExpressionBodyFactory #163
TemplateRendering.WriteBody (CodeBlocker/Templates/TemplateRendering.cs) decides a body's shape by counting its non-blank lines:
A single line is treated as an expression body and kept on the declaration line.
Two or more lines are treated as a braced block. The declaration line is ended and the fragment is spliced in below it.
A BodyFactory that writes a multi-line expression body, one starting with =>, therefore takes the braced-block path, and the arrow ends up on its own line at the declaration's indent:
publicintM()=>kswitch{
_ =>0,};
Through PropertyTemplate.ExpressionBodyFactory (which uses WriteExpressionBody and was fixed in #112/#114), the same expression renders as:
publicintX=> k switch{
_ =>0,};
MethodTemplate, ConstructorTemplate and OperatorTemplate all go through WriteBody. Their docs say the callback "supplies its own braces, or writes an expression body such as => value;", but only the single-line form of an expression body renders as documented.
Reproduction
Reproduced at 21ac04c. The output was compiled with Roslyn: no errors, so this is a layout defect, not a compile break.
varc=newClassTemplate{Name="C",Keywords={"public"}};c.Members.Add(newMethodTemplate{Type="int",Name="M",Keywords={"public"},BodyFactory= cb =>{cb.WriteLine("=> k switch");using(newScopeWithTrailingSemicolon(cb)){cb.WriteLine("_ => 0,");}},});cb.AddClass(c);// actual: "\tpublic int M()\n\t=> k switch\n\t{\n\t\t_ => 0,\n\t};\n"// expected: "\tpublic int M() => k switch\n\t{\n\t\t_ => 0,\n\t};\n"
An explicit operator with the same body shows the same layout (public static explicit operator int(C c) / => c.k switch / …).
Why it matters
The output compiles, but it doesn't match the property form. That breaks golden-file comparisons, and multi-line switch, collection-expression and initialiser bodies on methods and operators look malformed in generated code.
Suggested fix and acceptance criteria
In WriteBody, when the first non-blank line starts with => (after trimming leading whitespace), write " " + firstLine on the declaration line and splice the remaining lines at the current indent, as WriteExpressionBody does for continuation lines. Leading blank lines are skipped, as they already are.
Braced bodies (first line {) keep their current layout.
Constructors with an initialiser (: this(...) on its own indented line) keep the arrow on the initialiser line.
Tests: a nested method, a constructor and an operator with a multi-line => body produce the same layout as a PropertyTemplate.ExpressionBodyFactory with the same expression.
Open PR #161 also edits WriteBody (comment-only bodies), so the two changes will need coordinating.
Priority: Low. The output compiles, so nothing is broken. The layout is wrong and doesn't match the property form, which matters for golden-file comparisons and readability.
Activity
matt-edmondson commentedon Nov 2, 2026
Triage
TemplateRendering.WriteBodyinCodeBlocker/Templates/TemplateRendering.cs, whichMethodTemplate,ConstructorTemplateandOperatorTemplateall use. Reuse the continuation-line handling fromWriteExpressionBody(Multi-line expression bodies (ExpressionBodyFactory / AccessorKind.Expression) lose indentation on every line after the first #112/Keep the enclosing indent on multi-line expression bodies #114).WriteBody, for A method or constructor whose BodyFactory writes only comments or #pragma lines gets no body, so the output fails with CS1002 #157) and Keep a preprocessor directive in an expression body off the arrow line and out of the semicolon [patch] #162 (preprocessor directives in an expression body). Land this after both and rebase onto them, so the=>detection respects their handling of comment and directive lines.=>and keep it on the declaration line. Add tests that compare the method, constructor (with and without: this(...)) and operator output againstPropertyTemplate.ExpressionBodyFactory.Generated by Claude Code