From bfaefed3f61a29624ea3a0c94fcc498d34d0c31f Mon Sep 17 00:00:00 2001 From: gfreezy Date: Mon, 4 Feb 2019 00:27:36 +0800 Subject: fill match arm --- crates/ra_ide_api/src/assits/fill_match_arm.rs | 157 +++++++++++++++++++++ .../assits/snapshots/tests__fill_match_arm1.snap | 20 +++ .../assits/snapshots/tests__fill_match_arm2.snap | 20 +++ 3 files changed, 197 insertions(+) create mode 100644 crates/ra_ide_api/src/assits/fill_match_arm.rs create mode 100644 crates/ra_ide_api/src/assits/snapshots/tests__fill_match_arm1.snap create mode 100644 crates/ra_ide_api/src/assits/snapshots/tests__fill_match_arm2.snap (limited to 'crates/ra_ide_api/src/assits') diff --git a/crates/ra_ide_api/src/assits/fill_match_arm.rs b/crates/ra_ide_api/src/assits/fill_match_arm.rs new file mode 100644 index 000000000..d433861a0 --- /dev/null +++ b/crates/ra_ide_api/src/assits/fill_match_arm.rs @@ -0,0 +1,157 @@ +use std::fmt::Write; +use hir::{ + AdtDef, + source_binder, + Ty, + FieldSource, +}; +use ra_ide_api_light::{ + assists::{ + Assist, + AssistBuilder + } +}; +use ra_syntax::{ + ast::{ + self, + AstNode, + } +}; + +use crate::assits::AssistCtx; + +pub fn fill_match_arm(ctx: AssistCtx) -> Option { + let match_expr = ctx.node_at_offset::()?; + + // We already have some match arms, so we don't provide any assists. + match match_expr.match_arm_list() { + Some(arm_list) if arm_list.arms().count() > 0 => { + return None; + } + _ => {} + } + + let expr = match_expr.expr()?; + let function = source_binder::function_from_child_node(ctx.db, ctx.file_id, expr.syntax())?; + let infer_result = function.infer(ctx.db); + let syntax_mapping = function.body_syntax_mapping(ctx.db); + let node_expr = syntax_mapping.node_expr(expr)?; + let match_expr_ty = infer_result[node_expr].clone(); + match match_expr_ty { + Ty::Adt { def_id, .. } => match def_id { + AdtDef::Enum(e) => { + let mut buf = format!("match {} {{\n", expr.syntax().text().to_string()); + let variants = e.variants(ctx.db); + for variant in variants { + let name = variant.name(ctx.db)?; + write!( + &mut buf, + " {}::{}", + e.name(ctx.db)?.to_string(), + name.to_string() + ) + .expect("write fmt"); + + let pat = variant + .fields(ctx.db) + .into_iter() + .map(|field| { + let name = field.name(ctx.db).to_string(); + let (_, source) = field.source(ctx.db); + match source { + FieldSource::Named(_) => name, + FieldSource::Pos(_) => "_".to_string(), + } + }) + .collect::>(); + + match pat.first().map(|s| s.as_str()) { + Some("_") => write!(&mut buf, "({})", pat.join(", ")).expect("write fmt"), + Some(_) => write!(&mut buf, "{{{}}}", pat.join(", ")).expect("write fmt"), + None => (), + }; + + buf.push_str(" => (),\n"); + } + buf.push_str("}"); + ctx.build("fill match arms", |edit: &mut AssistBuilder| { + edit.replace_node_and_indent(match_expr.syntax(), buf); + }) + } + _ => None, + }, + _ => None, + } +} + +#[cfg(test)] +mod tests { + use insta::assert_debug_snapshot_matches; + + use ra_syntax::{TextRange, TextUnit}; + + use crate::{ + FileRange, + mock_analysis::{analysis_and_position, single_file_with_position} +}; + use ra_db::SourceDatabase; + + fn test_assit(name: &str, code: &str) { + let (analysis, position) = if code.contains("//-") { + analysis_and_position(code) + } else { + single_file_with_position(code) + }; + let frange = FileRange { + file_id: position.file_id, + range: TextRange::offset_len(position.offset, TextUnit::from(1)), + }; + let source_file = analysis + .with_db(|db| db.parse(frange.file_id)) + .expect("source file"); + let ret = analysis + .with_db(|db| crate::assits::assists(db, frange.file_id, &source_file, frange.range)) + .expect("assits"); + + assert_debug_snapshot_matches!(name, ret); + } + + #[test] + fn test_fill_match_arm() { + test_assit( + "fill_match_arm1", + r#" + enum A { + As, + Bs, + Cs(String), + Ds(String, String), + Es{x: usize, y: usize} + } + + fn main() { + let a = A::As; + match a<|> + } + "#, + ); + + test_assit( + "fill_match_arm2", + r#" + enum A { + As, + Bs, + Cs(String), + Ds(String, String), + Es{x: usize, y: usize} + } + + fn main() { + let a = A::As; + match a<|> {} + } + "#, + ); + } +} diff --git a/crates/ra_ide_api/src/assits/snapshots/tests__fill_match_arm1.snap b/crates/ra_ide_api/src/assits/snapshots/tests__fill_match_arm1.snap new file mode 100644 index 000000000..980726d92 --- /dev/null +++ b/crates/ra_ide_api/src/assits/snapshots/tests__fill_match_arm1.snap @@ -0,0 +1,20 @@ +--- +created: "2019-02-03T15:38:46.094184+00:00" +creator: insta@0.5.2 +expression: ret +source: crates/ra_ide_api/src/assits/fill_match_arm.rs +--- +[ + LocalEdit { + label: "fill match arms", + edit: TextEdit { + atoms: [ + AtomTextEdit { + delete: [211; 218), + insert: "match a {\n A::As => (),\n A::Bs => (),\n A::Cs(_) => (),\n A::Ds(_, _) => (),\n A::Es{x, y} => (),\n }" + } + ] + }, + cursor_position: None + } +] diff --git a/crates/ra_ide_api/src/assits/snapshots/tests__fill_match_arm2.snap b/crates/ra_ide_api/src/assits/snapshots/tests__fill_match_arm2.snap new file mode 100644 index 000000000..cee0efe74 --- /dev/null +++ b/crates/ra_ide_api/src/assits/snapshots/tests__fill_match_arm2.snap @@ -0,0 +1,20 @@ +--- +created: "2019-02-03T15:41:34.640074+00:00" +creator: insta@0.5.2 +expression: ret +source: crates/ra_ide_api/src/assits/fill_match_arm.rs +--- +[ + LocalEdit { + label: "fill match arms", + edit: TextEdit { + atoms: [ + AtomTextEdit { + delete: [211; 221), + insert: "match a {\n A::As => (),\n A::Bs => (),\n A::Cs(_) => (),\n A::Ds(_, _) => (),\n A::Es{x, y} => (),\n }" + } + ] + }, + cursor_position: None + } +] -- cgit v1.2.3