diff --git a/crates/ra_assists/src/handlers/fill_match_arms.rs b/crates/ra_assists/src/handlers/fill_match_arms.rs index cc303285b35d..0b06f2efc0f6 100644 --- a/crates/ra_assists/src/handlers/fill_match_arms.rs +++ b/crates/ra_assists/src/handlers/fill_match_arms.rs @@ -53,11 +53,35 @@ pub(crate) fn fill_match_arms(acc: &mut Assists, ctx: &AssistContext) -> Option< let missing_arms: Vec = if let Some(enum_def) = resolve_enum_def(&ctx.sema, &expr) { let variants = enum_def.variants(ctx.db); + let self_pattern = arms + .first() + .and_then(|arm| arm.pat()) + .and_then(|pat| pat.syntax().first_child()) + .and_then(|node| { + String::from(node.text()).split("::").map(|elt| elt.to_string()).next() + }) + .map(|first_path_seg| first_path_seg.as_str() == "Self") + .unwrap_or_default(); + let mut variants = variants .into_iter() .filter_map(|variant| build_pat(ctx.db, module, variant)) .filter(|variant_pat| is_variant_missing(&mut arms, variant_pat)) - .map(|pat| make::match_arm(iter::once(pat), make::expr_empty_block())) + .map(|pat| { + let pat = if self_pattern { + let pat = pat.syntax().first_child().map(|node| { + String::from(node.text()) + .split("::") + .map(|elt| elt.to_string()) + .skip(1) + .collect::>() + }); + make::path_pat_from_string(format!("Self::{}", pat.unwrap().join("::"))) + } else { + pat + }; + make::match_arm(iter::once(pat), make::expr_empty_block()) + }) .collect::>(); if Some(enum_def) == FamousDefs(&ctx.sema, module.krate()).core_option_Option() { // Match `Some` variant first. @@ -136,8 +160,12 @@ fn is_variant_missing(existing_arms: &mut Vec, var: &Pat) -> bool { } fn does_pat_match_variant(pat: &Pat, var: &Pat) -> bool { - let pat_head = pat.syntax().first_child().map(|node| node.text()); - let var_head = var.syntax().first_child().map(|node| node.text()); + let pat_head = pat.syntax().first_child().map(|node| { + String::from(node.text()).split("::").map(|elt| elt.to_string()).skip(1).join("::") + }); + let var_head = var.syntax().first_child().map(|node| { + String::from(node.text()).split("::").map(|elt| elt.to_string()).skip(1).join("::") + }); pat_head == var_head } @@ -686,6 +714,34 @@ mod tests { ); } + #[test] + fn fill_match_arms_with_self() { + check_assist( + fill_match_arms, + r#" + enum A { One, Two } + impl A { + fn foo(self) { + match self { + Self::One => {},<|> + } + } + } + "#, + r#" + enum A { One, Two } + impl A { + fn foo(self) { + match self { + Self::One => {}, + $0Self::Two => {} + } + } + } + "#, + ); + } + #[test] fn fill_match_arms_placeholder() { check_assist( diff --git a/crates/ra_syntax/src/ast/make.rs b/crates/ra_syntax/src/ast/make.rs index da0eb09267ff..0f86fa3d45e0 100644 --- a/crates/ra_syntax/src/ast/make.rs +++ b/crates/ra_syntax/src/ast/make.rs @@ -203,6 +203,13 @@ pub fn path_pat(path: ast::Path) -> ast::Pat { } } +pub fn path_pat_from_string(path: String) -> ast::Pat { + return from_text(&path); + fn from_text(text: &str) -> ast::Pat { + ast_from_text(&format!("fn f({}: ())", text)) + } +} + pub fn match_arm(pats: impl IntoIterator, expr: ast::Expr) -> ast::MatchArm { let pats_str = pats.into_iter().join(" | "); return from_text(&format!("{} => {}", pats_str, expr));