This is a refactoring tool, to aid translation of code to idiomatic Rust. The benefit of using this tool over "raw" LLM is that
- Synchronized edits will be made across files, informed by static analysis - More precise and avoids LLMs not wanting to make "breaking edits"
- Less token usage because the tool is tailored for the purpose
The CLI includes these subcommands: c-string-stats, constants-to-enum,
constants-to-enum-csv, constants-to-enum-stats, enum-hoist,
enum-hoist-stats, extract-struct-module, inline, to-oop, to-oop-stats, out-param-stats,
module-coupling-stats, module-size-check, remove-function, return-stats, simplify-wrapper, struct-module-stats,
and visibility-stats. Run
rust-refactor <command> --help for all options.
module-coupling-stats builds a semantic, source-file-owned dependency graph before a module
refactor. Rust-analyzer resolves each declared symbol's consumers, so same-named symbols are not
merged. The versioned JSON report contains incoming and outgoing symbol dependencies, reference
weights, private boundary accesses, restricted-visibility bridge symbols, compatibility glob
imports, a deterministic weighted coupling matrix, and strongly connected components as cycle and
cohesive-cluster hints.
./target/debug/rust-refactor module-coupling-stats \
--manifest-path /path/to/Cargo.toml --format jsonMatrix rows and columns use weightedCouplingMatrix.moduleOrder; a cell is the number of resolved
references from the row module to the column module. bridgeCount counts distinct
consumer/owner/symbol crossings for non-pub declarations, while crossModulePrivateAccesses is
the stricter subset with no explicit visibility. Output arrays are path/name sorted and stable
across runs.
struct-module-stats measures how much code belongs to a selected struct before any source is
moved. It reports the declaration, inherent impls, whole trait impls, free functions that reference
the type, several candidate LOC totals, and references that would cross the proposed module
boundary.
./target/debug/rust-refactor struct-module-stats \
--manifest-path /path/to/Cargo.toml \
--selection src/lib.rs:42:12 --format jsonWhen the struct name is unique in the workspace, discovery uses a fast syntax reference index and
labels the result workspace_unique_syntax. --semantic forces rust-analyzer reference validation;
ambiguous type names use it automatically. Pass --target wasm32-unknown-unknown (or another target)
when the selected module is cfg-gated. Executable extraction plans will always receive semantic
validation even if their initial discovery report used the fast path.
Apply the reviewed struct and all of its same-file inherent and trait impls as a direct child module:
./target/debug/rust-refactor extract-struct-module \
--manifest-path /path/to/Cargo.toml \
--selection src/lib.rs:42:12 \
--destination src/widget.rs --dry-run --format json
./target/debug/rust-refactor extract-struct-module \
--manifest-path /path/to/Cargo.toml \
--selection src/lib.rs:42:12 \
--destination src/widget.rs --write --format jsonWrites are hash-guarded transactions: the tool creates the child, edits the parent, formats both,
and checks the nearest owning crate. A failed format or check restores edited/deleted files and
removes created files. Private members become pub(super) only where the child boundary requires
the former parent to retain its old access. Location-sensitive macros are refused. For cfg-gated
code, pass its compilation target with --target; verification runs from the subject package so its
Rust toolchain and installed targets are used rather than rust-refactor's own toolchain.
See the module-refactoring workflow for the reviewable sequence of independent discovery, method conversion, extraction, and verification commands.
apply-batch commits the output of several reviewed extraction plans as one transaction. This is
the execution format for batching extract-items-module, extract-impl-members,
extract-inline-module, extract-struct-module, and minimize-parent-imports work without
formatting and compiling after every individual extraction. The JSON schema is versioned and
strict; paths are relative to the Cargo workspace, byte offsets address the original UTF-8 file,
and every edited or deleted source has an expected SHA-256 hash.
{
"schema": "rust-refactor.batch/v1",
"workspaceManifestSha256": "<sha256 of Cargo.toml>",
"reviewedCommands": ["extractStructModule", "minimizeParentImports"],
"targets": [],
"allFeatures": false,
"checkTests": true,
"rustfmt": true,
"operations": [
{
"kind": "edit",
"path": "src/lib.rs",
"expectedSha256": "<sha256 of src/lib.rs>",
"edits": [
{ "startByte": 120, "endByte": 245, "replacement": "mod widget;\n" }
]
},
{
"kind": "create",
"path": "src/widget.rs",
"contents": "pub(crate) struct Widget;\n"
}
]
}Preview and apply the same reviewed manifest with:
rust-refactor apply-batch --manifest-path /path/to/Cargo.toml \
--batch /path/to/refactor-batch.json --dry-run --format json
rust-refactor apply-batch --manifest-path /path/to/Cargo.toml \
--batch /path/to/refactor-batch.json --write --format jsonBefore writing, the command preflights the complete operation set: workspace and source hashes,
path confinement, create collisions, edit ranges, and overlaps. Every writing refactor then stores
original bytes in .rust-refactor-transaction-backups, fsyncs a durable
.rust-refactor-transaction.json marker, applies its destinations, runs targeted rustfmt, and
verifies the requested compiler profiles. A formatting or compiler failure restores all
edited/deleted files and removes every created file. If the process is interrupted, the next
writing refactor first restores the exact snapshot. Recovery refuses to overwrite a path changed
by the user after interruption and retains the marker/backups for inspection. The journal is
removed durably before committed backup files are discarded, so a crash cannot leave an
unrecoverable half-transaction.
extract-impl-members moves selected complete functions, constants, or type aliases from one
top-level inherent impl into a partial impl in a direct child module. Repeat --selection; all
members in one invocation must belong to the same impl. Trait impls are indivisible and are
refused. The new partial impl preserves the original generics and where clause.
./target/debug/rust-refactor extract-impl-members \
--manifest-path /path/to/Cargo.toml \
--selection src/lib.rs:120:8 \
--selection src/lib.rs:148:8 \
--destination src/widget/rendering.rs --dry-run --format jsonA private moved member is widened only to pub(super) when syntax evidence finds a former-parent
consumer outside the selected group. Writes use the same hash-guarded transaction, targeted
rustfmt, owning-crate check, and rollback as whole-struct extraction. Location-sensitive macros,
macro-generated associated items, nested impls, and partial trait impls are refused.
visibility-stats resolves references to explicitly visible functions, types, modules, constants,
and fields and reports the narrowest scope proven by the current workspace. Restrict large runs to
one or more files. The report is conservative: public library APIs, public re-exports, cfg-dependent
items, trait surfaces, exported symbols, and foreign-ABI functions remain uncertain unless a
workspace consumer proves that pub is required.
./target/debug/rust-refactor visibility-stats \
--manifest-path /path/to/Cargo.toml \
--file crate/src/store.rs --format jsonThe default uses a fast workspace syntax index and reports workspaceCandidateVisibility; it is a
ranking aid, not proof. Add --semantic for rust-analyzer-resolved references and a
narrowestProvenVisibility result. Semantic mode is deliberately opt-in because a reference search
per item can be expensive in a large crate.
module_private_candidate means every resolved reference remains in the defining module;
crate_only_candidate means references cross a module boundary but not a crate boundary. The
stats command intentionally reports rather than edits. To apply every semantically proven reduction
in reviewed files as one compiler-verified transaction, use:
./target/debug/rust-refactor reduce-visibility \
--manifest-path /path/to/Cargo.toml \
--file crate/src/store.rs --dry-run --format json
./target/debug/rust-refactor reduce-visibility \
--manifest-path /path/to/Cargo.toml \
--file crate/src/store.rs --write --target wasm32-unknown-unknownreduce-visibility always performs semantic reference resolution, skips uncertain/library-public,
re-exported, cfg, trait, FFI, and exported surfaces, formats the touched files, and checks the host
plus every requested target once for each package which owns a touched file. Unrelated workspace
members are not rebuilt. Any compiler failure in any owning package rolls the entire reduction set
back.
module-coupling-stats performs the same kind of semantic reference lookup for every declaration
in the workspace. Large applications can take minutes; it reports reference-resolution progress to
stderr every 250 declarations while reserving stdout for the final text/JSON report.
inline finds all free functions annotated with #[doinline] or
#[rust_refactor::inline] in the Cargo workspace, replaces their supported
call sites with the function body, and removes the definitions. There is no
per-function selection flag: every annotated function is considered in one
run. For a compilable source file, the #[doinline] marker can be used with
#![allow(unused_attributes)].
#![allow(unused_attributes)]
#[doinline]
fn double(x: i32) -> i32 { x * 2 }./target/debug/rust-refactor inline \
--manifest-path /path/to/Cargo.toml --dry-run
./target/debug/rust-refactor inline \
--manifest-path /path/to/Cargo.toml --write --check--dry-run prints the planned edits without writing. --write applies them;
add --check to run cargo fmt and cargo check, or --test to also run
cargo test. Verification failure restores the original files unless
--keep-broken is set. --all-features and --target configure verification.
The inliner supports a limited subset of free functions and calls. It reports
unsupported annotated functions and references as errors; review the dry-run
diagnostics before writing.
Its to-oop command moves a free function whose first parameter is
T, &T, or &mut T into an inherent impl T, changes the parameter to
self, &self, or &mut self, and updates call sites. It either
applies the complete plan or refuses it with a diagnostic. Normal-mode
--write formats touched files and runs cargo check, restoring those files
if verification fails. Fast-mode --write runs cargo check with --check.
Public functions are moved too; this changes their free-function API.
Build from this repository with cargo build --locked. Use --format json
when an LLM calls the tool: stdout then contains status, targets, edits,
and diagnostics. Exit code 0 means the plan or write succeeded, 3 means the
refactor was safely refused, and 1 means an operational or verification error.
--dry-run validates the planned edits and leaves the workspace untouched.
For very large workspaces, --fast plans from parsed source without loading
rust-analyzer. It requires the selected free-function name to be unique in the
workspace. The preview applies edits in memory and parses touched files.
--write --fast backs up and formats only touched files, then parses them;
add --check to run cargo check. Failed writes restore those files.
Both modes refuse a selected function used as a callback or other function
value, since that reference cannot become a method call automatically.
Fast mode also scans macro arguments for direct calls, such as
assert_eq!(shift(&p, 2), 5), and rewrites them to method calls. A function
value inside a macro is refused.
Use to-oop-stats below to obtain a current FILE:LINE:COLUMN selection.
For one function:
./target/debug/rust-refactor to-oop \
--manifest-path /path/to/Cargo.toml \
--selection src/lib.rs:42:8 --dry-run --format json
./target/debug/rust-refactor to-oop \
--manifest-path /path/to/Cargo.toml \
--selection src/lib.rs:42:8 --write --format jsonThe tool has no coordination with concurrent editors. Keep other writers away
from files in the plan until the write completes. It currently requires the
struct and selected function in the same module. Optional receivers such as
Option<&T> need a separate source refactor to handle the None branch.
One invocation can refactor several independent functions. For functions in
one file with names starting at the same column, repeat --line:
./target/debug/rust-refactor to-oop --manifest-path /path/to/Cargo.toml \
--file src/lib.rs --line 12 --line 30 --column 4 --dry-run --format jsonFor different files or columns, repeat --selection FILE:LINE:COLUMN. A batch
uses one workspace analysis and one combined validation. If any selection
fails, edits overlap, or verification fails, the whole batch is refused or
rolled back. Functions in one batch currently need distinct names. When
selected functions call one another, convert the called functions first;
then refresh line numbers and select their callers.
Methods for one struct share a single inherent impl block. If one already
exists in the same module, the tool appends methods to it. Simple borrowed
receiver expressions at call sites become direct method calls, such as
shift(&p, 2) becoming p.shift(2); these formatting steps are automatic.
to-oop-stats scans the Cargo workspace without loading rust-analyzer and
groups free functions by the struct named in their first parameter. Groups
are sorted by function count. The text table and JSON include each function's
FILE:LINE:COLUMN selection; JSON also reports whether the struct is local
and whether the receiver is direct or optional. selectable_count counts
direct receivers with a struct in the same module; each candidate can still
be refused during planning.
./target/debug/rust-refactor to-oop-stats \
--manifest-path /path/to/Cargo.toml --format json
./target/debug/rust-refactor to-oop-stats \
--manifest-path /path/to/Cargo.toml --struct WidgetTo select every syntactically direct free function for one struct in a single
batch, use to-oop --struct Widget --dry-run --format json. Optional receivers
are listed in stats but excluded from this selection. An unsupported function
or conflicting edit refuses the whole batch. For a smaller batch, use the
reported selection values with repeated --selection arguments. The tool
does not generate forwarding wrappers.
A large translation case is documented in the imod case study.
return-stats scans function bodies without loading rust-analyzer. It reports
explicit return expressions and final expressions, including the individual
outcomes of if, else if, and match. A negative integer return suggests a
Result rewrite. A null pointer return, including null, null_mut, and a
zero-to-pointer cast, suggests an Option rewrite. Simple integer constants
are resolved when their value is unambiguous in the file or workspace. An
obvious cmp or compare function returning exactly -1, 0, and 1 is
marked ordered_comparison rather than proposed as a Result conversion.
Use CSV as the review table for another LLM:
./target/debug/rust-refactor return-stats \
--manifest-path /path/to/Cargo.toml --format csv > returns.csv
./target/debug/rust-refactor return-stats \
--manifest-path /path/to/Cargo.toml --format csv --candidates-onlyEach row identifies the function and source location, function kind,
visibility, declared return type, suggested Rust return family, confidence,
and reason. It lists known values, resolved negative sentinels, null forms,
unknown expressions, the number of return sites, and LINE:COLUMN:VALUE
evidence. The complete table includes functions without a suggestion so an
LLM can audit missed conventions; --candidates-only keeps only proposed
Result and Option rewrites. JSON contains the same fields and aggregate
counts. This command only discovers candidates and does not edit source.
The analysis deliberately leaves arbitrary calls and calculations in the
unknown_return_values column. It does not infer values through control flow
or resolve ambiguous constants. Those rows remain useful evidence without
turning an uncertain expression into an automatic recommendation.
out-param-stats finds functions with one or more &mut T parameters that
are only used as pure assignment destinations. Definite writes include
*output = value, output.field = value, and tuple assignments containing
those forms. A parameter must have at least one write. Indexed destinations
such as output[index] = value are excluded because they usually fill reusable
caller-owned storage rather than return one value.
./target/debug/rust-refactor out-param-stats \
--manifest-path /path/to/Cargo.toml --format csv > output-parameters.csvThe CSV has one row per function and includes its file and source location,
kind, visibility, output parameter names and types, write counts, and source
evidence. Writes are classified as direct or field. Field writes include a
review note that the parameter may intentionally preserve allocation or
existing state and may be worth keeping. JSON contains the same data as
structured parameter lists. Text is a compact terminal table.
The scanner is conservative. It omits a parameter if it is read, used in a compound assignment, passed to another function, mentioned in a macro, reassigned as a reference binding, shadowed, or used in a form whose effect is uncertain. A write-only result is therefore suitable for LLM review as a candidate for conversion into a returned value. This command does not edit source.
c-string-stats performs a fast syntax scan for function parameters, return
slots, struct fields, and statics whose types contain c_char, CStr, or
CString. It connects parameters through uniquely resolved direct calls, so
rows sharing component_id describe a cross-file signature component that
should be reviewed and migrated together.
./target/debug/rust-refactor c-string-stats \
--manifest-path /path/to/Cargo.toml --format csv > c-strings.csvThe CSV records the current type, inferred role, nullability, length and NUL
policy, observed string and ownership operations, callers, FFI status,
proposed type, confidence, blockers, and evidence. Its empty selected column
is intended for LLM review. Raw pointers receive a proposal only when the scan
finds string evidence locally or in a connected caller or callee. Exported and
extern functions, repr(C) fields, callback signatures, ambiguous mutable
buffers, pointer lists, and reallocating buffers are marked as boundaries or
blockers instead of being presented as direct rewrites.
This command does not edit source. The staged application design and the IMOD history examples used to derive its rules are in C_STRINGS.md.
Start with constants-to-enum-stats. It builds sets of constants from usage:
patterns of one match, comparisons with one subject, assignments to one
destination, returns from one function, and a fixed parameter of one uniquely
resolved workspace function. Generic constructors and wrappers such as
Some, Ok, Box::new, and Vec::from do not contribute call evidence.
Sets that overlap are merged transitively. This recovers default values,
result codes, and constants used as outputs as well as input discriminants.
Locals and parameters are keyed by their declarations, and fields include the
receiver identity. Dispatcher observations containing several complete name
prefix families are split before merging.
./target/debug/rust-refactor constants-to-enum-stats \
--manifest-path /path/to/Cargo.toml --min-constants 3 --format jsonCandidates are sorted by number of distinct constants. JSON reports the
subject expression and containing function, each constant's definition and
raw value, plus evidence locations. A match evidence selection can be passed
to constants-to-enum --match after checking that its constants are the exact
family being converted. Name resolution in this fast discovery pass prefers a
same-file definition and otherwise accepts a name with one definition in the
workspace. The conversion command performs the stricter semantic checks.
For an editable workspace inventory, request CSV and redirect stdout:
./target/debug/rust-refactor constants-to-enum-stats \
--manifest-path /path/to/Cargo.toml --format csv > constants.csvThe CSV has one row for every module, associated, trait, and local constant.
proposed_enum_group is empty when usage did not assign the constant to a
numeric enum candidate. Assigned rows also contain proposed enum and variant
names, subjects, match selections, and all evidence selections. Constants with
shift or bitwise initializers, constants used in bitwise expressions, and
constants used as ordering bounds with <, >, <=, or >= are removed
before candidate sets are merged. Their unassigned_reason is bitwise_use or
ordering_comparison. Thus one numeric bound cannot pull an otherwise valid
enum family into a limit group. Groups dominated by size, count, limit, or mask
names are also omitted. Unassigned numeric constants can have weak suggestions in
possible_enum_groups, based on membership in a detected name prefix; these
suggestions never merge sets automatically. unassigned_reason distinguishes
unsupported types, non-module constants, and constants with no strong set.
For equal raw values within one lexical name family, one row is canonical and
later rows name it in alias_of; those rows intentionally share the canonical
variant. An unassigned sibling is merged automatically when it is the only
equal-value candidate for an enum group of at least five constants and is
declared within five lines of the canonical constant. Other equal-value rows
name the candidate in possible_alias_of; an LLM can accept one by copying the
group and variant and moving the suggestion to alias_of. This keeps parallel
numeric domains that reuse 0, 1, 2 from being merged as aliases.
Repeated declarations are reported separately from value aliases. Rows with
the same constant name, type, and initializer receive duplicate_kind=exact;
integer literal spellings that normalize to the same value, such as 2,
0x2, and 2 as i32, receive duplicate_kind=normalized. Compatible rows
share a duplicate_group and a canonical_candidate source location. The
candidate favors public module constants, files containing more declarations
from the same name family, and declarations with stronger usage evidence. It
is a review hint rather than an instruction to delete the other declarations.
duplicate_name_conflict=true warns that the same name also has another type
or normalized value; an incompatible singleton is marked conflict. Constants
with different names are never classified as duplicate declarations merely
because their values are equal. Review duplicate families before enum groups,
because replacing copied declarations with one shared definition can turn
several file-local enum candidates into one workspace-wide family.
An LLM can edit the group, kind, enum, variant, and selection cells, then apply one reviewed group directly:
./target/debug/rust-refactor constants-to-enum-csv \
--manifest-path /path/to/Cargo.toml \
--table constants.csv --group group_001 --dry-run --format jsonReview the plan, then replace --dry-run with --write. The importer requires
one definition file, one enum name, nonempty variants, proposed_group_kind
set to enum, and at least one match or equality-comparison selection. It
validates that every alias_of row points to a selected canonical row with
the same raw type, value, and variant. It
refuses discovery-only groups supported solely by assignment, return, or
argument evidence because the current transform cannot yet introduce enum
types at those boundaries.
The importer also refuses plausible unselected siblings from
possible_enum_groups. Add such a row to the reviewed group or clear that
cell to record an explicit decision that it does not belong.
Use --enum-path when selected matches are outside the definition module.
Empty group cells are intentional and remain available for classification.
constants-to-enum turns an explicitly selected family of integer constants
into a numeric enum and converts selected match expressions to use it. Raw
function parameters and struct fields remain integers in this first stage.
The original constants become aliases such as
MODE_BYTE: i32 = Mode::Byte.to_raw(), so existing raw boundaries continue to
compile while selected matches use Mode::from_raw(value).
./target/debug/rust-refactor constants-to-enum \
--manifest-path /path/to/Cargo.toml \
--file src/lib.rs --enum-name Mode \
--constant MODE_BYTE=Byte \
--constant MODE_SHORT=Short \
--match src/lib.rs:40:5 \
--dry-run --format jsonRepeat --constant CONSTANT=Variant to define exact membership and spelling.
Repeat --match FILE:LINE:COLUMN to convert
several matches atomically. Use --enum-path crate::module::Mode when a match
is in another module, and --visibility private|pub-crate|pub when the selected
constants do not share a usable visibility. Selected constants need one
primitive integer type and literal values. Equal values are supported when
their --constant specifications use the same variant, preserving both
constant names as aliases of one enum variant. A selected match must use
only those constants plus a _ arm. Bit masks are outside this command's
scope. --write formats touched files, runs cargo check, and restores them
on failure. See the design and staged migration plan.
The follow-on parameter and struct-field propagation design is documented in
ENUM_HOISTING.md.
After introducing an enum, find places that repeatedly convert the same raw value:
./target/debug/rust-refactor enum-hoist-stats \
--manifest-path /path/to/Cargo.toml \
--enum-file src/modes.rs --enum-name Mode --format jsonThe report identifies parameters, named fields, locals, and direct function
returns used as from_raw subjects, counts their conversions and references,
and emits source selections. Each reported kind can seed the transform.
Select one or more value flows and preview the complete propagation plan:
./target/debug/rust-refactor enum-hoist \
--manifest-path /path/to/Cargo.toml \
--enum-file src/modes.rs --enum-name Mode \
--enum-path crate::modes::Mode \
--parameter src/worker.rs:40:18 \
--field src/window.rs:12:9 \
--local src/worker.rs:55:9 \
--return src/source.rs:20:8 \
--dry-run --format jsonThe command changes connected raw parameters, named struct fields, function
returns, and simple local bindings to the enum. It updates direct free-function
and method calls, rewrites ordinary struct initializers and assignments,
removes redundant from_raw/to_raw pairs, and places to_raw only at
remaining raw consumers. Compatibility constants and unique matching integer
literals become enum variants. An existing
let Some(value) = Mode::from_raw(raw) else { ... }; can remain as the single
raw entry boundary while downstream calls become typed.
Direct calls nested in expression macros such as assert! are included in the
value flow. Other opaque macro references are refused when the tool cannot
classify them.
Propagation uses a work queue to a fixpoint: each selected or discovered
parameter, field, local, or return value adds its producer places and consumer
places until no new typed place is found. Cycles and multi-function chains are
planned as one closure. A constructor parameter or local stored in a named
field automatically brings that field into the closure; both Struct { field }
shorthand and Struct { field: value } are supported. Locals are discovered
from simple identifier bindings; function returns support direct tail
expressions and explicit return expressions. Unsupported destructuring,
branch-valued expressions, and async returns refuse the atomic plan.
The plan is atomic. It refuses function-value references, unknown argument or
field producers, compound field writes, unresolved macro references, explicit
observation of None in a converted match, conflicting edits, and plans that
do not reduce the number of conversions. --write snapshots touched files,
runs rustfmt and cargo check, and restores every file when verification
fails. No forwarding wrappers are generated.
Workspace syntax, definitions, references, and call sites are indexed once per
invocation. Fixpoint propagation then examines references with matching names
and the connected value-flow edges rather than rescanning the workspace for
each discovered place. Set RUST_REFACTOR_TIMING=1 to print phase timings to
standard error when diagnosing a slow project.
Compatibility constants are temporary migration names. Remove them after
hoisting, replacing every remaining raw use with Enum::Variant.to_raw():
./target/debug/rust-refactor enum-hoist \
--manifest-path /path/to/Cargo.toml \
--enum-file src/modes.rs --enum-name Mode \
--remove-aliases --write --format jsonThe cleanup also rewrites grouped imports. Batch several enums through one
workspace analysis by repeating --remove-aliases-from FILE=ENUM; the primary
enum is selected by --enum-file, --enum-name, and --remove-aliases. Alias
cleanup can run without a parameter, field, local, or return seed.
Use repeated --comparison FILE:LINE:COLUMN selections for == and !=
expressions. A selected raw == MODE_BYTE becomes
Mode::from_raw(raw) == Some(Mode::Byte). Match and comparison selections can
be combined in one transaction.
remove-function deletes a selected free function, direct calls used as
statements, and simple imports of that function. It is useful for no-op
translation artifacts. Select the function name by its
current one-based location:
./target/debug/rust-refactor remove-function \
--manifest-path /path/to/Cargo.toml \
--file src/lib.rs --line 42 --column 8 --dry-run --format jsonReview the JSON edits, then use --write in place of --dry-run. A write
formats edited files and runs cargo check; failed verification restores
their original contents. The command refuses calls whose result is used,
function pointers/callbacks, and references it cannot remove. It also refuses
names shared by multiple workspace functions. These limits prevent a partial
deletion; the JSON diagnostics field explains a refusal.
simplify-wrapper recognizes a selected free function whose only operation
is drop on its single owned parameter. It replaces resolved calls with
::core::mem::drop(argument), removes simple imports, and deletes the wrapper.
Selection is by source position; the function's name does not determine whether
it matches. Other wrapper shapes are currently refused. For large workspaces,
--fast scans source without loading rust-analyzer; it requires the selected
name to be unique among workspace functions.
./target/debug/rust-refactor simplify-wrapper \
--manifest-path /path/to/Cargo.toml \
--file src/lib.rs --line 42 --column 8 --dry-run --format jsonReview the JSON plan, then replace --dry-run with --write. A write formats
touched files and runs cargo check, restoring those files if verification
fails. Function-value references and calls the tool cannot rewrite cause a
refusal with exit code 3. Unqualified drop must resolve to the standard
function or be unshadowed in the defining source file.