4529: Fix Some|None order in fill_match_arms r=matklad a=matklad



bors r+
🤖

Co-authored-by: Aleksey Kladov <aleksey.kladov@gmail.com>
This commit is contained in:
bors[bot] 2020-05-20 08:52:34 +00:00 committed by GitHub
commit b422cef7dc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 69 additions and 11 deletions

View File

@ -4,8 +4,9 @@
use itertools::Itertools; use itertools::Itertools;
use ra_ide_db::RootDatabase; use ra_ide_db::RootDatabase;
use ra_syntax::ast::{self, make, AstNode, MatchArm, NameOwner, Pat}; 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 // Assist: fill_match_arms
// //
@ -49,12 +50,18 @@ pub(crate) fn fill_match_arms(acc: &mut Assists, ctx: &AssistContext) -> Option<
let missing_arms: Vec<MatchArm> = if let Some(enum_def) = resolve_enum_def(&ctx.sema, &expr) { let missing_arms: Vec<MatchArm> = if let Some(enum_def) = resolve_enum_def(&ctx.sema, &expr) {
let variants = enum_def.variants(ctx.db); let variants = enum_def.variants(ctx.db);
variants let mut variants = variants
.into_iter() .into_iter()
.filter_map(|variant| build_pat(ctx.db, module, variant)) .filter_map(|variant| build_pat(ctx.db, module, variant))
.filter(|variant_pat| is_variant_missing(&mut arms, variant_pat)) .filter(|variant_pat| is_variant_missing(&mut arms, variant_pat))
.map(|pat| make::match_arm(iter::once(pat), make::expr_empty_block())) .map(|pat| make::match_arm(iter::once(pat), make::expr_empty_block()))
.collect() .collect::<Vec<_>>();
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) { } else if let Some(enum_defs) = resolve_tuple_of_enum_def(&ctx.sema, &expr) {
// Partial fill not currently supported for tuple of enums. // Partial fill not currently supported for tuple of enums.
if !arms.is_empty() { if !arms.is_empty() {
@ -167,9 +174,13 @@ fn build_pat(db: &RootDatabase, module: hir::Module, var: hir::EnumVariant) -> O
#[cfg(test)] #[cfg(test)]
mod tests { 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 super::fill_match_arms;
use test_utils::covers;
#[test] #[test]
fn all_match_arms_provided() { fn all_match_arms_provided() {
@ -736,4 +747,29 @@ fn foo(a: A) {
"#, "#,
); );
} }
#[test]
fn option_order() {
covers!(option_order);
let before = r#"
fn foo(opt: Option<i32>) {
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<i32>) {
match <|>opt {
Some(_) => {}
None => {}
}
}
"#,
);
}
} }

View File

@ -1,6 +1,7 @@
//! See test_utils/src/marks.rs //! See test_utils/src/marks.rs
test_utils::marks![ test_utils::marks![
option_order
introduce_var_in_comment_is_not_applicable introduce_var_in_comment_is_not_applicable
test_introduce_var_expr_stmt test_introduce_var_expr_stmt
test_introduce_var_last_expr test_introduce_var_last_expr

View File

@ -3,7 +3,7 @@
use std::{iter, ops}; 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_ide_db::RootDatabase;
use ra_syntax::{ use ra_syntax::{
ast::{self, make, NameOwner}, ast::{self, make, NameOwner},
@ -206,7 +206,13 @@ pub trait From<T> {
} }
} }
pub mod prelude { pub use crate::convert::From } pub mod option {
pub enum Option<T> { None, Some(T)}
}
pub mod prelude {
pub use crate::{convert::From, option::Option::{self, *}};
}
#[prelude_import] #[prelude_import]
pub use prelude::*; pub use prelude::*;
"#; "#;
@ -215,7 +221,25 @@ pub(crate) fn core_convert_From(&self) -> Option<Trait> {
self.find_trait("core:convert:From") self.find_trait("core:convert:From")
} }
pub(crate) fn core_option_Option(&self) -> Option<Enum> {
self.find_enum("core:option:Option")
}
fn find_trait(&self, path: &str) -> Option<Trait> { fn find_trait(&self, path: &str) -> Option<Trait> {
match self.find_def(path)? {
hir::ScopeDef::ModuleDef(hir::ModuleDef::Trait(it)) => Some(it),
_ => None,
}
}
fn find_enum(&self, path: &str) -> Option<Enum> {
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<ScopeDef> {
let db = self.0.db; let db = self.0.db;
let mut path = path.split(':'); let mut path = path.split(':');
let trait_ = path.next_back()?; let trait_ = path.next_back()?;
@ -240,9 +264,6 @@ fn find_trait(&self, path: &str) -> Option<Trait> {
} }
let def = let def =
module.scope(db, None).into_iter().find(|(name, _def)| &name.to_string() == trait_)?.1; module.scope(db, None).into_iter().find(|(name, _def)| &name.to_string() == trait_)?.1;
match def { Some(def)
hir::ScopeDef::ModuleDef(hir::ModuleDef::Trait(it)) => Some(it),
_ => None,
}
} }
} }