@@ -6,7 +6,7 @@ use ide_db::{
6
6
label:: Label ,
7
7
source_change:: SourceChange ,
8
8
} ;
9
- use syntax:: { Edition , TextRange } ;
9
+ use syntax:: { AstNode , Edition , TextRange } ;
10
10
11
11
use crate :: { Diagnostic , DiagnosticCode , DiagnosticsContext } ;
12
12
@@ -24,15 +24,21 @@ pub(crate) fn unused_variables(
24
24
}
25
25
let diagnostic_range = ctx. sema . diagnostics_display_range ( ast) ;
26
26
// The range for the Actual Name. We don't want to replace the entire declaration. Using the diagnostic range causes issues within in Array Destructuring.
27
- let name_range = d
28
- . local
29
- . primary_source ( ctx. sema . db )
27
+ let primary_source = d. local . primary_source ( ctx. sema . db ) ;
28
+ let name_range = primary_source
30
29
. name ( )
31
30
. map ( |v| v. syntax ( ) . original_file_range_rooted ( ctx. sema . db ) )
32
31
. filter ( |it| {
33
32
Some ( it. file_id ) == ast. file_id . file_id ( )
34
33
&& diagnostic_range. range . contains_range ( it. range )
35
34
} ) ;
35
+ let is_shorthand_field = primary_source
36
+ . source
37
+ . value
38
+ . left ( )
39
+ . and_then ( |name| name. syntax ( ) . parent ( ) )
40
+ . and_then ( syntax:: ast:: RecordPatField :: cast)
41
+ . is_some_and ( |field| field. colon_token ( ) . is_none ( ) ) ;
36
42
let var_name = d. local . name ( ctx. sema . db ) ;
37
43
Some (
38
44
Diagnostic :: new_with_syntax_node_ptr (
@@ -48,6 +54,7 @@ pub(crate) fn unused_variables(
48
54
it. range ,
49
55
diagnostic_range,
50
56
ast. file_id . is_macro ( ) ,
57
+ is_shorthand_field,
51
58
ctx. edition ,
52
59
)
53
60
} ) ) ,
@@ -60,24 +67,23 @@ fn fixes(
60
67
name_range : TextRange ,
61
68
diagnostic_range : FileRange ,
62
69
is_in_marco : bool ,
70
+ is_shorthand_field : bool ,
63
71
edition : Edition ,
64
72
) -> Option < Vec < Assist > > {
65
73
if is_in_marco {
66
74
return None ;
67
75
}
76
+ let name = var_name. display ( db, edition) ;
77
+ let new_name = if is_shorthand_field { format ! ( "{name}: _{name}" ) } else { format ! ( "_{name}" ) } ;
68
78
69
79
Some ( vec ! [ Assist {
70
80
id: AssistId :: quick_fix( "unscore_unused_variable_name" ) ,
71
- label: Label :: new( format!(
72
- "Rename unused {} to _{}" ,
73
- var_name. display( db, edition) ,
74
- var_name. display( db, edition)
75
- ) ) ,
81
+ label: Label :: new( format!( "Rename unused {name} to {new_name}" ) ) ,
76
82
group: None ,
77
83
target: diagnostic_range. range,
78
84
source_change: Some ( SourceChange :: from_text_edit(
79
85
diagnostic_range. file_id,
80
- TextEdit :: replace( name_range, format! ( "_{}" , var_name . display ( db , edition ) ) ) ,
86
+ TextEdit :: replace( name_range, new_name ) ,
81
87
) ) ,
82
88
command: None ,
83
89
} ] )
@@ -220,7 +226,7 @@ struct Foo { f1: i32, f2: i64 }
220
226
fn main() {
221
227
let f = Foo { f1: 0, f2: 0 };
222
228
match f {
223
- Foo { _f1, f2 } => {
229
+ Foo { f1: _f1, f2 } => {
224
230
_ = f2;
225
231
}
226
232
}
@@ -263,6 +269,46 @@ fn main() {
263
269
) ;
264
270
}
265
271
272
+ #[ test]
273
+ fn unused_variable_in_record_field ( ) {
274
+ check_fix (
275
+ r#"
276
+ struct S { field : u32 }
277
+ fn main() {
278
+ let s = S { field : 2 };
279
+ let S { field: $0x } = s
280
+ }
281
+ "# ,
282
+ r#"
283
+ struct S { field : u32 }
284
+ fn main() {
285
+ let s = S { field : 2 };
286
+ let S { field: _x } = s
287
+ }
288
+ "# ,
289
+ ) ;
290
+ }
291
+
292
+ #[ test]
293
+ fn unused_variable_in_shorthand_record_field ( ) {
294
+ check_fix (
295
+ r#"
296
+ struct S { field : u32 }
297
+ fn main() {
298
+ let s = S { field : 2 };
299
+ let S { $0field } = s
300
+ }
301
+ "# ,
302
+ r#"
303
+ struct S { field : u32 }
304
+ fn main() {
305
+ let s = S { field : 2 };
306
+ let S { field: _field } = s
307
+ }
308
+ "# ,
309
+ ) ;
310
+ }
311
+
266
312
// regression test as we used to panic in this scenario
267
313
#[ test]
268
314
fn unknown_struct_pattern_param_type ( ) {
0 commit comments