diff options
Diffstat (limited to 'crates/ra_assists')
-rw-r--r-- | crates/ra_assists/src/doc_tests/generated.rs | 17 | ||||
-rw-r--r-- | crates/ra_assists/src/handlers/add_impl.rs | 4 | ||||
-rw-r--r-- | crates/ra_assists/src/handlers/add_missing_impl_members.rs | 34 | ||||
-rw-r--r-- | crates/ra_assists/src/handlers/add_new.rs | 5 | ||||
-rw-r--r-- | crates/ra_assists/src/handlers/inline_local_variable.rs | 2 | ||||
-rw-r--r-- | crates/ra_assists/src/handlers/introduce_variable.rs | 2 | ||||
-rw-r--r-- | crates/ra_assists/src/handlers/merge_imports.rs | 4 | ||||
-rw-r--r-- | crates/ra_assists/src/handlers/move_bounds.rs | 3 | ||||
-rw-r--r-- | crates/ra_assists/src/handlers/reorder_fields.rs | 230 | ||||
-rw-r--r-- | crates/ra_assists/src/lib.rs | 2 |
10 files changed, 275 insertions, 28 deletions
diff --git a/crates/ra_assists/src/doc_tests/generated.rs b/crates/ra_assists/src/doc_tests/generated.rs index 64444ee3a..b63b4d81a 100644 --- a/crates/ra_assists/src/doc_tests/generated.rs +++ b/crates/ra_assists/src/doc_tests/generated.rs | |||
@@ -180,7 +180,7 @@ trait Trait<T> { | |||
180 | } | 180 | } |
181 | 181 | ||
182 | impl Trait<u32> for () { | 182 | impl Trait<u32> for () { |
183 | fn foo(&self) -> u32 { unimplemented!() } | 183 | fn foo(&self) -> u32 { todo!() } |
184 | 184 | ||
185 | } | 185 | } |
186 | "#####, | 186 | "#####, |
@@ -607,6 +607,21 @@ impl Walrus { | |||
607 | } | 607 | } |
608 | 608 | ||
609 | #[test] | 609 | #[test] |
610 | fn doctest_reorder_fields() { | ||
611 | check( | ||
612 | "reorder_fields", | ||
613 | r#####" | ||
614 | struct Foo {foo: i32, bar: i32}; | ||
615 | const test: Foo = <|>Foo {bar: 0, foo: 1} | ||
616 | "#####, | ||
617 | r#####" | ||
618 | struct Foo {foo: i32, bar: i32}; | ||
619 | const test: Foo = Foo {foo: 1, bar: 0} | ||
620 | "#####, | ||
621 | ) | ||
622 | } | ||
623 | |||
624 | #[test] | ||
610 | fn doctest_replace_if_let_with_match() { | 625 | fn doctest_replace_if_let_with_match() { |
611 | check( | 626 | check( |
612 | "replace_if_let_with_match", | 627 | "replace_if_let_with_match", |
diff --git a/crates/ra_assists/src/handlers/add_impl.rs b/crates/ra_assists/src/handlers/add_impl.rs index 72a201b6d..6622eadb2 100644 --- a/crates/ra_assists/src/handlers/add_impl.rs +++ b/crates/ra_assists/src/handlers/add_impl.rs | |||
@@ -1,5 +1,5 @@ | |||
1 | use ra_syntax::{ | 1 | use ra_syntax::{ |
2 | ast::{self, AstNode, AstToken, NameOwner, TypeParamsOwner}, | 2 | ast::{self, AstNode, NameOwner, TypeParamsOwner}, |
3 | TextUnit, | 3 | TextUnit, |
4 | }; | 4 | }; |
5 | use stdx::{format_to, SepBy}; | 5 | use stdx::{format_to, SepBy}; |
@@ -42,7 +42,7 @@ pub(crate) fn add_impl(ctx: AssistCtx) -> Option<Assist> { | |||
42 | if let Some(type_params) = type_params { | 42 | if let Some(type_params) = type_params { |
43 | let lifetime_params = type_params | 43 | let lifetime_params = type_params |
44 | .lifetime_params() | 44 | .lifetime_params() |
45 | .filter_map(|it| it.lifetime()) | 45 | .filter_map(|it| it.lifetime_token()) |
46 | .map(|it| it.text().clone()); | 46 | .map(|it| it.text().clone()); |
47 | let type_params = | 47 | let type_params = |
48 | type_params.type_params().filter_map(|it| it.name()).map(|it| it.text().clone()); | 48 | type_params.type_params().filter_map(|it| it.name()).map(|it| it.text().clone()); |
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/add_new.rs b/crates/ra_assists/src/handlers/add_new.rs index c10397249..240b19fa3 100644 --- a/crates/ra_assists/src/handlers/add_new.rs +++ b/crates/ra_assists/src/handlers/add_new.rs | |||
@@ -1,8 +1,7 @@ | |||
1 | use hir::Adt; | 1 | use hir::Adt; |
2 | use ra_syntax::{ | 2 | use ra_syntax::{ |
3 | ast::{ | 3 | ast::{ |
4 | self, AstNode, AstToken, NameOwner, StructKind, TypeAscriptionOwner, TypeParamsOwner, | 4 | self, AstNode, NameOwner, StructKind, TypeAscriptionOwner, TypeParamsOwner, VisibilityOwner, |
5 | VisibilityOwner, | ||
6 | }, | 5 | }, |
7 | TextUnit, T, | 6 | TextUnit, T, |
8 | }; | 7 | }; |
@@ -106,7 +105,7 @@ fn generate_impl_text(strukt: &ast::StructDef, code: &str) -> String { | |||
106 | if let Some(type_params) = type_params { | 105 | if let Some(type_params) = type_params { |
107 | let lifetime_params = type_params | 106 | let lifetime_params = type_params |
108 | .lifetime_params() | 107 | .lifetime_params() |
109 | .filter_map(|it| it.lifetime()) | 108 | .filter_map(|it| it.lifetime_token()) |
110 | .map(|it| it.text().clone()); | 109 | .map(|it| it.text().clone()); |
111 | let type_params = | 110 | let type_params = |
112 | type_params.type_params().filter_map(|it| it.name()).map(|it| it.text().clone()); | 111 | type_params.type_params().filter_map(|it| it.name()).map(|it| it.text().clone()); |
diff --git a/crates/ra_assists/src/handlers/inline_local_variable.rs b/crates/ra_assists/src/handlers/inline_local_variable.rs index 3bfcba8ff..c4fb425b0 100644 --- a/crates/ra_assists/src/handlers/inline_local_variable.rs +++ b/crates/ra_assists/src/handlers/inline_local_variable.rs | |||
@@ -29,7 +29,7 @@ pub(crate) fn inline_local_variable(ctx: AssistCtx) -> Option<Assist> { | |||
29 | ast::Pat::BindPat(pat) => pat, | 29 | ast::Pat::BindPat(pat) => pat, |
30 | _ => return None, | 30 | _ => return None, |
31 | }; | 31 | }; |
32 | if bind_pat.is_mutable() { | 32 | if bind_pat.mut_token().is_some() { |
33 | tested_by!(test_not_inline_mut_variable); | 33 | tested_by!(test_not_inline_mut_variable); |
34 | return None; | 34 | return None; |
35 | } | 35 | } |
diff --git a/crates/ra_assists/src/handlers/introduce_variable.rs b/crates/ra_assists/src/handlers/introduce_variable.rs index 8a02f1a32..8d0f7e922 100644 --- a/crates/ra_assists/src/handlers/introduce_variable.rs +++ b/crates/ra_assists/src/handlers/introduce_variable.rs | |||
@@ -61,7 +61,7 @@ pub(crate) fn introduce_variable(ctx: AssistCtx) -> Option<Assist> { | |||
61 | }; | 61 | }; |
62 | if is_full_stmt { | 62 | if is_full_stmt { |
63 | tested_by!(test_introduce_var_expr_stmt); | 63 | tested_by!(test_introduce_var_expr_stmt); |
64 | if !full_stmt.unwrap().has_semi() { | 64 | if full_stmt.unwrap().semicolon_token().is_none() { |
65 | buf.push_str(";"); | 65 | buf.push_str(";"); |
66 | } | 66 | } |
67 | edit.replace(expr.syntax().text_range(), buf); | 67 | edit.replace(expr.syntax().text_range(), buf); |
diff --git a/crates/ra_assists/src/handlers/merge_imports.rs b/crates/ra_assists/src/handlers/merge_imports.rs index f8b3ddb4e..0958f52f1 100644 --- a/crates/ra_assists/src/handlers/merge_imports.rs +++ b/crates/ra_assists/src/handlers/merge_imports.rs | |||
@@ -3,7 +3,7 @@ use std::iter::successors; | |||
3 | use ra_syntax::{ | 3 | use ra_syntax::{ |
4 | algo::{neighbor, SyntaxRewriter}, | 4 | algo::{neighbor, SyntaxRewriter}, |
5 | ast::{self, edit::AstNodeEdit, make}, | 5 | ast::{self, edit::AstNodeEdit, make}, |
6 | AstNode, AstToken, Direction, InsertPosition, SyntaxElement, T, | 6 | AstNode, Direction, InsertPosition, SyntaxElement, T, |
7 | }; | 7 | }; |
8 | 8 | ||
9 | use crate::{Assist, AssistCtx, AssistId}; | 9 | use crate::{Assist, AssistCtx, AssistId}; |
@@ -82,7 +82,7 @@ fn try_merge_trees(old: &ast::UseTree, new: &ast::UseTree) -> Option<ast::UseTre | |||
82 | .filter(|it| it.kind() != T!['{'] && it.kind() != T!['}']), | 82 | .filter(|it| it.kind() != T!['{'] && it.kind() != T!['}']), |
83 | ); | 83 | ); |
84 | let use_tree_list = lhs.use_tree_list()?; | 84 | let use_tree_list = lhs.use_tree_list()?; |
85 | let pos = InsertPosition::Before(use_tree_list.r_curly()?.syntax().clone().into()); | 85 | let pos = InsertPosition::Before(use_tree_list.r_curly_token()?.into()); |
86 | let use_tree_list = use_tree_list.insert_children(pos, to_insert); | 86 | let use_tree_list = use_tree_list.insert_children(pos, to_insert); |
87 | Some(lhs.with_use_tree_list(use_tree_list)) | 87 | Some(lhs.with_use_tree_list(use_tree_list)) |
88 | } | 88 | } |
diff --git a/crates/ra_assists/src/handlers/move_bounds.rs b/crates/ra_assists/src/handlers/move_bounds.rs index 93f26f51a..0f26884dc 100644 --- a/crates/ra_assists/src/handlers/move_bounds.rs +++ b/crates/ra_assists/src/handlers/move_bounds.rs | |||
@@ -2,6 +2,7 @@ use ra_syntax::{ | |||
2 | ast::{self, edit::AstNodeEdit, make, AstNode, NameOwner, TypeBoundsOwner}, | 2 | ast::{self, edit::AstNodeEdit, make, AstNode, NameOwner, TypeBoundsOwner}, |
3 | match_ast, | 3 | match_ast, |
4 | SyntaxKind::*, | 4 | SyntaxKind::*, |
5 | T, | ||
5 | }; | 6 | }; |
6 | 7 | ||
7 | use crate::{Assist, AssistCtx, AssistId}; | 8 | use crate::{Assist, AssistCtx, AssistId}; |
@@ -42,7 +43,7 @@ pub(crate) fn move_bounds_to_where_clause(ctx: AssistCtx) -> Option<Assist> { | |||
42 | ast::EnumDef(it) => it.variant_list()?.syntax().clone().into(), | 43 | ast::EnumDef(it) => it.variant_list()?.syntax().clone().into(), |
43 | ast::StructDef(it) => { | 44 | ast::StructDef(it) => { |
44 | it.syntax().children_with_tokens() | 45 | it.syntax().children_with_tokens() |
45 | .find(|it| it.kind() == RECORD_FIELD_DEF_LIST || it.kind() == SEMI)? | 46 | .find(|it| it.kind() == RECORD_FIELD_DEF_LIST || it.kind() == T![;])? |
46 | }, | 47 | }, |
47 | _ => return None | 48 | _ => return None |
48 | } | 49 | } |
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..692dd1315 --- /dev/null +++ b/crates/ra_assists/src/handlers/reorder_fields.rs | |||
@@ -0,0 +1,230 @@ | |||
1 | use std::collections::HashMap; | ||
2 | |||
3 | use itertools::Itertools; | ||
4 | |||
5 | use hir::{Adt, ModuleDef, PathResolution, Semantics, Struct}; | ||
6 | use ra_ide_db::RootDatabase; | ||
7 | use ra_syntax::{ | ||
8 | algo, ast, | ||
9 | ast::{Name, Path, RecordLit, RecordPat}, | ||
10 | AstNode, SyntaxKind, SyntaxNode, | ||
11 | }; | ||
12 | |||
13 | use crate::{ | ||
14 | assist_ctx::{Assist, AssistCtx}, | ||
15 | AssistId, | ||
16 | }; | ||
17 | use ra_syntax::ast::{Expr, NameRef}; | ||
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 | use SyntaxKind::*; | ||
63 | match node.kind() { | ||
64 | RECORD_LIT => vec![RECORD_FIELD], | ||
65 | RECORD_PAT => vec![RECORD_FIELD_PAT, BIND_PAT], | ||
66 | _ => vec![], | ||
67 | } | ||
68 | } | ||
69 | |||
70 | fn get_field_name(node: &SyntaxNode) -> String { | ||
71 | use SyntaxKind::*; | ||
72 | match node.kind() { | ||
73 | RECORD_FIELD => { | ||
74 | if let Some(name) = node.children().find_map(NameRef::cast) { | ||
75 | return name.to_string(); | ||
76 | } | ||
77 | node.children().find_map(Expr::cast).map(|expr| expr.to_string()).unwrap_or_default() | ||
78 | } | ||
79 | BIND_PAT | RECORD_FIELD_PAT => { | ||
80 | node.children().find_map(Name::cast).map(|n| n.to_string()).unwrap_or_default() | ||
81 | } | ||
82 | _ => String::new(), | ||
83 | } | ||
84 | } | ||
85 | |||
86 | fn get_fields(record: &SyntaxNode) -> Vec<SyntaxNode> { | ||
87 | let kinds = get_fields_kind(record); | ||
88 | record.children().flat_map(|n| n.children()).filter(|n| kinds.contains(&n.kind())).collect() | ||
89 | } | ||
90 | |||
91 | fn sorted_by_rank( | ||
92 | fields: &[SyntaxNode], | ||
93 | get_rank: impl Fn(&SyntaxNode) -> usize, | ||
94 | ) -> Vec<SyntaxNode> { | ||
95 | fields.iter().cloned().sorted_by_key(get_rank).collect() | ||
96 | } | ||
97 | |||
98 | fn struct_definition(path: &ast::Path, sema: &Semantics<RootDatabase>) -> Option<Struct> { | ||
99 | match sema.resolve_path(path) { | ||
100 | Some(PathResolution::Def(ModuleDef::Adt(Adt::Struct(s)))) => Some(s), | ||
101 | _ => None, | ||
102 | } | ||
103 | } | ||
104 | |||
105 | fn compute_fields_ranks(path: &Path, ctx: &AssistCtx) -> Option<HashMap<String, usize>> { | ||
106 | Some( | ||
107 | struct_definition(path, ctx.sema)? | ||
108 | .fields(ctx.db) | ||
109 | .iter() | ||
110 | .enumerate() | ||
111 | .map(|(idx, field)| (field.name(ctx.db).to_string(), idx)) | ||
112 | .collect(), | ||
113 | ) | ||
114 | } | ||
115 | |||
116 | #[cfg(test)] | ||
117 | mod tests { | ||
118 | use crate::helpers::{check_assist, check_assist_not_applicable}; | ||
119 | |||
120 | use super::*; | ||
121 | |||
122 | #[test] | ||
123 | fn not_applicable_if_sorted() { | ||
124 | check_assist_not_applicable( | ||
125 | reorder_fields, | ||
126 | r#" | ||
127 | struct Foo { | ||
128 | foo: i32, | ||
129 | bar: i32, | ||
130 | } | ||
131 | |||
132 | const test: Foo = <|>Foo { foo: 0, bar: 0 }; | ||
133 | "#, | ||
134 | ) | ||
135 | } | ||
136 | |||
137 | #[test] | ||
138 | fn trivial_empty_fields() { | ||
139 | check_assist_not_applicable( | ||
140 | reorder_fields, | ||
141 | r#" | ||
142 | struct Foo {}; | ||
143 | const test: Foo = <|>Foo {} | ||
144 | "#, | ||
145 | ) | ||
146 | } | ||
147 | |||
148 | #[test] | ||
149 | fn reorder_struct_fields() { | ||
150 | check_assist( | ||
151 | reorder_fields, | ||
152 | r#" | ||
153 | struct Foo {foo: i32, bar: i32}; | ||
154 | const test: Foo = <|>Foo {bar: 0, foo: 1} | ||
155 | "#, | ||
156 | r#" | ||
157 | struct Foo {foo: i32, bar: i32}; | ||
158 | const test: Foo = <|>Foo {foo: 1, bar: 0} | ||
159 | "#, | ||
160 | ) | ||
161 | } | ||
162 | |||
163 | #[test] | ||
164 | fn reorder_struct_pattern() { | ||
165 | check_assist( | ||
166 | reorder_fields, | ||
167 | r#" | ||
168 | struct Foo { foo: i64, bar: i64, baz: i64 } | ||
169 | |||
170 | fn f(f: Foo) -> { | ||
171 | match f { | ||
172 | <|>Foo { baz: 0, ref mut bar, .. } => (), | ||
173 | _ => () | ||
174 | } | ||
175 | } | ||
176 | "#, | ||
177 | r#" | ||
178 | struct Foo { foo: i64, bar: i64, baz: i64 } | ||
179 | |||
180 | fn f(f: Foo) -> { | ||
181 | match f { | ||
182 | <|>Foo { ref mut bar, baz: 0, .. } => (), | ||
183 | _ => () | ||
184 | } | ||
185 | } | ||
186 | "#, | ||
187 | ) | ||
188 | } | ||
189 | |||
190 | #[test] | ||
191 | fn reorder_with_extra_field() { | ||
192 | check_assist( | ||
193 | reorder_fields, | ||
194 | r#" | ||
195 | struct Foo { | ||
196 | foo: String, | ||
197 | bar: String, | ||
198 | } | ||
199 | |||
200 | impl Foo { | ||
201 | fn new() -> Foo { | ||
202 | let foo = String::new(); | ||
203 | <|>Foo { | ||
204 | bar: foo.clone(), | ||
205 | extra: "Extra field", | ||
206 | foo, | ||
207 | } | ||
208 | } | ||
209 | } | ||
210 | "#, | ||
211 | r#" | ||
212 | struct Foo { | ||
213 | foo: String, | ||
214 | bar: String, | ||
215 | } | ||
216 | |||
217 | impl Foo { | ||
218 | fn new() -> Foo { | ||
219 | let foo = String::new(); | ||
220 | <|>Foo { | ||
221 | foo, | ||
222 | bar: foo.clone(), | ||
223 | extra: "Extra field", | ||
224 | } | ||
225 | } | ||
226 | } | ||
227 | "#, | ||
228 | ) | ||
229 | } | ||
230 | } | ||
diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs index 5ba5254fd..a00136da1 100644 --- a/crates/ra_assists/src/lib.rs +++ b/crates/ra_assists/src/lib.rs | |||
@@ -129,6 +129,7 @@ mod handlers { | |||
129 | mod replace_unwrap_with_match; | 129 | mod replace_unwrap_with_match; |
130 | mod split_import; | 130 | mod split_import; |
131 | mod add_from_impl_for_enum; | 131 | mod add_from_impl_for_enum; |
132 | mod reorder_fields; | ||
132 | 133 | ||
133 | pub(crate) fn all() -> &'static [AssistHandler] { | 134 | pub(crate) fn all() -> &'static [AssistHandler] { |
134 | &[ | 135 | &[ |
@@ -170,6 +171,7 @@ mod handlers { | |||
170 | // These are manually sorted for better priorities | 171 | // These are manually sorted for better priorities |
171 | add_missing_impl_members::add_missing_impl_members, | 172 | add_missing_impl_members::add_missing_impl_members, |
172 | add_missing_impl_members::add_missing_default_members, | 173 | add_missing_impl_members::add_missing_default_members, |
174 | reorder_fields::reorder_fields, | ||
173 | ] | 175 | ] |
174 | } | 176 | } |
175 | } | 177 | } |