diff options
-rw-r--r-- | crates/ra_assists/src/handlers/fill_match_arms.rs | 44 | ||||
-rw-r--r-- | crates/ra_assists/src/marks.rs | 1 | ||||
-rw-r--r-- | 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 13c1e7e80..b57ff75ae 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}; | |||
4 | use itertools::Itertools; | 4 | use itertools::Itertools; |
5 | use ra_ide_db::RootDatabase; | 5 | use ra_ide_db::RootDatabase; |
6 | use ra_syntax::ast::{self, make, AstNode, MatchArm, NameOwner, Pat}; | 6 | use ra_syntax::ast::{self, make, AstNode, MatchArm, NameOwner, Pat}; |
7 | use test_utils::tested_by; | ||
7 | 8 | ||
8 | use crate::{AssistContext, AssistId, Assists}; | 9 | use crate::{utils::FamousDefs, AssistContext, AssistId, Assists}; |
9 | 10 | ||
10 | // Assist: fill_match_arms | 11 | // Assist: fill_match_arms |
11 | // | 12 | // |
@@ -49,12 +50,18 @@ pub(crate) fn fill_match_arms(acc: &mut Assists, ctx: &AssistContext) -> Option< | |||
49 | let missing_arms: Vec<MatchArm> = if let Some(enum_def) = resolve_enum_def(&ctx.sema, &expr) { | 50 | let missing_arms: Vec<MatchArm> = if let Some(enum_def) = resolve_enum_def(&ctx.sema, &expr) { |
50 | let variants = enum_def.variants(ctx.db); | 51 | let variants = enum_def.variants(ctx.db); |
51 | 52 | ||
52 | variants | 53 | let mut variants = variants |
53 | .into_iter() | 54 | .into_iter() |
54 | .filter_map(|variant| build_pat(ctx.db, module, variant)) | 55 | .filter_map(|variant| build_pat(ctx.db, module, variant)) |
55 | .filter(|variant_pat| is_variant_missing(&mut arms, variant_pat)) | 56 | .filter(|variant_pat| is_variant_missing(&mut arms, variant_pat)) |
56 | .map(|pat| make::match_arm(iter::once(pat), make::expr_empty_block())) | 57 | .map(|pat| make::match_arm(iter::once(pat), make::expr_empty_block())) |
57 | .collect() | 58 | .collect::<Vec<_>>(); |
59 | if Some(enum_def) == FamousDefs(&ctx.sema, module.krate()).core_option_Option() { | ||
60 | // Match `Some` variant first. | ||
61 | tested_by!(option_order); | ||
62 | variants.reverse() | ||
63 | } | ||
64 | variants | ||
58 | } else if let Some(enum_defs) = resolve_tuple_of_enum_def(&ctx.sema, &expr) { | 65 | } else if let Some(enum_defs) = resolve_tuple_of_enum_def(&ctx.sema, &expr) { |
59 | // Partial fill not currently supported for tuple of enums. | 66 | // Partial fill not currently supported for tuple of enums. |
60 | if !arms.is_empty() { | 67 | if !arms.is_empty() { |
@@ -167,9 +174,13 @@ fn build_pat(db: &RootDatabase, module: hir::Module, var: hir::EnumVariant) -> O | |||
167 | 174 | ||
168 | #[cfg(test)] | 175 | #[cfg(test)] |
169 | mod tests { | 176 | mod tests { |
170 | use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target}; | 177 | use crate::{ |
178 | tests::{check_assist, check_assist_not_applicable, check_assist_target}, | ||
179 | utils::FamousDefs, | ||
180 | }; | ||
171 | 181 | ||
172 | use super::fill_match_arms; | 182 | use super::fill_match_arms; |
183 | use test_utils::covers; | ||
173 | 184 | ||
174 | #[test] | 185 | #[test] |
175 | fn all_match_arms_provided() { | 186 | fn all_match_arms_provided() { |
@@ -736,4 +747,29 @@ mod tests { | |||
736 | "#, | 747 | "#, |
737 | ); | 748 | ); |
738 | } | 749 | } |
750 | |||
751 | #[test] | ||
752 | fn option_order() { | ||
753 | covers!(option_order); | ||
754 | let before = r#" | ||
755 | fn foo(opt: Option<i32>) { | ||
756 | match opt<|> { | ||
757 | } | ||
758 | }"#; | ||
759 | let before = | ||
760 | &format!("//- main.rs crate:main deps:core\n{}{}", before, FamousDefs::FIXTURE); | ||
761 | |||
762 | check_assist( | ||
763 | fill_match_arms, | ||
764 | before, | ||
765 | r#" | ||
766 | fn foo(opt: Option<i32>) { | ||
767 | match <|>opt { | ||
768 | Some(_) => {} | ||
769 | None => {} | ||
770 | } | ||
771 | } | ||
772 | "#, | ||
773 | ); | ||
774 | } | ||
739 | } | 775 | } |
diff --git a/crates/ra_assists/src/marks.rs b/crates/ra_assists/src/marks.rs index d579e627f..722f3c6a4 100644 --- a/crates/ra_assists/src/marks.rs +++ b/crates/ra_assists/src/marks.rs | |||
@@ -1,6 +1,7 @@ | |||
1 | //! See test_utils/src/marks.rs | 1 | //! See test_utils/src/marks.rs |
2 | 2 | ||
3 | test_utils::marks![ | 3 | test_utils::marks![ |
4 | option_order | ||
4 | introduce_var_in_comment_is_not_applicable | 5 | introduce_var_in_comment_is_not_applicable |
5 | test_introduce_var_expr_stmt | 6 | test_introduce_var_expr_stmt |
6 | test_introduce_var_last_expr | 7 | test_introduce_var_last_expr |
diff --git a/crates/ra_assists/src/utils.rs b/crates/ra_assists/src/utils.rs index 9af27180b..0038a9764 100644 --- a/crates/ra_assists/src/utils.rs +++ b/crates/ra_assists/src/utils.rs | |||
@@ -3,7 +3,7 @@ pub(crate) mod insert_use; | |||
3 | 3 | ||
4 | use std::{iter, ops}; | 4 | use std::{iter, ops}; |
5 | 5 | ||
6 | use hir::{Adt, Crate, Semantics, Trait, Type}; | 6 | use hir::{Adt, Crate, Enum, ScopeDef, Semantics, Trait, Type}; |
7 | use ra_ide_db::RootDatabase; | 7 | use ra_ide_db::RootDatabase; |
8 | use ra_syntax::{ | 8 | use ra_syntax::{ |
9 | ast::{self, make, NameOwner}, | 9 | ast::{self, make, NameOwner}, |
@@ -200,13 +200,19 @@ impl FamousDefs<'_, '_> { | |||
200 | #[cfg(test)] | 200 | #[cfg(test)] |
201 | pub(crate) const FIXTURE: &'static str = r#" | 201 | pub(crate) const FIXTURE: &'static str = r#" |
202 | //- /libcore.rs crate:core | 202 | //- /libcore.rs crate:core |
203 | pub mod convert{ | 203 | pub mod convert { |
204 | pub trait From<T> { | 204 | pub trait From<T> { |
205 | fn from(T) -> Self; | 205 | fn from(T) -> Self; |
206 | } | 206 | } |
207 | } | 207 | } |
208 | 208 | ||
209 | pub mod prelude { pub use crate::convert::From } | 209 | pub mod option { |
210 | pub enum Option<T> { None, Some(T)} | ||
211 | } | ||
212 | |||
213 | pub mod prelude { | ||
214 | pub use crate::{convert::From, option::Option::{self, *}}; | ||
215 | } | ||
210 | #[prelude_import] | 216 | #[prelude_import] |
211 | pub use prelude::*; | 217 | pub use prelude::*; |
212 | "#; | 218 | "#; |
@@ -215,7 +221,25 @@ pub use prelude::*; | |||
215 | self.find_trait("core:convert:From") | 221 | self.find_trait("core:convert:From") |
216 | } | 222 | } |
217 | 223 | ||
224 | pub(crate) fn core_option_Option(&self) -> Option<Enum> { | ||
225 | self.find_enum("core:option:Option") | ||
226 | } | ||
227 | |||
218 | fn find_trait(&self, path: &str) -> Option<Trait> { | 228 | fn find_trait(&self, path: &str) -> Option<Trait> { |
229 | match self.find_def(path)? { | ||
230 | hir::ScopeDef::ModuleDef(hir::ModuleDef::Trait(it)) => Some(it), | ||
231 | _ => None, | ||
232 | } | ||
233 | } | ||
234 | |||
235 | fn find_enum(&self, path: &str) -> Option<Enum> { | ||
236 | match self.find_def(path)? { | ||
237 | hir::ScopeDef::ModuleDef(hir::ModuleDef::Adt(hir::Adt::Enum(it))) => Some(it), | ||
238 | _ => None, | ||
239 | } | ||
240 | } | ||
241 | |||
242 | fn find_def(&self, path: &str) -> Option<ScopeDef> { | ||
219 | let db = self.0.db; | 243 | let db = self.0.db; |
220 | let mut path = path.split(':'); | 244 | let mut path = path.split(':'); |
221 | let trait_ = path.next_back()?; | 245 | let trait_ = path.next_back()?; |
@@ -240,9 +264,6 @@ pub use prelude::*; | |||
240 | } | 264 | } |
241 | let def = | 265 | let def = |
242 | module.scope(db, None).into_iter().find(|(name, _def)| &name.to_string() == trait_)?.1; | 266 | module.scope(db, None).into_iter().find(|(name, _def)| &name.to_string() == trait_)?.1; |
243 | match def { | 267 | Some(def) |
244 | hir::ScopeDef::ModuleDef(hir::ModuleDef::Trait(it)) => Some(it), | ||
245 | _ => None, | ||
246 | } | ||
247 | } | 268 | } |
248 | } | 269 | } |