diff options
Diffstat (limited to 'crates/ra_assists/src/handlers')
-rw-r--r-- | crates/ra_assists/src/handlers/add_missing_impl_members.rs | 34 | ||||
-rw-r--r-- | crates/ra_assists/src/handlers/reorder_fields.rs | 224 |
2 files changed, 241 insertions, 17 deletions
diff --git a/crates/ra_assists/src/handlers/add_missing_impl_members.rs b/crates/ra_assists/src/handlers/add_missing_impl_members.rs index 722f207e2..2d6d44980 100644 --- a/crates/ra_assists/src/handlers/add_missing_impl_members.rs +++ b/crates/ra_assists/src/handlers/add_missing_impl_members.rs | |||
@@ -40,7 +40,7 @@ enum AddMissingImplMembersMode { | |||
40 | // } | 40 | // } |
41 | // | 41 | // |
42 | // impl Trait<u32> for () { | 42 | // impl Trait<u32> for () { |
43 | // fn foo(&self) -> u32 { unimplemented!() } | 43 | // fn foo(&self) -> u32 { todo!() } |
44 | // | 44 | // |
45 | // } | 45 | // } |
46 | // ``` | 46 | // ``` |
@@ -165,7 +165,7 @@ fn add_missing_impl_members_inner( | |||
165 | 165 | ||
166 | fn add_body(fn_def: ast::FnDef) -> ast::FnDef { | 166 | fn add_body(fn_def: ast::FnDef) -> ast::FnDef { |
167 | if fn_def.body().is_none() { | 167 | if fn_def.body().is_none() { |
168 | fn_def.with_body(make::block_from_expr(make::expr_unimplemented())) | 168 | fn_def.with_body(make::block_from_expr(make::expr_todo())) |
169 | } else { | 169 | } else { |
170 | fn_def | 170 | fn_def |
171 | } | 171 | } |
@@ -215,8 +215,8 @@ impl Foo for S { | |||
215 | fn bar(&self) {} | 215 | fn bar(&self) {} |
216 | <|>type Output; | 216 | <|>type Output; |
217 | const CONST: usize = 42; | 217 | const CONST: usize = 42; |
218 | fn foo(&self) { unimplemented!() } | 218 | fn foo(&self) { todo!() } |
219 | fn baz(&self) { unimplemented!() } | 219 | fn baz(&self) { todo!() } |
220 | 220 | ||
221 | }", | 221 | }", |
222 | ); | 222 | ); |
@@ -250,7 +250,7 @@ struct S; | |||
250 | 250 | ||
251 | impl Foo for S { | 251 | impl Foo for S { |
252 | fn bar(&self) {} | 252 | fn bar(&self) {} |
253 | <|>fn foo(&self) { unimplemented!() } | 253 | <|>fn foo(&self) { todo!() } |
254 | 254 | ||
255 | }", | 255 | }", |
256 | ); | 256 | ); |
@@ -268,7 +268,7 @@ impl Foo for S { <|> }", | |||
268 | trait Foo { fn foo(&self); } | 268 | trait Foo { fn foo(&self); } |
269 | struct S; | 269 | struct S; |
270 | impl Foo for S { | 270 | impl Foo for S { |
271 | <|>fn foo(&self) { unimplemented!() } | 271 | <|>fn foo(&self) { todo!() } |
272 | }", | 272 | }", |
273 | ); | 273 | ); |
274 | } | 274 | } |
@@ -285,7 +285,7 @@ impl Foo<u32> for S { <|> }", | |||
285 | trait Foo<T> { fn foo(&self, t: T) -> &T; } | 285 | trait Foo<T> { fn foo(&self, t: T) -> &T; } |
286 | struct S; | 286 | struct S; |
287 | impl Foo<u32> for S { | 287 | impl Foo<u32> for S { |
288 | <|>fn foo(&self, t: u32) -> &u32 { unimplemented!() } | 288 | <|>fn foo(&self, t: u32) -> &u32 { todo!() } |
289 | }", | 289 | }", |
290 | ); | 290 | ); |
291 | } | 291 | } |
@@ -302,7 +302,7 @@ impl<U> Foo<U> for S { <|> }", | |||
302 | trait Foo<T> { fn foo(&self, t: T) -> &T; } | 302 | trait Foo<T> { fn foo(&self, t: T) -> &T; } |
303 | struct S; | 303 | struct S; |
304 | impl<U> Foo<U> for S { | 304 | impl<U> Foo<U> for S { |
305 | <|>fn foo(&self, t: U) -> &U { unimplemented!() } | 305 | <|>fn foo(&self, t: U) -> &U { todo!() } |
306 | }", | 306 | }", |
307 | ); | 307 | ); |
308 | } | 308 | } |
@@ -319,7 +319,7 @@ impl Foo for S {}<|>", | |||
319 | trait Foo { fn foo(&self); } | 319 | trait Foo { fn foo(&self); } |
320 | struct S; | 320 | struct S; |
321 | impl Foo for S { | 321 | impl Foo for S { |
322 | <|>fn foo(&self) { unimplemented!() } | 322 | <|>fn foo(&self) { todo!() } |
323 | }", | 323 | }", |
324 | ) | 324 | ) |
325 | } | 325 | } |
@@ -342,7 +342,7 @@ mod foo { | |||
342 | } | 342 | } |
343 | struct S; | 343 | struct S; |
344 | impl foo::Foo for S { | 344 | impl foo::Foo for S { |
345 | <|>fn foo(&self, bar: foo::Bar) { unimplemented!() } | 345 | <|>fn foo(&self, bar: foo::Bar) { todo!() } |
346 | }", | 346 | }", |
347 | ); | 347 | ); |
348 | } | 348 | } |
@@ -365,7 +365,7 @@ mod foo { | |||
365 | } | 365 | } |
366 | struct S; | 366 | struct S; |
367 | impl foo::Foo for S { | 367 | impl foo::Foo for S { |
368 | <|>fn foo(&self, bar: foo::Bar<u32>) { unimplemented!() } | 368 | <|>fn foo(&self, bar: foo::Bar<u32>) { todo!() } |
369 | }", | 369 | }", |
370 | ); | 370 | ); |
371 | } | 371 | } |
@@ -388,7 +388,7 @@ mod foo { | |||
388 | } | 388 | } |
389 | struct S; | 389 | struct S; |
390 | impl foo::Foo<u32> for S { | 390 | impl foo::Foo<u32> for S { |
391 | <|>fn foo(&self, bar: foo::Bar<u32>) { unimplemented!() } | 391 | <|>fn foo(&self, bar: foo::Bar<u32>) { todo!() } |
392 | }", | 392 | }", |
393 | ); | 393 | ); |
394 | } | 394 | } |
@@ -414,7 +414,7 @@ mod foo { | |||
414 | struct Param; | 414 | struct Param; |
415 | struct S; | 415 | struct S; |
416 | impl foo::Foo<Param> for S { | 416 | impl foo::Foo<Param> for S { |
417 | <|>fn foo(&self, bar: Param) { unimplemented!() } | 417 | <|>fn foo(&self, bar: Param) { todo!() } |
418 | }", | 418 | }", |
419 | ); | 419 | ); |
420 | } | 420 | } |
@@ -439,7 +439,7 @@ mod foo { | |||
439 | } | 439 | } |
440 | struct S; | 440 | struct S; |
441 | impl foo::Foo for S { | 441 | impl foo::Foo for S { |
442 | <|>fn foo(&self, bar: foo::Bar<u32>::Assoc) { unimplemented!() } | 442 | <|>fn foo(&self, bar: foo::Bar<u32>::Assoc) { todo!() } |
443 | }", | 443 | }", |
444 | ); | 444 | ); |
445 | } | 445 | } |
@@ -464,7 +464,7 @@ mod foo { | |||
464 | } | 464 | } |
465 | struct S; | 465 | struct S; |
466 | impl foo::Foo for S { | 466 | impl foo::Foo for S { |
467 | <|>fn foo(&self, bar: foo::Bar<foo::Baz>) { unimplemented!() } | 467 | <|>fn foo(&self, bar: foo::Bar<foo::Baz>) { todo!() } |
468 | }", | 468 | }", |
469 | ); | 469 | ); |
470 | } | 470 | } |
@@ -487,7 +487,7 @@ mod foo { | |||
487 | } | 487 | } |
488 | struct S; | 488 | struct S; |
489 | impl foo::Foo for S { | 489 | impl foo::Foo for S { |
490 | <|>fn foo(&self, bar: dyn Fn(u32) -> i32) { unimplemented!() } | 490 | <|>fn foo(&self, bar: dyn Fn(u32) -> i32) { todo!() } |
491 | }", | 491 | }", |
492 | ); | 492 | ); |
493 | } | 493 | } |
@@ -544,7 +544,7 @@ trait Foo { | |||
544 | struct S; | 544 | struct S; |
545 | impl Foo for S { | 545 | impl Foo for S { |
546 | <|>type Output; | 546 | <|>type Output; |
547 | fn foo(&self) { unimplemented!() } | 547 | fn foo(&self) { todo!() } |
548 | }"#, | 548 | }"#, |
549 | ) | 549 | ) |
550 | } | 550 | } |
diff --git a/crates/ra_assists/src/handlers/reorder_fields.rs b/crates/ra_assists/src/handlers/reorder_fields.rs new file mode 100644 index 000000000..a43e53a11 --- /dev/null +++ b/crates/ra_assists/src/handlers/reorder_fields.rs | |||
@@ -0,0 +1,224 @@ | |||
1 | use std::collections::HashMap; | ||
2 | |||
3 | use hir::{Adt, ModuleDef, PathResolution, Semantics, Struct}; | ||
4 | use itertools::Itertools; | ||
5 | use ra_ide_db::RootDatabase; | ||
6 | use ra_syntax::{ | ||
7 | algo, | ||
8 | ast::{self, Path, RecordLit, RecordPat}, | ||
9 | match_ast, AstNode, SyntaxKind, | ||
10 | SyntaxKind::*, | ||
11 | SyntaxNode, | ||
12 | }; | ||
13 | |||
14 | use crate::{ | ||
15 | assist_ctx::{Assist, AssistCtx}, | ||
16 | AssistId, | ||
17 | }; | ||
18 | |||
19 | // Assist: reorder_fields | ||
20 | // | ||
21 | // Reorder the fields of record literals and record patterns in the same order as in | ||
22 | // the definition. | ||
23 | // | ||
24 | // ``` | ||
25 | // struct Foo {foo: i32, bar: i32}; | ||
26 | // const test: Foo = <|>Foo {bar: 0, foo: 1} | ||
27 | // ``` | ||
28 | // -> | ||
29 | // ``` | ||
30 | // struct Foo {foo: i32, bar: i32}; | ||
31 | // const test: Foo = Foo {foo: 1, bar: 0} | ||
32 | // ``` | ||
33 | // | ||
34 | pub(crate) fn reorder_fields(ctx: AssistCtx) -> Option<Assist> { | ||
35 | reorder::<RecordLit>(ctx.clone()).or_else(|| reorder::<RecordPat>(ctx)) | ||
36 | } | ||
37 | |||
38 | fn reorder<R: AstNode>(ctx: AssistCtx) -> Option<Assist> { | ||
39 | let record = ctx.find_node_at_offset::<R>()?; | ||
40 | let path = record.syntax().children().find_map(Path::cast)?; | ||
41 | |||
42 | let ranks = compute_fields_ranks(&path, &ctx)?; | ||
43 | |||
44 | let fields = get_fields(&record.syntax()); | ||
45 | let sorted_fields = sorted_by_rank(&fields, |node| { | ||
46 | *ranks.get(&get_field_name(node)).unwrap_or(&usize::max_value()) | ||
47 | }); | ||
48 | |||
49 | if sorted_fields == fields { | ||
50 | return None; | ||
51 | } | ||
52 | |||
53 | ctx.add_assist(AssistId("reorder_fields"), "Reorder record fields", |edit| { | ||
54 | for (old, new) in fields.iter().zip(&sorted_fields) { | ||
55 | algo::diff(old, new).into_text_edit(edit.text_edit_builder()); | ||
56 | } | ||
57 | edit.target(record.syntax().text_range()) | ||
58 | }) | ||
59 | } | ||
60 | |||
61 | fn get_fields_kind(node: &SyntaxNode) -> Vec<SyntaxKind> { | ||
62 | match node.kind() { | ||
63 | RECORD_LIT => vec![RECORD_FIELD], | ||
64 | RECORD_PAT => vec![RECORD_FIELD_PAT, BIND_PAT], | ||
65 | _ => vec![], | ||
66 | } | ||
67 | } | ||
68 | |||
69 | fn get_field_name(node: &SyntaxNode) -> String { | ||
70 | let res = match_ast! { | ||
71 | match node { | ||
72 | ast::RecordField(field) => { field.field_name().map(|it| it.to_string()) }, | ||
73 | ast::RecordFieldPat(field) => { field.field_name().map(|it| it.to_string()) }, | ||
74 | _ => None, | ||
75 | } | ||
76 | }; | ||
77 | res.unwrap_or_default() | ||
78 | } | ||
79 | |||
80 | fn get_fields(record: &SyntaxNode) -> Vec<SyntaxNode> { | ||
81 | let kinds = get_fields_kind(record); | ||
82 | record.children().flat_map(|n| n.children()).filter(|n| kinds.contains(&n.kind())).collect() | ||
83 | } | ||
84 | |||
85 | fn sorted_by_rank( | ||
86 | fields: &[SyntaxNode], | ||
87 | get_rank: impl Fn(&SyntaxNode) -> usize, | ||
88 | ) -> Vec<SyntaxNode> { | ||
89 | fields.iter().cloned().sorted_by_key(get_rank).collect() | ||
90 | } | ||
91 | |||
92 | fn struct_definition(path: &ast::Path, sema: &Semantics<RootDatabase>) -> Option<Struct> { | ||
93 | match sema.resolve_path(path) { | ||
94 | Some(PathResolution::Def(ModuleDef::Adt(Adt::Struct(s)))) => Some(s), | ||
95 | _ => None, | ||
96 | } | ||
97 | } | ||
98 | |||
99 | fn compute_fields_ranks(path: &Path, ctx: &AssistCtx) -> Option<HashMap<String, usize>> { | ||
100 | Some( | ||
101 | struct_definition(path, ctx.sema)? | ||
102 | .fields(ctx.db) | ||
103 | .iter() | ||
104 | .enumerate() | ||
105 | .map(|(idx, field)| (field.name(ctx.db).to_string(), idx)) | ||
106 | .collect(), | ||
107 | ) | ||
108 | } | ||
109 | |||
110 | #[cfg(test)] | ||
111 | mod tests { | ||
112 | use crate::helpers::{check_assist, check_assist_not_applicable}; | ||
113 | |||
114 | use super::*; | ||
115 | |||
116 | #[test] | ||
117 | fn not_applicable_if_sorted() { | ||
118 | check_assist_not_applicable( | ||
119 | reorder_fields, | ||
120 | r#" | ||
121 | struct Foo { | ||
122 | foo: i32, | ||
123 | bar: i32, | ||
124 | } | ||
125 | |||
126 | const test: Foo = <|>Foo { foo: 0, bar: 0 }; | ||
127 | "#, | ||
128 | ) | ||
129 | } | ||
130 | |||
131 | #[test] | ||
132 | fn trivial_empty_fields() { | ||
133 | check_assist_not_applicable( | ||
134 | reorder_fields, | ||
135 | r#" | ||
136 | struct Foo {}; | ||
137 | const test: Foo = <|>Foo {} | ||
138 | "#, | ||
139 | ) | ||
140 | } | ||
141 | |||
142 | #[test] | ||
143 | fn reorder_struct_fields() { | ||
144 | check_assist( | ||
145 | reorder_fields, | ||
146 | r#" | ||
147 | struct Foo {foo: i32, bar: i32}; | ||
148 | const test: Foo = <|>Foo {bar: 0, foo: 1} | ||
149 | "#, | ||
150 | r#" | ||
151 | struct Foo {foo: i32, bar: i32}; | ||
152 | const test: Foo = <|>Foo {foo: 1, bar: 0} | ||
153 | "#, | ||
154 | ) | ||
155 | } | ||
156 | |||
157 | #[test] | ||
158 | fn reorder_struct_pattern() { | ||
159 | check_assist( | ||
160 | reorder_fields, | ||
161 | r#" | ||
162 | struct Foo { foo: i64, bar: i64, baz: i64 } | ||
163 | |||
164 | fn f(f: Foo) -> { | ||
165 | match f { | ||
166 | <|>Foo { baz: 0, ref mut bar, .. } => (), | ||
167 | _ => () | ||
168 | } | ||
169 | } | ||
170 | "#, | ||
171 | r#" | ||
172 | struct Foo { foo: i64, bar: i64, baz: i64 } | ||
173 | |||
174 | fn f(f: Foo) -> { | ||
175 | match f { | ||
176 | <|>Foo { ref mut bar, baz: 0, .. } => (), | ||
177 | _ => () | ||
178 | } | ||
179 | } | ||
180 | "#, | ||
181 | ) | ||
182 | } | ||
183 | |||
184 | #[test] | ||
185 | fn reorder_with_extra_field() { | ||
186 | check_assist( | ||
187 | reorder_fields, | ||
188 | r#" | ||
189 | struct Foo { | ||
190 | foo: String, | ||
191 | bar: String, | ||
192 | } | ||
193 | |||
194 | impl Foo { | ||
195 | fn new() -> Foo { | ||
196 | let foo = String::new(); | ||
197 | <|>Foo { | ||
198 | bar: foo.clone(), | ||
199 | extra: "Extra field", | ||
200 | foo, | ||
201 | } | ||
202 | } | ||
203 | } | ||
204 | "#, | ||
205 | r#" | ||
206 | struct Foo { | ||
207 | foo: String, | ||
208 | bar: String, | ||
209 | } | ||
210 | |||
211 | impl Foo { | ||
212 | fn new() -> Foo { | ||
213 | let foo = String::new(); | ||
214 | <|>Foo { | ||
215 | foo, | ||
216 | bar: foo.clone(), | ||
217 | extra: "Extra field", | ||
218 | } | ||
219 | } | ||
220 | } | ||
221 | "#, | ||
222 | ) | ||
223 | } | ||
224 | } | ||