summaryrefslogtreecommitdiffstats
path: root/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_tuple.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_tuple.rs')
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_tuple.rs159
1 files changed, 159 insertions, 0 deletions
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_tuple.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_tuple.rs
new file mode 100644
index 000000000..25c58d086
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_tuple.rs
@@ -0,0 +1,159 @@
+use syntax::{
+ ast::{self, edit::AstNodeEdit},
+ AstNode, T,
+};
+
+use crate::{AssistContext, AssistId, AssistKind, Assists};
+
+// Assist: unwrap_tuple
+//
+// Unwrap the tuple to different variables.
+//
+// ```
+// # //- minicore: result
+// fn main() {
+// $0let (foo, bar) = ("Foo", "Bar");
+// }
+// ```
+// ->
+// ```
+// fn main() {
+// let foo = "Foo";
+// let bar = "Bar";
+// }
+// ```
+pub(crate) fn unwrap_tuple(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
+ let let_kw = ctx.find_token_syntax_at_offset(T![let])?;
+ let let_stmt = let_kw.parent().and_then(ast::LetStmt::cast)?;
+ let indent_level = let_stmt.indent_level().0 as usize;
+ let pat = let_stmt.pat()?;
+ let ty = let_stmt.ty();
+ let init = let_stmt.initializer()?;
+
+ // This only applies for tuple patterns, types, and initializers.
+ let tuple_pat = match pat {
+ ast::Pat::TuplePat(pat) => pat,
+ _ => return None,
+ };
+ let tuple_ty = ty.and_then(|it| match it {
+ ast::Type::TupleType(ty) => Some(ty),
+ _ => None,
+ });
+ let tuple_init = match init {
+ ast::Expr::TupleExpr(expr) => expr,
+ _ => return None,
+ };
+
+ if tuple_pat.fields().count() != tuple_init.fields().count() {
+ return None;
+ }
+ if let Some(tys) = &tuple_ty {
+ if tuple_pat.fields().count() != tys.fields().count() {
+ return None;
+ }
+ }
+
+ let parent = let_kw.parent()?;
+
+ acc.add(
+ AssistId("unwrap_tuple", AssistKind::RefactorRewrite),
+ "Unwrap tuple",
+ let_kw.text_range(),
+ |edit| {
+ let indents = " ".repeat(indent_level);
+
+ // If there is an ascribed type, insert that type for each declaration,
+ // otherwise, omit that type.
+ if let Some(tys) = tuple_ty {
+ let mut zipped_decls = String::new();
+ for (pat, ty, expr) in
+ itertools::izip!(tuple_pat.fields(), tys.fields(), tuple_init.fields())
+ {
+ zipped_decls.push_str(&format!("{}let {pat}: {ty} = {expr};\n", indents))
+ }
+ edit.replace(parent.text_range(), zipped_decls.trim());
+ } else {
+ let mut zipped_decls = String::new();
+ for (pat, expr) in itertools::izip!(tuple_pat.fields(), tuple_init.fields()) {
+ zipped_decls.push_str(&format!("{}let {pat} = {expr};\n", indents));
+ }
+ edit.replace(parent.text_range(), zipped_decls.trim());
+ }
+ },
+ )
+}
+
+#[cfg(test)]
+mod tests {
+ use crate::tests::check_assist;
+
+ use super::*;
+
+ #[test]
+ fn unwrap_tuples() {
+ check_assist(
+ unwrap_tuple,
+ r#"
+fn main() {
+ $0let (foo, bar) = ("Foo", "Bar");
+}
+"#,
+ r#"
+fn main() {
+ let foo = "Foo";
+ let bar = "Bar";
+}
+"#,
+ );
+
+ check_assist(
+ unwrap_tuple,
+ r#"
+fn main() {
+ $0let (foo, bar, baz) = ("Foo", "Bar", "Baz");
+}
+"#,
+ r#"
+fn main() {
+ let foo = "Foo";
+ let bar = "Bar";
+ let baz = "Baz";
+}
+"#,
+ );
+ }
+
+ #[test]
+ fn unwrap_tuple_with_types() {
+ check_assist(
+ unwrap_tuple,
+ r#"
+fn main() {
+ $0let (foo, bar): (u8, i32) = (5, 10);
+}
+"#,
+ r#"
+fn main() {
+ let foo: u8 = 5;
+ let bar: i32 = 10;
+}
+"#,
+ );
+
+ check_assist(
+ unwrap_tuple,
+ r#"
+fn main() {
+ $0let (foo, bar, baz): (u8, i32, f64) = (5, 10, 17.5);
+}
+"#,
+ r#"
+fn main() {
+ let foo: u8 = 5;
+ let bar: i32 = 10;
+ let baz: f64 = 17.5;
+}
+"#,
+ );
+ }
+}