aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_assists/src/handlers/flip_trait_bound.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_assists/src/handlers/flip_trait_bound.rs')
-rw-r--r--crates/ra_assists/src/handlers/flip_trait_bound.rs116
1 files changed, 116 insertions, 0 deletions
diff --git a/crates/ra_assists/src/handlers/flip_trait_bound.rs b/crates/ra_assists/src/handlers/flip_trait_bound.rs
new file mode 100644
index 000000000..f56769624
--- /dev/null
+++ b/crates/ra_assists/src/handlers/flip_trait_bound.rs
@@ -0,0 +1,116 @@
1use ra_syntax::{
2 algo::non_trivia_sibling,
3 ast::{self, AstNode},
4 Direction, T,
5};
6
7use crate::{Assist, AssistCtx, AssistId};
8
9// Assist: flip_trait_bound
10//
11// Flips two trait bounds.
12//
13// ```
14// fn foo<T: Clone +<|> Copy>() { }
15// ```
16// ->
17// ```
18// fn foo<T: Copy + Clone>() { }
19// ```
20pub(crate) fn flip_trait_bound(ctx: AssistCtx) -> Option<Assist> {
21 // We want to replicate the behavior of `flip_binexpr` by only suggesting
22 // the assist when the cursor is on a `+`
23 let plus = ctx.find_token_at_offset(T![+])?;
24
25 // Make sure we're in a `TypeBoundList`
26 if ast::TypeBoundList::cast(plus.parent()).is_none() {
27 return None;
28 }
29
30 let (before, after) = (
31 non_trivia_sibling(plus.clone().into(), Direction::Prev)?,
32 non_trivia_sibling(plus.clone().into(), Direction::Next)?,
33 );
34
35 ctx.add_assist(AssistId("flip_trait_bound"), "Flip trait bounds", |edit| {
36 edit.target(plus.text_range());
37 edit.replace(before.text_range(), after.to_string());
38 edit.replace(after.text_range(), before.to_string());
39 })
40}
41
42#[cfg(test)]
43mod tests {
44 use super::*;
45
46 use crate::helpers::{check_assist, check_assist_not_applicable, check_assist_target};
47
48 #[test]
49 fn flip_trait_bound_assist_available() {
50 check_assist_target(flip_trait_bound, "struct S<T> where T: A <|>+ B + C { }", "+")
51 }
52
53 #[test]
54 fn flip_trait_bound_not_applicable_for_single_trait_bound() {
55 check_assist_not_applicable(flip_trait_bound, "struct S<T> where T: <|>A { }")
56 }
57
58 #[test]
59 fn flip_trait_bound_works_for_struct() {
60 check_assist(
61 flip_trait_bound,
62 "struct S<T> where T: A <|>+ B { }",
63 "struct S<T> where T: B <|>+ A { }",
64 )
65 }
66
67 #[test]
68 fn flip_trait_bound_works_for_trait_impl() {
69 check_assist(
70 flip_trait_bound,
71 "impl X for S<T> where T: A +<|> B { }",
72 "impl X for S<T> where T: B +<|> A { }",
73 )
74 }
75
76 #[test]
77 fn flip_trait_bound_works_for_fn() {
78 check_assist(flip_trait_bound, "fn f<T: A <|>+ B>(t: T) { }", "fn f<T: B <|>+ A>(t: T) { }")
79 }
80
81 #[test]
82 fn flip_trait_bound_works_for_fn_where_clause() {
83 check_assist(
84 flip_trait_bound,
85 "fn f<T>(t: T) where T: A +<|> B { }",
86 "fn f<T>(t: T) where T: B +<|> A { }",
87 )
88 }
89
90 #[test]
91 fn flip_trait_bound_works_for_lifetime() {
92 check_assist(
93 flip_trait_bound,
94 "fn f<T>(t: T) where T: A <|>+ 'static { }",
95 "fn f<T>(t: T) where T: 'static <|>+ A { }",
96 )
97 }
98
99 #[test]
100 fn flip_trait_bound_works_for_complex_bounds() {
101 check_assist(
102 flip_trait_bound,
103 "struct S<T> where T: A<T> <|>+ b_mod::B<T> + C<T> { }",
104 "struct S<T> where T: b_mod::B<T> <|>+ A<T> + C<T> { }",
105 )
106 }
107
108 #[test]
109 fn flip_trait_bound_works_for_long_bounds() {
110 check_assist(
111 flip_trait_bound,
112 "struct S<T> where T: A + B + C + D + E + F +<|> G + H + I + J { }",
113 "struct S<T> where T: A + B + C + D + E + G +<|> F + H + I + J { }",
114 )
115 }
116}