about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2022-07-26 16:14:51 +0000
committerbors <bors@rust-lang.org>2022-07-26 16:14:51 +0000
commitc2eebd7a50faa2578376a80ceba91bdc75d748e2 (patch)
treecf9ee9f5302ec3cbbd455143aafb0dda30d59a8b
parent7a30f62ecf5642174dbc52de122fc0b21e1c15e1 (diff)
parentadd33b65dda4b59b46b5192f3a88a83b771af844 (diff)
downloadrust-c2eebd7a50faa2578376a80ceba91bdc75d748e2.tar.gz
rust-c2eebd7a50faa2578376a80ceba91bdc75d748e2.zip
Auto merge of #12877 - zachs18:inline-def-in-macro, r=zachs18
fix: Insert spaces when inlining a function defined in a macro.

(partially) fixes #12860.

This PR (only) addresses the whitespace issue when inlining functions defined in macros.

Additionally, the indentation/spacing is not ideal, but works, e.g.
```rs
macro_rules! define_function {
    () => { fn test_function_macro() {
        if let Some(3) = 3i32.checked_add(0) {
            println!("3 + 0 == 3");
        }
    } };
}
define_function!();
fn main() {
    test_function_macro();
}
// previously became
// ...
fn main() {
    ifletSome(3)=3i32.checked_add(0){println!("3 + 0 == 3");};
}
// now becomes
// ...
fn main() {
    if let Some(3) = 3i32.checked_add(0){
        println!("3 + 0 == 3");

      };
}
```

The `self` -> `this` problem[^this] is (probably?) a separate problem that I am also looking into.

[^this]: As mentioned in [my comment on the above issue](https://github.com/rust-lang/rust-analyzer/issues/12860#issuecomment-1193231766), inlining a method defined in a macro does not properly replace `self` with the new local `this`.
-rw-r--r--crates/ide-assists/src/handlers/inline_call.rs48
1 files changed, 46 insertions, 2 deletions
diff --git a/crates/ide-assists/src/handlers/inline_call.rs b/crates/ide-assists/src/handlers/inline_call.rs
index 658a1aadf53..80d3b925593 100644
--- a/crates/ide-assists/src/handlers/inline_call.rs
+++ b/crates/ide-assists/src/handlers/inline_call.rs
@@ -7,7 +7,7 @@ use ide_db::{
     imports::insert_use::remove_path_if_in_use_stmt,
     path_transform::PathTransform,
     search::{FileReference, SearchScope},
-    syntax_helpers::node_ext::expr_as_name_ref,
+    syntax_helpers::{insert_whitespace_into_node::insert_ws_into, node_ext::expr_as_name_ref},
     RootDatabase,
 };
 use itertools::{izip, Itertools};
@@ -301,7 +301,16 @@ fn inline(
     params: &[(ast::Pat, Option<ast::Type>, hir::Param)],
     CallInfo { node, arguments, generic_arg_list }: &CallInfo,
 ) -> ast::Expr {
-    let body = fn_body.clone_for_update();
+    let body = if sema.hir_file_for(fn_body.syntax()).is_macro() {
+        cov_mark::hit!(inline_call_defined_in_macro);
+        if let Some(body) = ast::BlockExpr::cast(insert_ws_into(fn_body.syntax().clone())) {
+            body
+        } else {
+            fn_body.clone_for_update()
+        }
+    } else {
+        fn_body.clone_for_update()
+    };
     let usages_for_locals = |local| {
         Definition::Local(local)
             .usages(sema)
@@ -1147,4 +1156,39 @@ fn bar() -> u32 {
 "#,
         )
     }
+
+    #[test]
+    fn inline_call_defined_in_macro() {
+        cov_mark::check!(inline_call_defined_in_macro);
+        check_assist(
+            inline_call,
+            r#"
+macro_rules! define_foo {
+    () => { fn foo() -> u32 {
+        let x = 0;
+        x
+    } };
+}
+define_foo!();
+fn bar() -> u32 {
+    foo$0()
+}
+"#,
+            r#"
+macro_rules! define_foo {
+    () => { fn foo() -> u32 {
+        let x = 0;
+        x
+    } };
+}
+define_foo!();
+fn bar() -> u32 {
+    {
+      let x = 0;
+      x
+    }
+}
+"#,
+        )
+    }
 }