using ExtractMethod.Tooling; using Microsoft.CodeAnalysis; // CLIs are boring on purpose: argument parsing and printing live here, all // Roslyn logic lives in Tooling/ so the tests can drive it directly. string usage = "usage: ExtractMethod (1-based, inclusive)"; if (args.Length != 3) { Console.Error.WriteLine(usage); return 2; } string file = Path.GetFullPath(args[0]); if (!File.Exists(file)) { Console.Error.WriteLine($"error: file not found: {file}"); Console.Error.WriteLine(usage); return 2; } if (!int.TryParse(args[1], out int startLine) || !int.TryParse(args[2], out int endLine)) { Console.Error.WriteLine($"error: line numbers must be integers"); Console.Error.WriteLine(usage); return 2; } // 1. parse the file var tree = CompilationLoader.ParseFile(file); // 2. build the scratch compilation (refs from TRUSTED_PLATFORM_ASSEMBLIES) var compilation = CompilationLoader.CreateCompilation(tree, Path.GetFileNameWithoutExtension(file)); if (compilation.GetDiagnostics().Any(d => d.Severity == DiagnosticSeverity.Error)) { Console.Error.WriteLine("warning: the file does not compile cleanly under a plain Roslyn compilation; reporting syntax-level resolution only"); } // 3. snap the range to whole statements, report cleanly otherwise var report = SelectionResolver.Resolve(tree, startLine, endLine); if (!report.Succeeded) { Console.Error.WriteLine($"error: {report.Error}"); return SelectionResolver.ExitError; } Console.WriteLine( $"{report.Count} statement(s) selected, lines {report.StartLine}..{report.EndLine} " + $"in {report.Method?.Identifier.ValueText}(): " + string.Join(", ", report.Kinds)); // 4. classify the data flow into the raw buckets (em 02: no pretty report yet) // A classification failure is a semantic resolution error: same exit code as // the resolver, message on stderr, but never a stack trace. ExtractionSuggestion suggestion; try { suggestion = DataFlowClassifier.Classify(compilation.GetSemanticModel(tree), report); } catch (Exception e) when (e is InvalidOperationException or ArgumentException) { Console.Error.WriteLine($"error: data-flow analysis failed: {e.Message}"); return SelectionResolver.ExitError; } foreach (var param in suggestion.Params) { Console.WriteLine($"params: {param.Name} ({param.Type}){(param.ByRef ? " [ref]" : " [in]")}"); } if (suggestion.Params.Count == 0) { Console.WriteLine("params: (none)"); } foreach (var name in suggestion.Returns) { Console.WriteLine($"returns: {name}"); } if (suggestion.Returns.Count == 0) { Console.WriteLine("returns: (none)"); } foreach (var name in suggestion.Locals) { Console.WriteLine($"locals: {name}"); } if (suggestion.Locals.Count == 0) { Console.WriteLine("locals: (none)"); } return 0;