-
Notifications
You must be signed in to change notification settings - Fork 1
Visual Studio Code Rust Analyzer
This document outlines how Visual Studio Code's Rust Analyzer which works on LSP handles the toy examples in the criterion for refactoring page.
pub fn original_foo() -> String {
let x = '1';
let y = if x > '2' {
x
} else {
return String::from("y")
};
String::from(y)
}Rust Analyzer used the Result container and did the extraction as described in the correction to IntelliJ's extraction:
pub fn new_foo() -> String {
let x = '1';
let y = match bar_extracted(x) {
Ok(value) => value,
Err(value) => return value,
};
String::from(y)
}
fn bar_extracted(x: char) -> Result<char, String> {
Ok(if x > '2' {
x
} else {
return Err(String::from("y"))
})
}const W: i32 = 5; // 'static
pub fn original_foo () { // scope a
let x = 1;
let x_ref = &x; // 'a
let mut z : &i32; // 'a
{ // scope b
let y = 2;
z = &y; // 'b
z = if *z < *x_ref {
&y // 'b
} else {
&W // 'static
};
println!("{}", *z);
}
}For this particular extraction, Rust Analyzer did not account for lifetime at all:
pub fn new_foo () {
let x = 1;
let x_ref = &x;
let mut z : &i32;
{
let y = 2;
z = &y;
z = bar_extracted(z, x_ref, y);
println!("{}", *z);
}
}
fn bar_extracted(z: &i32, x_ref: &i32, y: i32) -> &i32 {
if *z < *x_ref {
&y
} else {
&W
}
}However, Rust Analyzer managed to show the error:

Furthermore, this is also a flawed way of extracting since the reference to y is needed as an output but the extracted function uses y itself as the input to the function. This means that the ownership of y is passed to the function and so it cannot return a reference to the value that it owns.
pub fn original_foo(){
let p : &mut &i32 = &mut &0; // 'a
{
let x = 1;
*p = &x; // 'b
}
}Rust Analyzer again did not account for lifetimes, and while it did highlights the error to the user, it passes ownership of x to the extracted function rather than an immutable reference:
pub fn new_foo(){
let p : &mut &i32 = &mut &0;
{
let x = 1;
bar_extracted(p, x);
}
}
fn bar_extracted(p: &mut &i32, x: i32) {
*p = &x;
}trait MultiLifetimeTrait<'b, 'a: 'b> {
fn trait_function(self: &Self, x: & 'a i32, y: &'b i32) -> & 'b i32;
}
struct SimpleStruct;
impl<'b, 'a: 'b> MultiLifetimeTrait<'b, 'a> for SimpleStruct {
fn trait_function(&self, x: &'a i32, y: &'b i32) -> &'b i32 {
if *x < *y {
y
} else {
x
}
}
}
pub fn original_foo<'b, 'a: 'b>(x: &'a i32, y: &'b i32) {
let foo = SimpleStruct;
let z = &mut &0;
*z = foo.trait_function(x, y);
}Similarly, no lifetime annotation here but errors reported.
pub fn new_foo<'b, 'a: 'b>(x: &'a i32, y: &'b i32) {
let foo = SimpleStruct;
let z = &mut &0;
*z = bar_extracted(foo, x, y);
}
fn bar_extracted(foo: SimpleStruct, x: &i32, y: &i32) -> &i32 {
foo.trait_function(x, y)
}pub fn original_foo1<'a> (p: &'a mut &'a i32, x: &'a i32){
*p = x;
}
pub fn original_foo2<'a, 'b : 'a>(p: &'a mut &'b i32, x: &'b i32){
*p = x;
}Again, no lifetime annotations but errors reported. Rust Analyzer did not try to replace any other "duplicate" code:
pub fn new_foo1_fixed<'a> (p: &'a mut &'a i32, x: &'a i32){
bar_fixed(p, x);
}
fn bar_fixed<'a>(p: &'a mut &'a i32, x: &'a i32) {
*p = x;
}