em 04: codegen — generate the refactoring, round-trip check, unified-diff preview
RefactoringGenerator emits the new method (promoted signature, parameter
names = source symbol names) plus the rewritten call site for every
em 02/03 bucket shape (return slot declared inside/outside, tuple
deconstruction, ref write-back, return-call when the selection ends a
non-void method) and refuses loudly where v1 cannot be sound (composite
trailing return, return not ending the method).
The transformed tree must compile with zero diagnostics (the yak's
round-trip check, enforced in both the CLI and the tests).
Findings that shaped the implementation, all enforced by tests:
- NormalizeWhitespace on the WHOLE root corrupts doc-comment trivia so
Roslyn's XML-doc writer fails with CS1569 ('count (-3) must be
non-negative') — and it would reformat the entire file, killing the
diff. Only generated nodes are normalized; original trivia is kept and
indentation/end-of-line is grafted onto the inserted statements/method.
- ParseTypeName("void") yields a node rejected as a method return type
(CS1547) — a void signature must be PredefinedType(Token(VoidKeyword)).
- NormalizeWhitespace drops the space after the contextual keyword 'var'
before '(' — the parsed 'var (x, y) = ...' deconstruction skeleton is
used verbatim; builder-made statements are normalized.
- The new method is normalized inside a throwaway class wrapper: the
normalizer computes indentation from nesting depth, and a bare method
has none.
v1 decision: print a unified-diff PREVIEW to stdout (hand-rolled LCS
unified diff), never an in-place rewrite. Also fixes the hunk header
off-by-one from the phantom trailing empty line of Split('\n').
This commit is contained in:
@@ -115,4 +115,37 @@ public class Demo
|
||||
{
|
||||
return (double)total / _seed;
|
||||
}
|
||||
|
||||
/// <summary>Bucket (em 04 codegen): a local DECLARED BEFORE the selection
|
||||
/// that the selection writes and the tail reads — the promoted signature
|
||||
/// keeps it as a <c>ref</c> parameter (the write-back already flows the
|
||||
/// value out, so the result is not re-returned; void) and the call site
|
||||
/// is a plain call, no assignment: <c>Extract(ref acc, n);</c>.</summary>
|
||||
public int Accumulate(int n)
|
||||
{
|
||||
int acc = 0;
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
acc += i;
|
||||
}
|
||||
|
||||
return acc * 2;
|
||||
}
|
||||
|
||||
/// <summary>Bucket (em 04 codegen): TWO locals declared inside, both
|
||||
/// written inside and read after — the promoted signature returns a
|
||||
/// tuple <c>(int, int)</c> and the call site deconstructs it:
|
||||
/// <c>var (x, y) = Extract(n);</c>.</summary>
|
||||
public (int, int) Pairwise(int n)
|
||||
{
|
||||
int x = 0;
|
||||
int y = 1;
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
x += i;
|
||||
y += i * 2;
|
||||
}
|
||||
|
||||
return (x + y, x - y);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user