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
//
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() {
#[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() {
"#,
);
}
+
+ #[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 => {}
+ }
+}
+"#,
+ );
+ }
}
//! 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
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},
#[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::*;
"#;
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()?;
}
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)
}
}
// arguments for a runnable from the quick pick should be updated.
// see crates\rust-analyzer\src\main_loop\handlers.rs, handle_code_lens
- if (cargoArgs[0] === "run") {
- cargoArgs[0] = "build";
- } else if (cargoArgs.indexOf("--no-run") === -1) {
- cargoArgs.push("--no-run");
+ switch (cargoArgs[0]) {
+ case "run": cargoArgs[0] = "build"; break;
+ case "test": {
+ if (cargoArgs.indexOf("--no-run") === -1) {
+ cargoArgs.push("--no-run");
+ }
+ break;
+ }
}
let artifacts = await this.artifactsFromArgs(cargoArgs);