From d8881d98d3d1c88335c5f00328f1f2fc0100dd62 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 20 May 2020 10:51:48 +0200 Subject: [PATCH] Fix Some|None order in fill_match_arms --- .../src/handlers/fill_match_arms.rs | 44 +++++++++++++++++-- crates/ra_assists/src/marks.rs | 1 + crates/ra_assists/src/utils.rs | 35 ++++++++++++--- 3 files changed, 69 insertions(+), 11 deletions(-) diff --git a/crates/ra_assists/src/handlers/fill_match_arms.rs b/crates/ra_assists/src/handlers/fill_match_arms.rs index 13c1e7e8014..b57ff75aedb 100644 --- a/crates/ra_assists/src/handlers/fill_match_arms.rs +++ b/crates/ra_assists/src/handlers/fill_match_arms.rs @@ -4,8 +4,9 @@ use hir::{Adt, HasSource, ModuleDef, Semantics}; use itertools::Itertools; use ra_ide_db::RootDatabase; use ra_syntax::ast::{self, make, AstNode, MatchArm, NameOwner, Pat}; +use test_utils::tested_by; -use crate::{AssistContext, AssistId, Assists}; +use crate::{utils::FamousDefs, AssistContext, AssistId, Assists}; // Assist: fill_match_arms // @@ -49,12 +50,18 @@ 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); - variants + 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())) - .collect() + .collect::>(); + if Some(enum_def) == FamousDefs(&ctx.sema, module.krate()).core_option_Option() { + // Match `Some` variant first. + tested_by!(option_order); + variants.reverse() + } + variants } else if let Some(enum_defs) = resolve_tuple_of_enum_def(&ctx.sema, &expr) { // Partial fill not currently supported for tuple of enums. if !arms.is_empty() { @@ -167,9 +174,13 @@ fn build_pat(db: &RootDatabase, module: hir::Module, var: hir::EnumVariant) -> O #[cfg(test)] mod tests { - use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target}; + use crate::{ + tests::{check_assist, check_assist_not_applicable, check_assist_target}, + utils::FamousDefs, + }; use super::fill_match_arms; + use test_utils::covers; #[test] fn all_match_arms_provided() { @@ -736,4 +747,29 @@ mod tests { "#, ); } + + #[test] + fn option_order() { + covers!(option_order); + let before = r#" +fn foo(opt: Option) { + match opt<|> { + } +}"#; + let before = + &format!("//- main.rs crate:main deps:core\n{}{}", before, FamousDefs::FIXTURE); + + check_assist( + fill_match_arms, + before, + r#" +fn foo(opt: Option) { + match <|>opt { + Some(_) => {} + None => {} + } +} +"#, + ); + } } diff --git a/crates/ra_assists/src/marks.rs b/crates/ra_assists/src/marks.rs index d579e627f04..722f3c6a4b7 100644 --- a/crates/ra_assists/src/marks.rs +++ b/crates/ra_assists/src/marks.rs @@ -1,6 +1,7 @@ //! See test_utils/src/marks.rs test_utils::marks![ + option_order introduce_var_in_comment_is_not_applicable test_introduce_var_expr_stmt test_introduce_var_last_expr diff --git a/crates/ra_assists/src/utils.rs b/crates/ra_assists/src/utils.rs index 9af27180bc5..0038a9764b1 100644 --- a/crates/ra_assists/src/utils.rs +++ b/crates/ra_assists/src/utils.rs @@ -3,7 +3,7 @@ pub(crate) mod insert_use; use std::{iter, ops}; -use hir::{Adt, Crate, Semantics, Trait, Type}; +use hir::{Adt, Crate, Enum, ScopeDef, Semantics, Trait, Type}; use ra_ide_db::RootDatabase; use ra_syntax::{ ast::{self, make, NameOwner}, @@ -200,13 +200,19 @@ impl FamousDefs<'_, '_> { #[cfg(test)] pub(crate) const FIXTURE: &'static str = r#" //- /libcore.rs crate:core -pub mod convert{ +pub mod convert { pub trait From { fn from(T) -> Self; } } -pub mod prelude { pub use crate::convert::From } +pub mod option { + pub enum Option { None, Some(T)} +} + +pub mod prelude { + pub use crate::{convert::From, option::Option::{self, *}}; +} #[prelude_import] pub use prelude::*; "#; @@ -215,7 +221,25 @@ pub use prelude::*; self.find_trait("core:convert:From") } + pub(crate) fn core_option_Option(&self) -> Option { + self.find_enum("core:option:Option") + } + fn find_trait(&self, path: &str) -> Option { + match self.find_def(path)? { + hir::ScopeDef::ModuleDef(hir::ModuleDef::Trait(it)) => Some(it), + _ => None, + } + } + + fn find_enum(&self, path: &str) -> Option { + match self.find_def(path)? { + hir::ScopeDef::ModuleDef(hir::ModuleDef::Adt(hir::Adt::Enum(it))) => Some(it), + _ => None, + } + } + + fn find_def(&self, path: &str) -> Option { let db = self.0.db; let mut path = path.split(':'); let trait_ = path.next_back()?; @@ -240,9 +264,6 @@ pub use prelude::*; } let def = module.scope(db, None).into_iter().find(|(name, _def)| &name.to_string() == trait_)?.1; - match def { - hir::ScopeDef::ModuleDef(hir::ModuleDef::Trait(it)) => Some(it), - _ => None, - } + Some(def) } }