// Demo fixture for the extract-method micro-tool (tools/ExtractMethod).
//
// This file is DATA, not project source: the test project excludes it from
// compilation (see BeforeAfter.Tests.csproj) and runs Roslyn over its raw
// text, so the tool sees exactly what is checked in here. It uses explicit
// usings because the scratch compilation has no implicit usings.
//
// Bucket map (the classification yak 02 works from):
// bucket where example
// local, read-only (param) ScoreReads seed, score
// written + read-later (return) Summarize, Heaviest total, message, best
// scratch local (local) Summarize for-loop i
// enclosing-method param (param) ScoreReads, Summarize bonus, limit
// field access (extract-first) ScoreReads _seed (optional)
// property access (extract-first) Summarize Scale (optional)
// indexer access (extract-first) Heaviest widgets[i]
// method invocation (extract-first, flagged) Heaviest best.Bigger(...)
// multi-statement range incl. for Summarize total + for-loop
//
// Tests pin EXACT line numbers of the statements they select. Keep the
// formatting stable; when a line must change, update DemoFixtureTests too.
using System.Collections.Generic;
namespace BeforeAfter.Tests.ExtractMethod.Fixtures;
///
/// Small first-class citizen of the extract-method tool: every method below
/// shows one or more of the classification "buckets" the tool must report.
///
public class Demo
{
// Own-class state: reading it from a selection is "extract-first optional"
// (a same-class extracted method can still see these fields). Initialized
// here so the fixture compiles with zero diagnostics (CS0649 otherwise).
private int _seed = 5;
// Own-class property: like a field, accessible from a same-class method,
// so hoisting it is optional in the report.
public int Scale { get; set; } = 1;
/// Small local type so the scratch compilation binds.
public sealed record Widget(int Weight, int Count, string Label)
{
/// Instance method used to exercise the invocation bucket.
public Widget Bigger(Widget other) =>
Weight >= other.Weight ? this : other;
}
///
/// Bucket: enclosing-method parameter read (bonus => param), local
/// read-only (seed, score => param), own-class field access
/// (_seed => extract-first, optional). Ends with a return expression.
///
public int ScoreReads(int bonus)
{
int seed = _seed;
int score = seed * 2;
return score + bonus;
}
///
/// Bucket: written + read-later locals (total, message => return),
/// scratch local (i => local), own-class property access (Scale =>
/// extract-first optional), multi-statement range incl. a for-loop.
///
public string Summarize(int limit)
{
int total = 0;
for (int i = 0; i < limit; i++)
{
total += i;
}
int scaled = total * Scale;
string message = "sum=" + scaled;
return message;
}
///
/// Bucket: indexer access (widgets[i] on List<T> => extract-first),
/// method invocation (Bigger => extract-first, flagged because hoisting
/// changes how often it is evaluated), local written + read-later
/// (best => return).
///
public Widget Heaviest(List widgets, int count)
{
Widget best = widgets[0];
for (int i = 1; i < count; i++)
{
best = best.Bigger(widgets[i]);
}
return best;
}
}