Change Signature
Change signature operations modify function signatures while automatically updating all call sites to match.
Overview
ChangeSignature allows you to:
- Add, remove, or rename parameters
- Reorder parameters
- Change return types
- Add default values for new parameters
All call sites are updated automatically to maintain correctness.
Basic Usage
#![allow(unused)]
fn main() {
use refactor::prelude::*;
// Add a new parameter with a default value
let result = ChangeSignature::for_function("process")
.in_file("src/lib.rs")
.add_parameter("timeout", "Duration", "Duration::from_secs(30)")
.execute()?;
println!("Updated {} call sites", result.call_sites_updated);
}
Adding Parameters
With Default Value
#![allow(unused)]
fn main() {
ChangeSignature::for_function("connect")
.in_file("src/client.rs")
.add_parameter("retry_count", "u32", "3")
.execute()?;
}
Before:
#![allow(unused)]
fn main() {
fn connect(host: &str) -> Result<Connection> { /* ... */ }
// Call sites:
let conn = connect("localhost")?;
}
After:
#![allow(unused)]
fn main() {
fn connect(host: &str, retry_count: u32) -> Result<Connection> { /* ... */ }
// Call sites updated:
let conn = connect("localhost", 3)?;
}
At Specific Position
#![allow(unused)]
fn main() {
ChangeSignature::for_function("create_user")
.in_file("src/users.rs")
.add_parameter_at("email", "String", 1) // After first param
.default_value("String::new()")
.execute()?;
}
Multiple Parameters
#![allow(unused)]
fn main() {
ChangeSignature::for_function("configure")
.in_file("src/config.rs")
.add_parameter("debug", "bool", "false")
.add_parameter("verbose", "bool", "false")
.add_parameter("timeout", "Duration", "Duration::from_secs(60)")
.execute()?;
}
Removing Parameters
#![allow(unused)]
fn main() {
ChangeSignature::for_function("old_api")
.in_file("src/legacy.rs")
.remove_parameter("unused_flag")
.execute()?;
}
Before:
#![allow(unused)]
fn main() {
fn old_api(data: &str, unused_flag: bool) -> String { /* ... */ }
// Call sites:
let result = old_api("input", true);
let result = old_api("other", false);
}
After:
#![allow(unused)]
fn main() {
fn old_api(data: &str) -> String { /* ... */ }
// Call sites updated:
let result = old_api("input");
let result = old_api("other");
}
Renaming Parameters
#![allow(unused)]
fn main() {
ChangeSignature::for_function("process")
.in_file("src/processor.rs")
.rename_parameter("input", "source")
.execute()?;
}
This updates:
- The parameter name in the function definition
- All uses of the parameter within the function body
- Named arguments at call sites (for languages that support them)
Reordering Parameters
#![allow(unused)]
fn main() {
ChangeSignature::for_function("create_user")
.in_file("src/users.rs")
.reorder_parameters(&["name", "email", "role"])
.execute()?;
}
Before:
#![allow(unused)]
fn main() {
fn create_user(role: Role, name: String, email: String) -> User { /* ... */ }
// Call sites:
create_user(Role::Admin, "Alice".into(), "alice@example.com".into())
}
After:
#![allow(unused)]
fn main() {
fn create_user(name: String, email: String, role: Role) -> User { /* ... */ }
// Call sites reordered:
create_user("Alice".into(), "alice@example.com".into(), Role::Admin)
}
Changing Types
#![allow(unused)]
fn main() {
ChangeSignature::for_function("process")
.in_file("src/lib.rs")
.change_parameter_type("count", "u32", "usize")
.execute()?;
}
Note: Type changes may require manual updates if the new type is incompatible with existing usage.
Complex Changes
Combine multiple modifications:
#![allow(unused)]
fn main() {
ChangeSignature::for_function("legacy_handler")
.in_file("src/handlers.rs")
// Remove deprecated parameters
.remove_parameter("deprecated_flag")
.remove_parameter("old_config")
// Add new parameters
.add_parameter("options", "Options", "Options::default()")
// Rename for clarity
.rename_parameter("cb", "callback")
// Reorder for consistency
.reorder_parameters(&["request", "options", "callback"])
.execute()?;
}
Method Signatures
For methods on structs/classes:
#![allow(unused)]
fn main() {
// Rust
ChangeSignature::for_method("process")
.on_type("DataProcessor")
.in_file("src/processor.rs")
.add_parameter("config", "&Config", "&Config::default()")
.execute()?;
// Java
ChangeSignature::for_method("process")
.on_type("DataProcessor")
.in_file("src/DataProcessor.java")
.add_parameter("config", "Config", "new Config()")
.execute()?;
}
Validation
#![allow(unused)]
fn main() {
let validation = ChangeSignature::for_function("api")
.in_file("src/lib.rs")
.add_parameter("new_param", "String", "String::new()")
.validate()?;
match validation {
ValidationResult::Valid => println!("Ready to change signature"),
ValidationResult::Warning(msg) => {
println!("Warning: {}", msg);
// e.g., "Found 50 call sites to update"
}
ValidationResult::Invalid(msg) => {
println!("Cannot change signature: {}", msg);
// e.g., "Function is part of a trait implementation"
}
}
}
Error Handling
#![allow(unused)]
fn main() {
use refactor::error::RefactorError;
match ChangeSignature::for_function("api").in_file("src/lib.rs")
.add_parameter("param", "Type", "default")
.execute()
{
Ok(result) => {
println!("Updated {} call sites", result.call_sites_updated);
}
Err(RefactorError::SymbolNotFound(name)) => {
println!("Function '{}' not found", name);
}
Err(RefactorError::TraitConstraint(msg)) => {
println!("Cannot change: {}", msg);
// Signature must match trait definition
}
Err(RefactorError::AmbiguousReference(msg)) => {
println!("Ambiguous function: {}", msg);
// Multiple functions with same name
}
Err(e) => return Err(e.into()),
}
}
Language-Specific Notes
Rust
- Trait implementations require matching trait changes
- Generic parameters are preserved
- Lifetime annotations are maintained
TypeScript
- Optional parameters use
?syntax - Destructured parameters are handled
- Overloads need manual attention
Python
- Default values must be valid Python expressions
*argsand**kwargsare preserved- Decorators are maintained
Go
- Named return values are supported
- Multiple return values are handled
- Interface implementations need matching changes
Best Practices
- Preview changes - Always use
.dry_run()first - Start with additions - Add parameters before removing old ones
- Provide meaningful defaults - Help callers migrate gradually
- Update tests - Test call sites may need attention
- Consider deprecation - Mark old signature as deprecated first
See Also
- Safe Delete - Remove unused parameters
- Extract - Create functions with proper signatures