Fix Some|None order in fill_match_arms

This commit is contained in:
Aleksey Kladov 2020-05-20 10:51:48 +02:00
parent c0bcaea466
commit d8881d98d3
3 changed files with 69 additions and 11 deletions

View File

@ -4,8 +4,9 @@
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<MatchArm> = 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::<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) {
// 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 @@ 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
test_utils::marks![
option_order
introduce_var_in_comment_is_not_applicable
test_introduce_var_expr_stmt
test_introduce_var_last_expr

View File

@ -3,7 +3,7 @@
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<T> {
fn from(T) -> Self;
}
}
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]
pub use prelude::*;
"#;
@ -215,7 +221,25 @@ pub(crate) fn core_convert_From(&self) -> Option<Trait> {
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> {
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 mut path = path.split(':');
let trait_ = path.next_back()?;
@ -240,9 +264,6 @@ fn find_trait(&self, path: &str) -> Option<Trait> {
}
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)
}
}