diff options
author | Florian Diebold <[email protected]> | 2020-01-10 20:42:04 +0000 |
---|---|---|
committer | Florian Diebold <[email protected]> | 2020-01-12 10:34:52 +0000 |
commit | 2c11a9b42deca002bcd4a669dcbb3ab972b939d8 (patch) | |
tree | b4221236837f69190f133291979e0121a69563c9 | |
parent | 86d2af9f7b3f6af2ea9e4eca2584aa501b60aa14 (diff) |
Qualify paths in 'fill match arms' assist
-rw-r--r-- | crates/ra_assists/src/assists/fill_match_arms.rs | 67 | ||||
-rw-r--r-- | crates/ra_assists/src/ast_transform.rs | 2 | ||||
-rw-r--r-- | crates/ra_syntax/src/ast/make.rs | 5 |
3 files changed, 55 insertions, 19 deletions
diff --git a/crates/ra_assists/src/assists/fill_match_arms.rs b/crates/ra_assists/src/assists/fill_match_arms.rs index b75bd44eb..99d80998c 100644 --- a/crates/ra_assists/src/assists/fill_match_arms.rs +++ b/crates/ra_assists/src/assists/fill_match_arms.rs | |||
@@ -46,19 +46,24 @@ pub(crate) fn fill_match_arms(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist | |||
46 | }; | 46 | }; |
47 | 47 | ||
48 | let expr = match_expr.expr()?; | 48 | let expr = match_expr.expr()?; |
49 | let enum_def = { | 49 | let (enum_def, module) = { |
50 | let analyzer = ctx.source_analyzer(expr.syntax(), None); | 50 | let analyzer = ctx.source_analyzer(expr.syntax(), None); |
51 | resolve_enum_def(ctx.db, &analyzer, &expr)? | 51 | (resolve_enum_def(ctx.db, &analyzer, &expr)?, analyzer.module()?) |
52 | }; | 52 | }; |
53 | let variant_list = enum_def.variant_list()?; | 53 | let variants = enum_def.variants(ctx.db); |
54 | if variants.is_empty() { | ||
55 | return None; | ||
56 | } | ||
57 | |||
58 | let db = ctx.db; | ||
54 | 59 | ||
55 | ctx.add_assist(AssistId("fill_match_arms"), "fill match arms", |edit| { | 60 | ctx.add_assist(AssistId("fill_match_arms"), "fill match arms", |edit| { |
56 | let indent_level = IndentLevel::from_node(match_arm_list.syntax()); | 61 | let indent_level = IndentLevel::from_node(match_arm_list.syntax()); |
57 | 62 | ||
58 | let new_arm_list = { | 63 | let new_arm_list = { |
59 | let variants = variant_list.variants(); | ||
60 | let arms = variants | 64 | let arms = variants |
61 | .filter_map(build_pat) | 65 | .into_iter() |
66 | .filter_map(|variant| build_pat(db, module, variant)) | ||
62 | .map(|pat| make::match_arm(iter::once(pat), make::expr_unit())); | 67 | .map(|pat| make::match_arm(iter::once(pat), make::expr_unit())); |
63 | indent_level.increase_indent(make::match_arm_list(arms)) | 68 | indent_level.increase_indent(make::match_arm_list(arms)) |
64 | }; | 69 | }; |
@@ -80,23 +85,25 @@ fn resolve_enum_def( | |||
80 | db: &impl HirDatabase, | 85 | db: &impl HirDatabase, |
81 | analyzer: &hir::SourceAnalyzer, | 86 | analyzer: &hir::SourceAnalyzer, |
82 | expr: &ast::Expr, | 87 | expr: &ast::Expr, |
83 | ) -> Option<ast::EnumDef> { | 88 | ) -> Option<hir::Enum> { |
84 | let expr_ty = analyzer.type_of(db, &expr)?; | 89 | let expr_ty = analyzer.type_of(db, &expr)?; |
85 | 90 | ||
86 | let res = expr_ty.autoderef(db).find_map(|ty| match ty.as_adt() { | 91 | let result = expr_ty.autoderef(db).find_map(|ty| match ty.as_adt() { |
87 | Some(Adt::Enum(e)) => Some(e.source(db).value), | 92 | Some(Adt::Enum(e)) => Some(e), |
88 | _ => None, | 93 | _ => None, |
89 | }); | 94 | }); |
90 | res | 95 | result |
91 | } | 96 | } |
92 | 97 | ||
93 | fn build_pat(var: ast::EnumVariant) -> Option<ast::Pat> { | 98 | fn build_pat( |
94 | let path = make::path_qualified( | 99 | db: &impl HirDatabase, |
95 | make::path_from_name_ref(make::name_ref(&var.parent_enum().name()?.syntax().to_string())), | 100 | module: hir::Module, |
96 | make::name_ref(&var.name()?.syntax().to_string()), | 101 | var: hir::EnumVariant, |
97 | ); | 102 | ) -> Option<ast::Pat> { |
103 | let path = crate::ast_transform::path_to_ast(module.find_use_path(db, var.into())?); | ||
98 | 104 | ||
99 | let pat: ast::Pat = match var.kind() { | 105 | // FIXME: use HIR for this; it doesn't currently expose struct vs. tuple vs. unit variants though |
106 | let pat: ast::Pat = match var.source(db).value.kind() { | ||
100 | ast::StructKind::Tuple(field_list) => { | 107 | ast::StructKind::Tuple(field_list) => { |
101 | let pats = | 108 | let pats = |
102 | iter::repeat(make::placeholder_pat().into()).take(field_list.fields().count()); | 109 | iter::repeat(make::placeholder_pat().into()).take(field_list.fields().count()); |
@@ -106,7 +113,7 @@ fn build_pat(var: ast::EnumVariant) -> Option<ast::Pat> { | |||
106 | let pats = field_list.fields().map(|f| make::bind_pat(f.name().unwrap()).into()); | 113 | let pats = field_list.fields().map(|f| make::bind_pat(f.name().unwrap()).into()); |
107 | make::record_pat(path, pats).into() | 114 | make::record_pat(path, pats).into() |
108 | } | 115 | } |
109 | ast::StructKind::Unit => make::path_pat(path).into(), | 116 | ast::StructKind::Unit => make::path_pat(path), |
110 | }; | 117 | }; |
111 | 118 | ||
112 | Some(pat) | 119 | Some(pat) |
@@ -252,4 +259,32 @@ mod tests { | |||
252 | "#, | 259 | "#, |
253 | ); | 260 | ); |
254 | } | 261 | } |
262 | |||
263 | #[test] | ||
264 | fn fill_match_arms_qualifies_path() { | ||
265 | check_assist( | ||
266 | fill_match_arms, | ||
267 | r#" | ||
268 | mod foo { pub enum E { X, Y } } | ||
269 | use foo::E::X; | ||
270 | |||
271 | fn main() { | ||
272 | match X { | ||
273 | <|> | ||
274 | } | ||
275 | } | ||
276 | "#, | ||
277 | r#" | ||
278 | mod foo { pub enum E { X, Y } } | ||
279 | use foo::E::X; | ||
280 | |||
281 | fn main() { | ||
282 | match <|>X { | ||
283 | X => (), | ||
284 | foo::E::Y => (), | ||
285 | } | ||
286 | } | ||
287 | "#, | ||
288 | ); | ||
289 | } | ||
255 | } | 290 | } |
diff --git a/crates/ra_assists/src/ast_transform.rs b/crates/ra_assists/src/ast_transform.rs index cbddc50ac..eac2903d1 100644 --- a/crates/ra_assists/src/ast_transform.rs +++ b/crates/ra_assists/src/ast_transform.rs | |||
@@ -173,7 +173,7 @@ impl<'a, DB: HirDatabase> AstTransform<'a> for QualifyPaths<'a, DB> { | |||
173 | } | 173 | } |
174 | } | 174 | } |
175 | 175 | ||
176 | fn path_to_ast(path: hir::ModPath) -> ast::Path { | 176 | pub(crate) fn path_to_ast(path: hir::ModPath) -> ast::Path { |
177 | let parse = ast::SourceFile::parse(&path.to_string()); | 177 | let parse = ast::SourceFile::parse(&path.to_string()); |
178 | parse.tree().syntax().descendants().find_map(ast::Path::cast).unwrap() | 178 | parse.tree().syntax().descendants().find_map(ast::Path::cast).unwrap() |
179 | } | 179 | } |
diff --git a/crates/ra_syntax/src/ast/make.rs b/crates/ra_syntax/src/ast/make.rs index 9781b748f..eef45090d 100644 --- a/crates/ra_syntax/src/ast/make.rs +++ b/crates/ra_syntax/src/ast/make.rs | |||
@@ -117,10 +117,11 @@ pub fn record_pat(path: ast::Path, pats: impl IntoIterator<Item = ast::Pat>) -> | |||
117 | } | 117 | } |
118 | } | 118 | } |
119 | 119 | ||
120 | pub fn path_pat(path: ast::Path) -> ast::PathPat { | 120 | /// Returns a `BindPat` if the path has just one segment, a `PathPat` otherwise. |
121 | pub fn path_pat(path: ast::Path) -> ast::Pat { | ||
121 | let path_str = path.syntax().text().to_string(); | 122 | let path_str = path.syntax().text().to_string(); |
122 | return from_text(path_str.as_str()); | 123 | return from_text(path_str.as_str()); |
123 | fn from_text(text: &str) -> ast::PathPat { | 124 | fn from_text(text: &str) -> ast::Pat { |
124 | ast_from_text(&format!("fn f({}: ())", text)) | 125 | ast_from_text(&format!("fn f({}: ())", text)) |
125 | } | 126 | } |
126 | } | 127 | } |