Skip to content

Commit d8887c0

Browse files
Merge pull request #19692 from vishruth-thimmaiah/remove_underscore_for_used_var
feat: adds an assist to remove underscores from used variables
2 parents 94fa31e + 47c22bf commit d8887c0

File tree

3 files changed

+212
-0
lines changed

3 files changed

+212
-0
lines changed
Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
use ide_db::{
2+
assists::AssistId,
3+
defs::{Definition, NameClass, NameRefClass},
4+
};
5+
use syntax::{AstNode, ast};
6+
7+
use crate::{AssistContext, Assists};
8+
9+
// Assist: remove_underscore_from_used_variables
10+
//
11+
// Removes underscore from used variables.
12+
//
13+
// ```
14+
// fn main() {
15+
// let mut _$0foo = 1;
16+
// _foo = 2;
17+
// }
18+
// ```
19+
// ->
20+
// ```
21+
// fn main() {
22+
// let mut foo = 1;
23+
// foo = 2;
24+
// }
25+
// ```
26+
pub(crate) fn remove_underscore(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
27+
let (text, text_range, def) = if let Some(name_ref) = ctx.find_node_at_offset::<ast::Name>() {
28+
let text = name_ref.text();
29+
if !text.starts_with('_') {
30+
return None;
31+
}
32+
33+
let def = match NameClass::classify(&ctx.sema, &name_ref)? {
34+
NameClass::Definition(def @ Definition::Local(_)) => def,
35+
NameClass::PatFieldShorthand { local_def, .. } => Definition::Local(local_def),
36+
_ => return None,
37+
};
38+
(text.to_owned(), name_ref.syntax().text_range(), def)
39+
} else if let Some(name_ref) = ctx.find_node_at_offset::<ast::NameRef>() {
40+
let text = name_ref.text();
41+
if !text.starts_with('_') {
42+
return None;
43+
}
44+
let def = match NameRefClass::classify(&ctx.sema, &name_ref)? {
45+
NameRefClass::Definition(def @ Definition::Local(_), _) => def,
46+
NameRefClass::FieldShorthand { local_ref, .. } => Definition::Local(local_ref),
47+
_ => return None,
48+
};
49+
(text.to_owned(), name_ref.syntax().text_range(), def)
50+
} else {
51+
return None;
52+
};
53+
54+
if !def.usages(&ctx.sema).at_least_one() {
55+
return None;
56+
}
57+
58+
let new_name = text.trim_start_matches('_');
59+
acc.add(
60+
AssistId::refactor("remove_underscore_from_used_variables"),
61+
"Remove underscore from a used variable",
62+
text_range,
63+
|builder| {
64+
let changes = def.rename(&ctx.sema, new_name).unwrap();
65+
builder.source_change = changes;
66+
},
67+
)
68+
}
69+
70+
#[cfg(test)]
71+
mod tests {
72+
use crate::tests::{check_assist, check_assist_not_applicable};
73+
74+
use super::*;
75+
76+
#[test]
77+
fn remove_underscore_from_used_variable() {
78+
check_assist(
79+
remove_underscore,
80+
r#"
81+
fn main() {
82+
let mut _$0foo = 1;
83+
_foo = 2;
84+
}
85+
"#,
86+
r#"
87+
fn main() {
88+
let mut foo = 1;
89+
foo = 2;
90+
}
91+
"#,
92+
);
93+
}
94+
95+
#[test]
96+
fn not_applicable_for_unused() {
97+
check_assist_not_applicable(
98+
remove_underscore,
99+
r#"
100+
fn main() {
101+
let _$0unused = 1;
102+
}
103+
"#,
104+
);
105+
}
106+
107+
#[test]
108+
fn not_applicable_for_no_underscore() {
109+
check_assist_not_applicable(
110+
remove_underscore,
111+
r#"
112+
fn main() {
113+
let f$0oo = 1;
114+
foo = 2;
115+
}
116+
"#,
117+
);
118+
}
119+
120+
#[test]
121+
fn remove_multiple_underscores() {
122+
check_assist(
123+
remove_underscore,
124+
r#"
125+
fn main() {
126+
let mut _$0_foo = 1;
127+
__foo = 2;
128+
}
129+
"#,
130+
r#"
131+
fn main() {
132+
let mut foo = 1;
133+
foo = 2;
134+
}
135+
"#,
136+
);
137+
}
138+
139+
#[test]
140+
fn remove_underscore_on_usage() {
141+
check_assist(
142+
remove_underscore,
143+
r#"
144+
fn main() {
145+
let mut _foo = 1;
146+
_$0foo = 2;
147+
}
148+
"#,
149+
r#"
150+
fn main() {
151+
let mut foo = 1;
152+
foo = 2;
153+
}
154+
"#,
155+
);
156+
}
157+
158+
#[test]
159+
fn remove_underscore_in_function_parameter_usage() {
160+
check_assist(
161+
remove_underscore,
162+
r#"
163+
fn foo(_foo: i32) {
164+
let bar = _$0foo + 1;
165+
}
166+
"#,
167+
r#"
168+
fn foo(foo: i32) {
169+
let bar = foo + 1;
170+
}
171+
"#,
172+
)
173+
}
174+
175+
#[test]
176+
fn remove_underscore_in_function_parameter() {
177+
check_assist(
178+
remove_underscore,
179+
r#"
180+
fn foo(_$0foo: i32) {
181+
let bar = _foo + 1;
182+
}
183+
"#,
184+
r#"
185+
fn foo(foo: i32) {
186+
let bar = foo + 1;
187+
}
188+
"#,
189+
)
190+
}
191+
}

crates/ide-assists/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,7 @@ mod handlers {
200200
mod remove_dbg;
201201
mod remove_mut;
202202
mod remove_parentheses;
203+
mod remove_underscore;
203204
mod remove_unused_imports;
204205
mod remove_unused_param;
205206
mod reorder_fields;
@@ -335,6 +336,7 @@ mod handlers {
335336
remove_dbg::remove_dbg,
336337
remove_mut::remove_mut,
337338
remove_parentheses::remove_parentheses,
339+
remove_underscore::remove_underscore,
338340
remove_unused_imports::remove_unused_imports,
339341
remove_unused_param::remove_unused_param,
340342
reorder_fields::reorder_fields,

crates/ide-assists/src/tests/generated.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2748,6 +2748,25 @@ fn main() {
27482748
)
27492749
}
27502750

2751+
#[test]
2752+
fn doctest_remove_underscore_from_used_variables() {
2753+
check_doc_test(
2754+
"remove_underscore_from_used_variables",
2755+
r#####"
2756+
fn main() {
2757+
let mut _$0foo = 1;
2758+
_foo = 2;
2759+
}
2760+
"#####,
2761+
r#####"
2762+
fn main() {
2763+
let mut foo = 1;
2764+
foo = 2;
2765+
}
2766+
"#####,
2767+
)
2768+
}
2769+
27512770
#[test]
27522771
fn doctest_remove_unused_imports() {
27532772
check_doc_test(

0 commit comments

Comments
 (0)