]> git.lizzy.rs Git - rust.git/blob - crates/ra_assists/src/handlers/flip_trait_bound.rs
Refactor assists API to be more convenient for adding new assists
[rust.git] / crates / ra_assists / src / handlers / flip_trait_bound.rs
1 use ra_syntax::{
2     algo::non_trivia_sibling,
3     ast::{self, AstNode},
4     Direction, T,
5 };
6
7 use crate::{AssistContext, AssistId, Assists};
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 // ```
20 pub(crate) fn flip_trait_bound(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
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     let target = plus.text_range();
36     acc.add(AssistId("flip_trait_bound"), "Flip trait bounds", target, |edit| {
37         edit.replace(before.text_range(), after.to_string());
38         edit.replace(after.text_range(), before.to_string());
39     })
40 }
41
42 #[cfg(test)]
43 mod tests {
44     use super::*;
45
46     use crate::tests::{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 }