Skip to content

Commit 9ed4af8

Browse files
committed
Auto merge of rust-lang#12142 - WaffleLapkin:sort-items-by-trait-def, r=lnicola
feat: Sort items by trait definition assist This PR replaces the "Sort **methods** by trait definition" assist with a "Sort **items** by trait definition" assist that sorts all items, not just methods. ![sort-items-by-trait-def-showcase](https://user-images.githubusercontent.com/38225716/166491828-0bc10dbd-91be-408f-9fe0-636ef5e99377.gif)
2 parents 0ee4e6a + e315124 commit 9ed4af8

File tree

3 files changed

+123
-60
lines changed

3 files changed

+123
-60
lines changed

crates/ide-assists/src/handlers/reorder_impl.rs renamed to crates/ide-assists/src/handlers/reorder_impl_items.rs

Lines changed: 108 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -6,46 +6,46 @@ use syntax::{
66
ted, AstNode,
77
};
88

9-
use crate::{utils::get_methods, AssistContext, AssistId, AssistKind, Assists};
9+
use crate::{AssistContext, AssistId, AssistKind, Assists};
1010

11-
// Assist: reorder_impl
11+
// Assist: reorder_impl_items
1212
//
13-
// Reorder the methods of an `impl Trait`. The methods will be ordered
13+
// Reorder the items of an `impl Trait`. The items will be ordered
1414
// in the same order as in the trait definition.
1515
//
1616
// ```
1717
// trait Foo {
18-
// fn a() {}
19-
// fn b() {}
20-
// fn c() {}
18+
// type A;
19+
// const B: u8;
20+
// fn c();
2121
// }
2222
//
2323
// struct Bar;
2424
// $0impl Foo for Bar {
25-
// fn b() {}
25+
// const B: u8 = 17;
2626
// fn c() {}
27-
// fn a() {}
27+
// type A = String;
2828
// }
2929
// ```
3030
// ->
3131
// ```
3232
// trait Foo {
33-
// fn a() {}
34-
// fn b() {}
35-
// fn c() {}
33+
// type A;
34+
// const B: u8;
35+
// fn c();
3636
// }
3737
//
3838
// struct Bar;
3939
// impl Foo for Bar {
40-
// fn a() {}
41-
// fn b() {}
40+
// type A = String;
41+
// const B: u8 = 17;
4242
// fn c() {}
4343
// }
4444
// ```
45-
pub(crate) fn reorder_impl(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
45+
pub(crate) fn reorder_impl_items(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
4646
let impl_ast = ctx.find_node_at_offset::<ast::Impl>()?;
4747
let items = impl_ast.assoc_item_list()?;
48-
let methods = get_methods(&items);
48+
let assoc_items = items.assoc_items().collect::<Vec<_>>();
4949

5050
let path = impl_ast
5151
.trait_()
@@ -55,48 +55,53 @@ pub(crate) fn reorder_impl(acc: &mut Assists, ctx: &AssistContext) -> Option<()>
5555
})?
5656
.path()?;
5757

58-
let ranks = compute_method_ranks(&path, ctx)?;
59-
let sorted: Vec<_> = methods
58+
let ranks = compute_item_ranks(&path, ctx)?;
59+
let sorted: Vec<_> = assoc_items
6060
.iter()
6161
.cloned()
62-
.sorted_by_key(|f| {
63-
f.name().and_then(|n| ranks.get(&n.to_string()).copied()).unwrap_or(usize::max_value())
62+
.sorted_by_key(|i| {
63+
let name = match i {
64+
ast::AssocItem::Const(c) => c.name(),
65+
ast::AssocItem::Fn(f) => f.name(),
66+
ast::AssocItem::TypeAlias(t) => t.name(),
67+
ast::AssocItem::MacroCall(_) => None,
68+
};
69+
70+
name.and_then(|n| ranks.get(&n.to_string()).copied()).unwrap_or(usize::max_value())
6471
})
6572
.collect();
6673

6774
// Don't edit already sorted methods:
68-
if methods == sorted {
75+
if assoc_items == sorted {
6976
cov_mark::hit!(not_applicable_if_sorted);
7077
return None;
7178
}
7279

7380
let target = items.syntax().text_range();
7481
acc.add(
75-
AssistId("reorder_impl", AssistKind::RefactorRewrite),
76-
"Sort methods by trait definition",
82+
AssistId("reorder_impl_items", AssistKind::RefactorRewrite),
83+
"Sort items by trait definition",
7784
target,
7885
|builder| {
79-
let methods = methods.into_iter().map(|fn_| builder.make_mut(fn_)).collect::<Vec<_>>();
80-
methods
86+
let assoc_items =
87+
assoc_items.into_iter().map(|item| builder.make_mut(item)).collect::<Vec<_>>();
88+
assoc_items
8189
.into_iter()
8290
.zip(sorted)
8391
.for_each(|(old, new)| ted::replace(old.syntax(), new.clone_for_update().syntax()));
8492
},
8593
)
8694
}
8795

88-
fn compute_method_ranks(path: &ast::Path, ctx: &AssistContext) -> Option<FxHashMap<String, usize>> {
96+
fn compute_item_ranks(path: &ast::Path, ctx: &AssistContext) -> Option<FxHashMap<String, usize>> {
8997
let td = trait_definition(path, &ctx.sema)?;
9098

9199
Some(
92100
td.items(ctx.db())
93101
.iter()
94-
.flat_map(|i| match i {
95-
hir::AssocItem::Function(f) => Some(f),
96-
_ => None,
97-
})
102+
.flat_map(|i| i.name(ctx.db()))
98103
.enumerate()
99-
.map(|(idx, func)| (func.name(ctx.db()).to_string(), idx))
104+
.map(|(idx, name)| (name.to_string(), idx))
100105
.collect(),
101106
)
102107
}
@@ -118,15 +123,19 @@ mod tests {
118123
fn not_applicable_if_sorted() {
119124
cov_mark::check!(not_applicable_if_sorted);
120125
check_assist_not_applicable(
121-
reorder_impl,
126+
reorder_impl_items,
122127
r#"
123128
trait Bar {
129+
type T;
130+
const C: ();
124131
fn a() {}
125132
fn z() {}
126133
fn b() {}
127134
}
128135
struct Foo;
129136
$0impl Bar for Foo {
137+
type T = ();
138+
const C: () = ();
130139
fn a() {}
131140
fn z() {}
132141
fn b() {}
@@ -135,10 +144,49 @@ $0impl Bar for Foo {
135144
)
136145
}
137146

147+
#[test]
148+
fn reorder_impl_trait_functions() {
149+
check_assist(
150+
reorder_impl_items,
151+
r#"
152+
trait Bar {
153+
fn a() {}
154+
fn c() {}
155+
fn b() {}
156+
fn d() {}
157+
}
158+
159+
struct Foo;
160+
$0impl Bar for Foo {
161+
fn d() {}
162+
fn b() {}
163+
fn c() {}
164+
fn a() {}
165+
}
166+
"#,
167+
r#"
168+
trait Bar {
169+
fn a() {}
170+
fn c() {}
171+
fn b() {}
172+
fn d() {}
173+
}
174+
175+
struct Foo;
176+
impl Bar for Foo {
177+
fn a() {}
178+
fn c() {}
179+
fn b() {}
180+
fn d() {}
181+
}
182+
"#,
183+
)
184+
}
185+
138186
#[test]
139187
fn not_applicable_if_empty() {
140188
check_assist_not_applicable(
141-
reorder_impl,
189+
reorder_impl_items,
142190
r#"
143191
trait Bar {};
144192
struct Foo;
@@ -148,69 +196,85 @@ $0impl Bar for Foo {}
148196
}
149197

150198
#[test]
151-
fn reorder_impl_trait_functions() {
199+
fn reorder_impl_trait_items() {
152200
check_assist(
153-
reorder_impl,
201+
reorder_impl_items,
154202
r#"
155203
trait Bar {
156204
fn a() {}
205+
type T0;
157206
fn c() {}
207+
const C1: ();
158208
fn b() {}
209+
type T1;
159210
fn d() {}
211+
const C0: ();
160212
}
161213
162214
struct Foo;
163215
$0impl Bar for Foo {
216+
type T1 = ();
164217
fn d() {}
165218
fn b() {}
166219
fn c() {}
220+
const C1: () = ();
167221
fn a() {}
222+
type T0 = ();
223+
const C0: () = ();
168224
}
169225
"#,
170226
r#"
171227
trait Bar {
172228
fn a() {}
229+
type T0;
173230
fn c() {}
231+
const C1: ();
174232
fn b() {}
233+
type T1;
175234
fn d() {}
235+
const C0: ();
176236
}
177237
178238
struct Foo;
179239
impl Bar for Foo {
180240
fn a() {}
241+
type T0 = ();
181242
fn c() {}
243+
const C1: () = ();
182244
fn b() {}
245+
type T1 = ();
183246
fn d() {}
247+
const C0: () = ();
184248
}
185249
"#,
186250
)
187251
}
188252

189253
#[test]
190-
fn reorder_impl_trait_methods_uneven_ident_lengths() {
254+
fn reorder_impl_trait_items_uneven_ident_lengths() {
191255
check_assist(
192-
reorder_impl,
256+
reorder_impl_items,
193257
r#"
194258
trait Bar {
195-
fn foo(&mut self) {}
196-
fn fooo(&mut self) {}
259+
type Foo;
260+
type Fooo;
197261
}
198262
199263
struct Foo;
200264
impl Bar for Foo {
201-
fn fooo(&mut self) {}
202-
fn foo(&mut self) {$0}
265+
type Fooo = ();
266+
type Foo = ();$0
203267
}"#,
204268
r#"
205269
trait Bar {
206-
fn foo(&mut self) {}
207-
fn fooo(&mut self) {}
270+
type Foo;
271+
type Fooo;
208272
}
209273
210274
struct Foo;
211275
impl Bar for Foo {
212-
fn foo(&mut self) {}
213-
fn fooo(&mut self) {}
276+
type Foo = ();
277+
type Fooo = ();
214278
}"#,
215279
)
216280
}

crates/ide-assists/src/lib.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
//! should be available more or less everywhere, which isn't useful. So
3838
//! instead we only show it if the user *selects* the items they want to sort.
3939
//! * Consider grouping related assists together (see [`Assists::add_group`]).
40-
//! * Make assists robust. If the assist depends on results of type-inference to
40+
//! * Make assists robust. If the assist depends on results of type-inference too
4141
//! much, it might only fire in fully-correct code. This makes assist less
4242
//! useful and (worse) less predictable. The user should have a clear
4343
//! intuition when each particular assist is available.
@@ -54,7 +54,6 @@
5454
//! something. If something *could* be a diagnostic, it should be a
5555
//! diagnostic. Conversely, it might be valuable to turn a diagnostic with a
5656
//! lot of false errors into an assist.
57-
//! *
5857
//!
5958
//! See also this post:
6059
//! <https://rust-analyzer.github.io/blog/2020/09/28/how-to-make-a-light-bulb.html>
@@ -170,7 +169,7 @@ mod handlers {
170169
mod remove_mut;
171170
mod remove_unused_param;
172171
mod reorder_fields;
173-
mod reorder_impl;
172+
mod reorder_impl_items;
174173
mod replace_try_expr_with_match;
175174
mod replace_derive_with_manual_impl;
176175
mod replace_if_let_with_match;
@@ -257,7 +256,7 @@ mod handlers {
257256
remove_mut::remove_mut,
258257
remove_unused_param::remove_unused_param,
259258
reorder_fields::reorder_fields,
260-
reorder_impl::reorder_impl,
259+
reorder_impl_items::reorder_impl_items,
261260
replace_try_expr_with_match::replace_try_expr_with_match,
262261
replace_derive_with_manual_impl::replace_derive_with_manual_impl,
263262
replace_if_let_with_match::replace_if_let_with_match,

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

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1737,34 +1737,34 @@ const test: Foo = Foo {foo: 1, bar: 0}
17371737
}
17381738

17391739
#[test]
1740-
fn doctest_reorder_impl() {
1740+
fn doctest_reorder_impl_items() {
17411741
check_doc_test(
1742-
"reorder_impl",
1742+
"reorder_impl_items",
17431743
r#####"
17441744
trait Foo {
1745-
fn a() {}
1746-
fn b() {}
1747-
fn c() {}
1745+
type A;
1746+
const B: u8;
1747+
fn c();
17481748
}
17491749
17501750
struct Bar;
17511751
$0impl Foo for Bar {
1752-
fn b() {}
1752+
const B: u8 = 17;
17531753
fn c() {}
1754-
fn a() {}
1754+
type A = String;
17551755
}
17561756
"#####,
17571757
r#####"
17581758
trait Foo {
1759-
fn a() {}
1760-
fn b() {}
1761-
fn c() {}
1759+
type A;
1760+
const B: u8;
1761+
fn c();
17621762
}
17631763
17641764
struct Bar;
17651765
impl Foo for Bar {
1766-
fn a() {}
1767-
fn b() {}
1766+
type A = String;
1767+
const B: u8 = 17;
17681768
fn c() {}
17691769
}
17701770
"#####,

0 commit comments

Comments
 (0)