aboutsummaryrefslogtreecommitdiff
path: root/crates/assists/src/handlers/flip_trait_bound.rs
diff options
context:
space:
mode:
authorZac Pullar-Strecker <[email protected]>2020-08-24 10:19:53 +0100
committerZac Pullar-Strecker <[email protected]>2020-08-24 10:20:13 +0100
commit7bbca7a1b3f9293d2f5cc5745199bc5f8396f2f0 (patch)
treebdb47765991cb973b2cd5481a088fac636bd326c /crates/assists/src/handlers/flip_trait_bound.rs
parentca464650eeaca6195891199a93f4f76cf3e7e697 (diff)
parente65d48d1fb3d4d91d9dc1148a7a836ff5c9a3c87 (diff)
Merge remote-tracking branch 'upstream/master' into 503-hover-doc-links
Diffstat (limited to 'crates/assists/src/handlers/flip_trait_bound.rs')
-rw-r--r--crates/assists/src/handlers/flip_trait_bound.rs121
1 files changed, 121 insertions, 0 deletions
diff --git a/crates/assists/src/handlers/flip_trait_bound.rs b/crates/assists/src/handlers/flip_trait_bound.rs
new file mode 100644
index 000000000..347e79b1d
--- /dev/null
+++ b/crates/assists/src/handlers/flip_trait_bound.rs
@@ -0,0 +1,121 @@
1use syntax::{
2 algo::non_trivia_sibling,
3 ast::{self, AstNode},
4 Direction, T,
5};
6
7use crate::{AssistContext, AssistId, AssistKind, 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// ```
20pub(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(
37 AssistId("flip_trait_bound", AssistKind::RefactorRewrite),
38 "Flip trait bounds",
39 target,
40 |edit| {
41 edit.replace(before.text_range(), after.to_string());
42 edit.replace(after.text_range(), before.to_string());
43 },
44 )
45}
46
47#[cfg(test)]
48mod tests {
49 use super::*;
50
51 use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target};
52
53 #[test]
54 fn flip_trait_bound_assist_available() {
55 check_assist_target(flip_trait_bound, "struct S<T> where T: A <|>+ B + C { }", "+")
56 }
57
58 #[test]
59 fn flip_trait_bound_not_applicable_for_single_trait_bound() {
60 check_assist_not_applicable(flip_trait_bound, "struct S<T> where T: <|>A { }")
61 }
62
63 #[test]
64 fn flip_trait_bound_works_for_struct() {
65 check_assist(
66 flip_trait_bound,
67 "struct S<T> where T: A <|>+ B { }",
68 "struct S<T> where T: B + A { }",
69 )
70 }
71
72 #[test]
73 fn flip_trait_bound_works_for_trait_impl() {
74 check_assist(
75 flip_trait_bound,
76 "impl X for S<T> where T: A +<|> B { }",
77 "impl X for S<T> where T: B + A { }",
78 )
79 }
80
81 #[test]
82 fn flip_trait_bound_works_for_fn() {
83 check_assist(flip_trait_bound, "fn f<T: A <|>+ B>(t: T) { }", "fn f<T: B + A>(t: T) { }")
84 }
85
86 #[test]
87 fn flip_trait_bound_works_for_fn_where_clause() {
88 check_assist(
89 flip_trait_bound,
90 "fn f<T>(t: T) where T: A +<|> B { }",
91 "fn f<T>(t: T) where T: B + A { }",
92 )
93 }
94
95 #[test]
96 fn flip_trait_bound_works_for_lifetime() {
97 check_assist(
98 flip_trait_bound,
99 "fn f<T>(t: T) where T: A <|>+ 'static { }",
100 "fn f<T>(t: T) where T: 'static + A { }",
101 )
102 }
103
104 #[test]
105 fn flip_trait_bound_works_for_complex_bounds() {
106 check_assist(
107 flip_trait_bound,
108 "struct S<T> where T: A<T> <|>+ b_mod::B<T> + C<T> { }",
109 "struct S<T> where T: b_mod::B<T> + A<T> + C<T> { }",
110 )
111 }
112
113 #[test]
114 fn flip_trait_bound_works_for_long_bounds() {
115 check_assist(
116 flip_trait_bound,
117 "struct S<T> where T: A + B + C + D + E + F +<|> G + H + I + J { }",
118 "struct S<T> where T: A + B + C + D + E + G + F + H + I + J { }",
119 )
120 }
121}