aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_assists
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_assists')
-rw-r--r--crates/ra_assists/src/assists/flip_trait_bound.rs119
-rw-r--r--crates/ra_assists/src/doc_tests.rs12
-rw-r--r--crates/ra_assists/src/doc_tests/generated.rs13
-rw-r--r--crates/ra_assists/src/lib.rs2
4 files changed, 145 insertions, 1 deletions
diff --git a/crates/ra_assists/src/assists/flip_trait_bound.rs b/crates/ra_assists/src/assists/flip_trait_bound.rs
new file mode 100644
index 000000000..1625b241f
--- /dev/null
+++ b/crates/ra_assists/src/assists/flip_trait_bound.rs
@@ -0,0 +1,119 @@
1use hir::db::HirDatabase;
2use ra_syntax::{
3 algo::non_trivia_sibling,
4 ast::{self, AstNode},
5 Direction, T,
6};
7
8use crate::{Assist, AssistCtx, AssistId};
9
10// Assist: flip_trait_bound
11//
12// Flips two trait bounds.
13//
14// ```
15// fn foo<T: Clone +<|> Copy>() { }
16// ```
17// ->
18// ```
19// fn foo<T: Copy + Clone>() { }
20// ```
21pub(crate) fn flip_trait_bound(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
22 // We want to replicate the behavior of `flip_binexpr` by only suggesting
23 // the assist when the cursor is on a `+`
24 let plus = ctx.find_token_at_offset(T![+])?;
25
26 // Make sure we're in a `TypeBoundList`
27 if ast::TypeBoundList::cast(plus.parent()).is_none() {
28 return None;
29 }
30
31 let (before, after) = (
32 non_trivia_sibling(plus.clone().into(), Direction::Prev)?,
33 non_trivia_sibling(plus.clone().into(), Direction::Next)?,
34 );
35
36 ctx.add_action(AssistId("flip_trait_bound"), "flip trait bound", |edit| {
37 edit.target(plus.text_range());
38 edit.replace(before.text_range(), after.to_string());
39 edit.replace(after.text_range(), before.to_string());
40 });
41
42 ctx.build()
43}
44
45#[cfg(test)]
46mod tests {
47 use super::*;
48
49 use crate::helpers::{check_assist, check_assist_not_applicable, check_assist_target};
50
51 #[test]
52 fn flip_trait_bound_assist_available() {
53 check_assist_target(flip_trait_bound, "struct S<T> where T: A <|>+ B + C { }", "+")
54 }
55
56 #[test]
57 fn flip_trait_bound_not_applicable_for_single_trait_bound() {
58 check_assist_not_applicable(flip_trait_bound, "struct S<T> where T: <|>A { }")
59 }
60
61 #[test]
62 fn flip_trait_bound_works_for_struct() {
63 check_assist(
64 flip_trait_bound,
65 "struct S<T> where T: A <|>+ B { }",
66 "struct S<T> where T: B <|>+ A { }",
67 )
68 }
69
70 #[test]
71 fn flip_trait_bound_works_for_trait_impl() {
72 check_assist(
73 flip_trait_bound,
74 "impl X for S<T> where T: A +<|> B { }",
75 "impl X for S<T> where T: B +<|> A { }",
76 )
77 }
78
79 #[test]
80 fn flip_trait_bound_works_for_fn() {
81 check_assist(flip_trait_bound, "fn f<T: A <|>+ B>(t: T) { }", "fn f<T: B <|>+ A>(t: T) { }")
82 }
83
84 #[test]
85 fn flip_trait_bound_works_for_fn_where_clause() {
86 check_assist(
87 flip_trait_bound,
88 "fn f<T>(t: T) where T: A +<|> B { }",
89 "fn f<T>(t: T) where T: B +<|> A { }",
90 )
91 }
92
93 #[test]
94 fn flip_trait_bound_works_for_lifetime() {
95 check_assist(
96 flip_trait_bound,
97 "fn f<T>(t: T) where T: A <|>+ 'static { }",
98 "fn f<T>(t: T) where T: 'static <|>+ A { }",
99 )
100 }
101
102 #[test]
103 fn flip_trait_bound_works_for_complex_bounds() {
104 check_assist(
105 flip_trait_bound,
106 "struct S<T> where T: A<T> <|>+ b_mod::B<T> + C<T> { }",
107 "struct S<T> where T: b_mod::B<T> <|>+ A<T> + C<T> { }",
108 )
109 }
110
111 #[test]
112 fn flip_trait_bound_works_for_long_bounds() {
113 check_assist(
114 flip_trait_bound,
115 "struct S<T> where T: A + B + C + D + E + F +<|> G + H + I + J { }",
116 "struct S<T> where T: A + B + C + D + E + G +<|> F + H + I + J { }",
117 )
118 }
119}
diff --git a/crates/ra_assists/src/doc_tests.rs b/crates/ra_assists/src/doc_tests.rs
index 0ccf9d730..6e1e3de84 100644
--- a/crates/ra_assists/src/doc_tests.rs
+++ b/crates/ra_assists/src/doc_tests.rs
@@ -17,7 +17,17 @@ fn check(assist_id: &str, before: &str, after: &str) {
17 let (_assist_id, action) = crate::assists(&db, frange) 17 let (_assist_id, action) = crate::assists(&db, frange)
18 .into_iter() 18 .into_iter()
19 .find(|(id, _)| id.id.0 == assist_id) 19 .find(|(id, _)| id.id.0 == assist_id)
20 .unwrap_or_else(|| panic!("Assist {:?} is not applicable", assist_id)); 20 .unwrap_or_else(|| {
21 panic!(
22 "\n\nAssist is not applicable: {}\nAvailable assists: {}",
23 assist_id,
24 crate::assists(&db, frange)
25 .into_iter()
26 .map(|(id, _)| id.id.0)
27 .collect::<Vec<_>>()
28 .join(", ")
29 )
30 });
21 31
22 let actual = action.edit.apply(&before); 32 let actual = action.edit.apply(&before);
23 assert_eq_text!(after, &actual); 33 assert_eq_text!(after, &actual);
diff --git a/crates/ra_assists/src/doc_tests/generated.rs b/crates/ra_assists/src/doc_tests/generated.rs
index b8d335911..ebe49aecf 100644
--- a/crates/ra_assists/src/doc_tests/generated.rs
+++ b/crates/ra_assists/src/doc_tests/generated.rs
@@ -256,6 +256,19 @@ fn main() {
256} 256}
257 257
258#[test] 258#[test]
259fn doctest_flip_trait_bound() {
260 check(
261 "flip_trait_bound",
262 r#####"
263fn foo<T: Clone +<|> Copy>() { }
264"#####,
265 r#####"
266fn foo<T: Copy + Clone>() { }
267"#####,
268 )
269}
270
271#[test]
259fn doctest_inline_local_variable() { 272fn doctest_inline_local_variable() {
260 check( 273 check(
261 "inline_local_variable", 274 "inline_local_variable",
diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs
index 7c226572a..7a1657d87 100644
--- a/crates/ra_assists/src/lib.rs
+++ b/crates/ra_assists/src/lib.rs
@@ -97,6 +97,7 @@ mod assists {
97 mod apply_demorgan; 97 mod apply_demorgan;
98 mod flip_comma; 98 mod flip_comma;
99 mod flip_binexpr; 99 mod flip_binexpr;
100 mod flip_trait_bound;
100 mod change_visibility; 101 mod change_visibility;
101 mod fill_match_arms; 102 mod fill_match_arms;
102 mod merge_match_arms; 103 mod merge_match_arms;
@@ -123,6 +124,7 @@ mod assists {
123 merge_match_arms::merge_match_arms, 124 merge_match_arms::merge_match_arms,
124 flip_comma::flip_comma, 125 flip_comma::flip_comma,
125 flip_binexpr::flip_binexpr, 126 flip_binexpr::flip_binexpr,
127 flip_trait_bound::flip_trait_bound,
126 introduce_variable::introduce_variable, 128 introduce_variable::introduce_variable,
127 replace_if_let_with_match::replace_if_let_with_match, 129 replace_if_let_with_match::replace_if_let_with_match,
128 split_import::split_import, 130 split_import::split_import,