- tools/ExtractMethod: net10.0 console app (Microsoft.CodeAnalysis.CSharp 5.9.0, pinned latest stable). CLI: <file.cs> <startLine> <endLine>. Parses the file, builds a scratch compilation with refs from TRUSTED_PLATFORM_ASSEMBLIES, and reports how many whole statements the line range covers (clean error otherwise; exit codes: 0 ok, 1 resolution error, 2 usage). - Tooling/CompilationLoader: shared parse + compilation path for CLI and tests (tests exercise the exact loading path the CLI uses). - Tooling/SelectionResolver: snaps a 1-based inclusive line range to whole statements in the enclosing method body block; boundary checks never split a statement; nested/blank-line ranges handled cleanly. - tests/: ExtractMethod/Fixtures/Demo.cs checked-in fixture exercising every bucket of the parent spec (read-only local, written+read-later return, scratch local, param read, field+property access, indexer + method invocation, multi-statement range incl. a for-loop); excluded from project compilation, copied to output as data. - Tests: Demo.cs compiles with no diagnostics; range 68..72 resolves to 2 statements (LocalDeclarationStatement, ForStatement); AnalyzeDataFlow succeeds on the fixture's for-loop node; mid-statement range fails cleanly. 30/30 green.
57 lines
2.4 KiB
C#
57 lines
2.4 KiB
C#
using Microsoft.CodeAnalysis;
|
|
using Microsoft.CodeAnalysis.CSharp;
|
|
|
|
namespace ExtractMethod.Tooling;
|
|
|
|
/// <summary>
|
|
/// Turns a plain .cs file into a Roslyn <see cref="CSharpCompilation"/> that a
|
|
/// semantic model can be queried against.
|
|
///
|
|
/// Shared by the CLI (Program.cs) and the tests so both exercise the same
|
|
/// loading path — the tests should not re-implement this, or they would be
|
|
/// testing their own assumptions instead of the tool.
|
|
/// </summary>
|
|
public static class CompilationLoader
|
|
{
|
|
/// <summary>
|
|
/// Parse a file into a <see cref="SyntaxTree"/> using the latest language
|
|
/// version. Nothing here is project-specific: no .sln, no .csproj, no
|
|
/// generated files — the tool is a micro-tool that runs on a single file.
|
|
/// </summary>
|
|
public static SyntaxTree ParseFile(string path)
|
|
{
|
|
var text = File.ReadAllText(Path.GetFullPath(path));
|
|
return CSharpSyntaxTree.ParseText(
|
|
text,
|
|
path: path,
|
|
options: CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.Latest));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Build a scratch compilation over <paramref name="tree"/>.
|
|
///
|
|
/// WHY <c>TRUSTED_PLATFORM_ASSEMBLIES</c>: it is the runtime-resolved list
|
|
/// of the actual BCL assemblies this process (net10.0) runs on, e.g.
|
|
/// System.Private.CoreLib, System.Runtime, System.Console. Referencing
|
|
/// them means an arbitrary fixture can bind List<T>, string, and the
|
|
/// rest of the BCL without any NuGet/EF/SQLite haul. (A single
|
|
/// typeof(object) reference is NOT enough on modern .NET — that only pulls
|
|
/// in the core library, and Console/GC/enums etc. fail to bind.)
|
|
/// </summary>
|
|
public static CSharpCompilation CreateCompilation(SyntaxTree tree, string assemblyName)
|
|
{
|
|
var refs = ((string)AppContext.GetData("TRUSTED_PLATFORM_ASSEMBLIES")!)
|
|
.Split(Path.PathSeparator)
|
|
.Select(p => (MetadataReference)MetadataReference.CreateFromFile(p));
|
|
|
|
return CSharpCompilation.Create(
|
|
assemblyName,
|
|
new[] { tree },
|
|
refs,
|
|
new CSharpCompilationOptions(
|
|
OutputKind.DynamicallyLinkedLibrary,
|
|
// Match the repo's net10.0 projects so the fixture's nullable
|
|
// annotations compile without warnings.
|
|
nullableContextOptions: NullableContextOptions.Enable));
|
|
}
|
|
} |