aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2020-01-12 11:23:11 +0000
committerGitHub <[email protected]>2020-01-12 11:23:11 +0000
commit21be386db8e8019d25c2529313d0371f91a15cb3 (patch)
treeb4221236837f69190f133291979e0121a69563c9
parent86d2af9f7b3f6af2ea9e4eca2584aa501b60aa14 (diff)
parent2c11a9b42deca002bcd4a669dcbb3ab972b939d8 (diff)
Merge #2809
2809: Qualify paths in 'fill match arms' assist r=matklad a=flodiebold Co-authored-by: Florian Diebold <[email protected]>
-rw-r--r--crates/ra_assists/src/assists/fill_match_arms.rs67
-rw-r--r--crates/ra_assists/src/ast_transform.rs2
-rw-r--r--crates/ra_syntax/src/ast/make.rs5
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
93fn build_pat(var: ast::EnumVariant) -> Option<ast::Pat> { 98fn 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
176fn path_to_ast(path: hir::ModPath) -> ast::Path { 176pub(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
120pub fn path_pat(path: ast::Path) -> ast::PathPat { 120/// Returns a `BindPat` if the path has just one segment, a `PathPat` otherwise.
121pub 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}