1 use std::iter::successors;
9 use crate::{AssistContext, AssistId, AssistKind, Assists, TextRange};
11 // Assist: merge_match_arms
13 // Merges the current match arm with the following if their bodies are identical.
16 // enum Action { Move { distance: u32 }, Stop }
18 // fn handle(action: Action) {
20 // $0Action::Move(..) => foo(),
21 // Action::Stop => foo(),
27 // enum Action { Move { distance: u32 }, Stop }
29 // fn handle(action: Action) {
31 // Action::Move(..) | Action::Stop => foo(),
35 pub(crate) fn merge_match_arms(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
36 let current_arm = ctx.find_node_at_offset::<ast::MatchArm>()?;
37 // Don't try to handle arms with guards for now - can add support for this later
38 if current_arm.guard().is_some() {
41 let current_expr = current_arm.expr()?;
42 let current_text_range = current_arm.syntax().text_range();
44 // We check if the following match arms match this one. We could, but don't,
45 // compare to the previous match arm as well.
46 let arms_to_merge = successors(Some(current_arm), |it| neighbor(it, Direction::Next))
47 .take_while(|arm| match arm.expr() {
48 Some(expr) if arm.guard().is_none() => {
49 expr.syntax().text() == current_expr.syntax().text()
55 if arms_to_merge.len() <= 1 {
60 AssistId("merge_match_arms", AssistKind::RefactorRewrite),
64 let pats = if arms_to_merge.iter().any(contains_placeholder) {
69 .filter_map(ast::MatchArm::pat)
70 .map(|x| x.syntax().to_string())
71 .collect::<Vec<String>>()
75 let arm = format!("{} => {},", pats, current_expr.syntax().text());
77 if let [first, .., last] = &*arms_to_merge {
78 let start = first.syntax().text_range().start();
79 let end = last.syntax().text_range().end();
81 edit.replace(TextRange::new(start, end), arm);
87 fn contains_placeholder(a: &ast::MatchArm) -> bool {
88 matches!(a.pat(), Some(ast::Pat::WildcardPat(..)))
93 use crate::tests::{check_assist, check_assist_not_applicable};
98 fn merge_match_arms_single_patterns() {
121 X::A | X::B => { 1i32 },
130 fn merge_match_arms_multiple_patterns() {
135 enum X { A, B, C, D, E }
140 X::A | X::B => {$0 1i32 },
141 X::C | X::D => { 1i32 },
148 enum X { A, B, C, D, E }
153 X::A | X::B | X::C | X::D => { 1i32 },
162 fn merge_match_arms_placeholder_pattern() {
167 enum X { A, B, C, D, E }
180 enum X { A, B, C, D, E }
194 fn merges_all_subsequent_arms() {
198 enum X { A, B, C, D, E }
211 enum X { A, B, C, D, E }
215 X::A | X::B | X::C => 92,
225 fn merge_match_arms_rejects_guards() {
226 check_assist_not_applicable(
239 X::A(a) if a > 5 => { $01i32 },