From 35f2e82e0b381f2f324970fc1464ad29a1151a96 Mon Sep 17 00:00:00 2001 From: DropDemBits Date: Sun, 9 Jul 2023 02:32:44 -0400 Subject: [PATCH] Don't show `add_missing_match_arms` when not needed `does_not_fill_wildcard_with_wildcard` and `does_not_fill_wildcard_with_partial_wildcard_and_wildcard` both made no modifications to the code, which is a problem for mutable ast porting as it generates a best-effort minimal set of text edits, and assists require at least one text edit. --- .../src/handlers/add_missing_match_arms.rs | 79 +++++++++++-------- 1 file changed, 45 insertions(+), 34 deletions(-) diff --git a/crates/ide-assists/src/handlers/add_missing_match_arms.rs b/crates/ide-assists/src/handlers/add_missing_match_arms.rs index 7384390f28b..2c7d8fc63a2 100644 --- a/crates/ide-assists/src/handlers/add_missing_match_arms.rs +++ b/crates/ide-assists/src/handlers/add_missing_match_arms.rs @@ -75,14 +75,18 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>) .collect(); let module = ctx.sema.scope(expr.syntax())?.module(); - let (mut missing_pats, is_non_exhaustive): ( + let (mut missing_pats, is_non_exhaustive, has_hidden_variants): ( Peekable>>, bool, + bool, ) = if let Some(enum_def) = resolve_enum_def(&ctx.sema, &expr) { let is_non_exhaustive = enum_def.is_non_exhaustive(ctx.db(), module.krate()); let variants = enum_def.variants(ctx.db()); + let has_hidden_variants = + variants.iter().any(|variant| variant.should_be_hidden(ctx.db(), module.krate())); + let missing_pats = variants .into_iter() .filter_map(|variant| { @@ -101,7 +105,7 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>) } else { Box::new(missing_pats) }; - (missing_pats.peekable(), is_non_exhaustive) + (missing_pats.peekable(), is_non_exhaustive, has_hidden_variants) } else if let Some(enum_defs) = resolve_tuple_of_enum_def(&ctx.sema, &expr) { let is_non_exhaustive = enum_defs.iter().any(|enum_def| enum_def.is_non_exhaustive(ctx.db(), module.krate())); @@ -124,6 +128,12 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>) if n_arms > 256 { return None; } + + let has_hidden_variants = variants_of_enums + .iter() + .flatten() + .any(|variant| variant.should_be_hidden(ctx.db(), module.krate())); + let missing_pats = variants_of_enums .into_iter() .multi_cartesian_product() @@ -139,7 +149,11 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>) (ast::Pat::from(make::tuple_pat(patterns)), is_hidden) }) .filter(|(variant_pat, _)| is_variant_missing(&top_lvl_pats, variant_pat)); - ((Box::new(missing_pats) as Box>).peekable(), is_non_exhaustive) + ( + (Box::new(missing_pats) as Box>).peekable(), + is_non_exhaustive, + has_hidden_variants, + ) } else if let Some((enum_def, len)) = resolve_array_of_enum_def(&ctx.sema, &expr) { let is_non_exhaustive = enum_def.is_non_exhaustive(ctx.db(), module.krate()); let variants = enum_def.variants(ctx.db()); @@ -148,6 +162,9 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>) return None; } + let has_hidden_variants = + variants.iter().any(|variant| variant.should_be_hidden(ctx.db(), module.krate())); + let variants_of_enums = vec![variants; len]; let missing_pats = variants_of_enums @@ -164,14 +181,20 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>) (ast::Pat::from(make::slice_pat(patterns)), is_hidden) }) .filter(|(variant_pat, _)| is_variant_missing(&top_lvl_pats, variant_pat)); - ((Box::new(missing_pats) as Box>).peekable(), is_non_exhaustive) + ( + (Box::new(missing_pats) as Box>).peekable(), + is_non_exhaustive, + has_hidden_variants, + ) } else { return None; }; let mut needs_catch_all_arm = is_non_exhaustive && !has_catch_all_arm; - if !needs_catch_all_arm && missing_pats.peek().is_none() { + if !needs_catch_all_arm + && ((has_hidden_variants && has_catch_all_arm) || missing_pats.peek().is_none()) + { return None; } @@ -181,11 +204,17 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>) target_range, |builder| { let new_match_arm_list = match_arm_list.clone_for_update(); - let missing_arms = missing_pats - .map(|(pat, hidden)| { - (make::match_arm(iter::once(pat), None, make::ext::expr_todo()), hidden) + + // having any hidden variants means that we need a catch-all arm + needs_catch_all_arm |= has_hidden_variants; + + let missing_arms = missing_pats.filter_map(|(pat, hidden)| { + // filter out hidden patterns because they're handled by the catch-all arm + (!hidden).then(|| { + make::match_arm(iter::once(pat), None, make::ext::expr_todo()) + .clone_for_update() }) - .map(|(it, hidden)| (it.clone_for_update(), hidden)); + }); let catch_all_arm = new_match_arm_list .arms() @@ -204,15 +233,13 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>) cov_mark::hit!(add_missing_match_arms_empty_expr); } } + let mut first_new_arm = None; - for (arm, hidden) in missing_arms { - if hidden { - needs_catch_all_arm = !has_catch_all_arm; - } else { - first_new_arm.get_or_insert_with(|| arm.clone()); - new_match_arm_list.add_arm(arm); - } + for arm in missing_arms { + first_new_arm.get_or_insert_with(|| arm.clone()); + new_match_arm_list.add_arm(arm); } + if needs_catch_all_arm && !has_catch_all_arm { cov_mark::hit!(added_wildcard_pattern); let arm = make::match_arm( @@ -1621,10 +1648,9 @@ pub enum E { #[doc(hidden)] A, } ); } - // FIXME: I don't think the assist should be applicable in this case #[test] fn does_not_fill_wildcard_with_wildcard() { - check_assist( + check_assist_not_applicable( add_missing_match_arms, r#" //- /main.rs crate:main deps:e @@ -1635,13 +1661,6 @@ fn foo(t: ::e::E) { } //- /e.rs crate:e pub enum E { #[doc(hidden)] A, } -"#, - r#" -fn foo(t: ::e::E) { - match t { - _ => todo!(), - } -} "#, ); } @@ -1777,7 +1796,7 @@ fn foo(t: ::e::E, b: bool) { #[test] fn does_not_fill_wildcard_with_partial_wildcard_and_wildcard() { - check_assist( + check_assist_not_applicable( add_missing_match_arms, r#" //- /main.rs crate:main deps:e @@ -1789,14 +1808,6 @@ fn foo(t: ::e::E, b: bool) { } //- /e.rs crate:e pub enum E { #[doc(hidden)] A, }"#, - r#" -fn foo(t: ::e::E, b: bool) { - match t { - _ if b => todo!(), - _ => todo!(), - } -} -"#, ); }