em 02: data-flow classification (params/returns/locals buckets)

- Tooling/DataFlowClassifier: buckets a resolved selection via Roslyn
  DataFlowAnalysis. Selection flow + tail flow (statements AFTER the
  selection in the same block) both use the two-argument AnalyzeDataFlow
  overload on the contiguous run; the em 01 spike verdict is pinned in
  tests — a synthetic BlockSyntax (parent decision #3) throws
  ArgumentException "statements not within tree" and would re-bind
  symbols, breaking the written-inside ∩ read-after identity match.
- Buckets per parent spec as plain-string records: in-params = local +
  parameter reads (filtering the implicit `this`; fields/properties stay
  in the em 03 extract-first bucket), ByRef = reassigned inside via a
  non-declaration write (declaration initializers are not write-backs),
  returns = written ∧ read-after (tail, branch-insensitive
  over-approximation) + trailing `return X;` simple-name candidate,
  locals = written ∧ never read-after.
- CLI now prints the raw bucket dump after the statement count line;
  classification failures exit 1 with a clean message (exit 0/1/2
  contract preserved).
- Tests: 6 new (in-param incl. `this` non-leak, multi-statement
  two-argument path, trailing-return, ref-vs-in differential, extract-first
  non-leak, synthetic-block dead path, single-statement one-argument path);
  shared DemoFixture loader; fixed pre-existing CS8602 in DemoFixtureTests.
  36/36 green.
This commit is contained in:
2026-09-12 15:52:16 +01:00
parent b012d0aaa0
commit 7f0981e012
5 changed files with 542 additions and 11 deletions
@@ -13,16 +13,7 @@ namespace BeforeAfter.Tests.ExtractMethod;
/// </summary>
public class DemoFixtureTests
{
private static readonly string FixturePath =
Path.Combine(AppContext.BaseDirectory, "Fixtures", "Demo.cs");
private static (SyntaxTree Tree, CSharpCompilation Compilation) LoadFixture()
{
Assert.True(File.Exists(FixturePath), $"fixture missing at {FixturePath}");
var tree = CompilationLoader.ParseFile(FixturePath);
var compilation = CompilationLoader.CreateCompilation(tree, "DemoFixture");
return (tree, compilation);
}
private static (SyntaxTree Tree, CSharpCompilation Compilation) LoadFixture() => DemoFixture.Load();
// ---------------------------------------------------------------------
// (a) The fixture is pristine under the scratch compilation: if this
@@ -77,6 +68,9 @@ public class DemoFixtureTests
var dataFlow = compilation.GetSemanticModel(tree).AnalyzeDataFlow(forStatement);
// AnalyzeDataFlow is nullable-annotated in Roslyn 5.x: assert non-null
// so the dereference below is provably safe (and test intent explicit).
Assert.NotNull(dataFlow);
Assert.True(dataFlow.Succeeded);
}