Skip to content

Commit 70dd421

Browse files
feat: adds an assist to remove underscores from used variables
adds an assist that suggests removing any underscore prefixes from used variables.
1 parent df594ba commit 70dd421

File tree

3 files changed

+293
-0
lines changed

3 files changed

+293
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,272 @@
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+
192+
#[test]
193+
fn remove_underscore_in_struct_field() {
194+
check_assist(
195+
remove_underscore,
196+
r#"
197+
struct Foo {
198+
_$0foo: i32,
199+
}
200+
201+
fn main() {
202+
let bar = Foo { _foo: 1 };
203+
let baz = bar._foo;
204+
}
205+
"#,
206+
r#"
207+
struct Foo {
208+
foo: i32,
209+
}
210+
211+
fn main() {
212+
let bar = Foo { foo: 1 };
213+
let baz = bar.foo;
214+
}
215+
"#,
216+
)
217+
}
218+
219+
#[test]
220+
fn remove_underscore_in_struct_name() {
221+
check_assist(
222+
remove_underscore,
223+
r#"
224+
struct _$0Foo {
225+
foo: i32,
226+
}
227+
228+
fn main() {
229+
let bar = _Foo { foo: 1 };
230+
let baz = bar.foo;
231+
}
232+
"#,
233+
r#"
234+
struct Foo {
235+
foo: i32,
236+
}
237+
238+
fn main() {
239+
let bar = Foo { foo: 1 };
240+
let baz = bar.foo;
241+
}
242+
"#,
243+
)
244+
}
245+
246+
#[test]
247+
fn remove_underscore_in_struct_name_usage() {
248+
check_assist(
249+
remove_underscore,
250+
r#"
251+
struct _Foo {
252+
foo: i32,
253+
}
254+
255+
fn main() {
256+
let bar = _$0Foo { foo: 1 };
257+
let baz = bar.foo;
258+
}
259+
"#,
260+
r#"
261+
struct Foo {
262+
foo: i32,
263+
}
264+
265+
fn main() {
266+
let bar = Foo { foo: 1 };
267+
let baz = bar.foo;
268+
}
269+
"#,
270+
)
271+
}
272+
}

crates/ide-assists/src/lib.rs

+2
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

+19
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)