aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhil Ellison <[email protected]>2019-07-29 21:59:52 +0100
committerPhil Ellison <[email protected]>2019-07-29 21:59:52 +0100
commite6113c09980043dd3d9a57eca8fef96c011a5da5 (patch)
tree343e1f7c5ccb8ec52ed5bec092ada5d937d77473
parenta5fe9f7a877bdb4dc35226d1cbac2b4870fde276 (diff)
Add merge_match_arm assist, bump rowan to 0.6.1
-rw-r--r--Cargo.lock6
-rw-r--r--crates/ra_assists/src/lib.rs2
-rw-r--r--crates/ra_assists/src/merge_match_arms.rs188
-rw-r--r--crates/ra_syntax/Cargo.toml2
4 files changed, 194 insertions, 4 deletions
diff --git a/Cargo.lock b/Cargo.lock
index fd4d876de..717b038f2 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1326,7 +1326,7 @@ dependencies = [
1326 "ra_parser 0.1.0", 1326 "ra_parser 0.1.0",
1327 "ra_rustc_lexer 0.1.0-pre.2 (registry+https://github.com/rust-lang/crates.io-index)", 1327 "ra_rustc_lexer 0.1.0-pre.2 (registry+https://github.com/rust-lang/crates.io-index)",
1328 "ra_text_edit 0.1.0", 1328 "ra_text_edit 0.1.0",
1329 "rowan 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", 1329 "rowan 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
1330 "smol_str 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", 1330 "smol_str 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
1331 "test_utils 0.1.0", 1331 "test_utils 0.1.0",
1332 "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 1332 "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1596,7 +1596,7 @@ dependencies = [
1596 1596
1597[[package]] 1597[[package]]
1598name = "rowan" 1598name = "rowan"
1599version = "0.6.0" 1599version = "0.6.1"
1600source = "registry+https://github.com/rust-lang/crates.io-index" 1600source = "registry+https://github.com/rust-lang/crates.io-index"
1601dependencies = [ 1601dependencies = [
1602 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 1602 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2281,7 +2281,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
2281"checksum relative-path 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0e7790c7f1cc73d831d28dc5a7deb316a006e7848e6a7f467cdb10a0a9e0fb1c" 2281"checksum relative-path 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0e7790c7f1cc73d831d28dc5a7deb316a006e7848e6a7f467cdb10a0a9e0fb1c"
2282"checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e" 2282"checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e"
2283"checksum ron 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "17f52a24414403f81528b67488cf8edc4eda977d3af1646bb6b106a600ead78f" 2283"checksum ron 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "17f52a24414403f81528b67488cf8edc4eda977d3af1646bb6b106a600ead78f"
2284"checksum rowan 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a796c0517d6969224c42e9ef01356363b0a7c57d10ec986c9a600d075666a5ff" 2284"checksum rowan 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "03e34c2e5f01d7fa4ab7e6a49da44f59fb38ffb61e6c9f714deb8e157274c2c7"
2285"checksum rustc-demangle 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "a7f4dccf6f4891ebcc0c39f9b6eb1a83b9bf5d747cb439ec6fba4f3b977038af" 2285"checksum rustc-demangle 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "a7f4dccf6f4891ebcc0c39f9b6eb1a83b9bf5d747cb439ec6fba4f3b977038af"
2286"checksum rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7540fc8b0c49f096ee9c961cda096467dce8084bec6bdca2fc83895fd9b28cb8" 2286"checksum rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7540fc8b0c49f096ee9c961cda096467dce8084bec6bdca2fc83895fd9b28cb8"
2287"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" 2287"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs
index 0d848629d..03eec73ad 100644
--- a/crates/ra_assists/src/lib.rs
+++ b/crates/ra_assists/src/lib.rs
@@ -93,6 +93,7 @@ mod flip_comma;
93mod flip_binexpr; 93mod flip_binexpr;
94mod change_visibility; 94mod change_visibility;
95mod fill_match_arms; 95mod fill_match_arms;
96mod merge_match_arms;
96mod introduce_variable; 97mod introduce_variable;
97mod inline_local_variable; 98mod inline_local_variable;
98mod replace_if_let_with_match; 99mod replace_if_let_with_match;
@@ -109,6 +110,7 @@ fn all_assists<DB: HirDatabase>() -> &'static [fn(AssistCtx<DB>) -> Option<Assis
109 add_impl::add_impl, 110 add_impl::add_impl,
110 change_visibility::change_visibility, 111 change_visibility::change_visibility,
111 fill_match_arms::fill_match_arms, 112 fill_match_arms::fill_match_arms,
113 merge_match_arms::merge_match_arms,
112 flip_comma::flip_comma, 114 flip_comma::flip_comma,
113 flip_binexpr::flip_binexpr, 115 flip_binexpr::flip_binexpr,
114 introduce_variable::introduce_variable, 116 introduce_variable::introduce_variable,
diff --git a/crates/ra_assists/src/merge_match_arms.rs b/crates/ra_assists/src/merge_match_arms.rs
new file mode 100644
index 000000000..bc5f6f17c
--- /dev/null
+++ b/crates/ra_assists/src/merge_match_arms.rs
@@ -0,0 +1,188 @@
1use crate::{Assist, AssistCtx, AssistId, TextRange, TextUnit};
2use hir::db::HirDatabase;
3use ra_syntax::ast::{AstNode, MatchArm};
4
5pub(crate) fn merge_match_arms(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
6 let current_arm = ctx.node_at_offset::<MatchArm>()?;
7
8 // We check if the following match arm matches this one. We could, but don't,
9 // compare to the previous match arm as well.
10 let next = current_arm.syntax().next_sibling();
11 let next_arm = MatchArm::cast(next?.clone())?;
12
13 // Don't try to handle arms with guards for now - can add support for this later
14 if current_arm.guard().is_some() || next_arm.guard().is_some() {
15 return None;
16 }
17
18 let current_expr = current_arm.expr()?;
19 let next_expr = next_arm.expr()?;
20
21 // Check for match arm equality by comparing lengths and then string contents
22 if current_expr.syntax().text_range().len() != next_expr.syntax().text_range().len() {
23 return None;
24 }
25 if current_expr.syntax().text() != next_expr.syntax().text() {
26 return None;
27 }
28
29 let cursor_to_end = current_arm.syntax().text_range().end() - ctx.frange.range.start();
30
31 ctx.add_action(AssistId("merge_match_arms"), "merge match arms", |edit| {
32 fn contains_placeholder(a: &MatchArm) -> bool {
33 a.pats().any(|x| match x.kind() {
34 ra_syntax::ast::PatKind::PlaceholderPat(..) => true,
35 _ => false,
36 })
37 }
38
39 let pats = if contains_placeholder(&current_arm) || contains_placeholder(&next_arm) {
40 "_".into()
41 } else {
42 let ps: Vec<String> = current_arm
43 .pats()
44 .map(|x| x.syntax().to_string())
45 .chain(next_arm.pats().map(|x| x.syntax().to_string()))
46 .collect();
47 ps.join(" | ")
48 };
49
50 let arm = format!("{} => {}", pats, current_expr.syntax().text());
51 let offset = TextUnit::from_usize(arm.len()) - cursor_to_end;
52
53 let start = current_arm.syntax().text_range().start();
54 let end = next_arm.syntax().text_range().end();
55
56 edit.target(current_arm.syntax().text_range());
57 edit.replace(TextRange::from_to(start, end), arm);
58 edit.set_cursor(start + offset);
59 });
60
61 ctx.build()
62}
63
64#[cfg(test)]
65mod tests {
66 use super::merge_match_arms;
67 use crate::helpers::{check_assist, check_assist_not_applicable};
68
69 #[test]
70 fn merge_match_arms_single_patterns() {
71 check_assist(
72 merge_match_arms,
73 r#"
74 #[derive(Debug)]
75 enum X { A, B, C }
76
77 fn main() {
78 let x = X::A;
79 let y = match x {
80 X::A => { 1i32<|> }
81 X::B => { 1i32 }
82 X::C => { 2i32 }
83 }
84 }
85 "#,
86 r#"
87 #[derive(Debug)]
88 enum X { A, B, C }
89
90 fn main() {
91 let x = X::A;
92 let y = match x {
93 X::A | X::B => { 1i32<|> }
94 X::C => { 2i32 }
95 }
96 }
97 "#,
98 );
99 }
100
101 #[test]
102 fn merge_match_arms_multiple_patterns() {
103 check_assist(
104 merge_match_arms,
105 r#"
106 #[derive(Debug)]
107 enum X { A, B, C, D, E }
108
109 fn main() {
110 let x = X::A;
111 let y = match x {
112 X::A | X::B => {<|> 1i32 },
113 X::C | X::D => { 1i32 },
114 X::E => { 2i32 },
115 }
116 }
117 "#,
118 r#"
119 #[derive(Debug)]
120 enum X { A, B, C, D, E }
121
122 fn main() {
123 let x = X::A;
124 let y = match x {
125 X::A | X::B | X::C | X::D => {<|> 1i32 },
126 X::E => { 2i32 },
127 }
128 }
129 "#,
130 );
131 }
132
133 #[test]
134 fn merge_match_arms_placeholder_pattern() {
135 check_assist(
136 merge_match_arms,
137 r#"
138 #[derive(Debug)]
139 enum X { A, B, C, D, E }
140
141 fn main() {
142 let x = X::A;
143 let y = match x {
144 X::A => { 1i32 },
145 X::B => { 2i<|>32 },
146 _ => { 2i32 }
147 }
148 }
149 "#,
150 r#"
151 #[derive(Debug)]
152 enum X { A, B, C, D, E }
153
154 fn main() {
155 let x = X::A;
156 let y = match x {
157 X::A => { 1i32 },
158 _ => { 2i<|>32 }
159 }
160 }
161 "#,
162 );
163 }
164
165 #[test]
166 fn merge_match_arms_rejects_guards() {
167 check_assist_not_applicable(
168 merge_match_arms,
169 r#"
170 #[derive(Debug)]
171 enum X {
172 A(i32),
173 B,
174 C
175 }
176
177 fn main() {
178 let x = X::A;
179 let y = match x {
180 X::A(a) if a > 5 => { <|>1i32 },
181 X::B => { 1i32 },
182 X::C => { 2i32 }
183 }
184 }
185 "#,
186 );
187 }
188}
diff --git a/crates/ra_syntax/Cargo.toml b/crates/ra_syntax/Cargo.toml
index 40d63ef7a..bc1c88070 100644
--- a/crates/ra_syntax/Cargo.toml
+++ b/crates/ra_syntax/Cargo.toml
@@ -10,7 +10,7 @@ repository = "https://github.com/rust-analyzer/rust-analyzer"
10[dependencies] 10[dependencies]
11unicode-xid = "0.1.0" 11unicode-xid = "0.1.0"
12itertools = "0.8.0" 12itertools = "0.8.0"
13rowan = "0.6.0" 13rowan = "0.6.1"
14ra_rustc_lexer = { version = "0.1.0-pre.2" } 14ra_rustc_lexer = { version = "0.1.0-pre.2" }
15 15
16# ideally, `serde` should be enabled by `ra_lsp_server`, but we enable it here 16# ideally, `serde` should be enabled by `ra_lsp_server`, but we enable it here