about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-05-21 12:40:29 +0000
committerbors <bors@rust-lang.org>2023-05-21 12:40:29 +0000
commit7ac161ce77dfa31dc39337c2543a1d777e70c16e (patch)
treeb25477f1987e18f486757c08eae51702ef35be33
parenta04d8456be1d289c814846178cc1ff63b4fc297b (diff)
parent7b70988d48373f6d43874346c1cbcd15712a88c7 (diff)
downloadrust-7ac161ce77dfa31dc39337c2543a1d777e70c16e.tar.gz
rust-7ac161ce77dfa31dc39337c2543a1d777e70c16e.zip
Auto merge of #14863 - lowr:fix/extract-fn-nested-tt, r=lnicola
fix: consider all tokens in macro expr when analyzing locals

Fixes #14687

2 fixes for `extract_function` assist (related closely enough that I squashed into one commit):

- Locals in macro expressions have been analyzed only when they are in the top-level token tree the macro call wraps. We should consider all descendant tokens.
- `self` in macro expressions haven't been analyzed.
-rw-r--r--crates/ide-assists/src/handlers/extract_function.rs93
1 files changed, 86 insertions, 7 deletions
diff --git a/crates/ide-assists/src/handlers/extract_function.rs b/crates/ide-assists/src/handlers/extract_function.rs
index 58605f7ed57..c29721b4648 100644
--- a/crates/ide-assists/src/handlers/extract_function.rs
+++ b/crates/ide-assists/src/handlers/extract_function.rs
@@ -707,7 +707,7 @@ impl FunctionBody {
     ) -> (FxIndexSet<Local>, Option<ast::SelfParam>) {
         let mut self_param = None;
         let mut res = FxIndexSet::default();
-        let mut cb = |name_ref: Option<_>| {
+        let mut add_name_if_local = |name_ref: Option<_>| {
             let local_ref =
                 match name_ref.and_then(|name_ref| NameRefClass::classify(sema, &name_ref)) {
                     Some(
@@ -731,21 +731,24 @@ impl FunctionBody {
         };
         self.walk_expr(&mut |expr| match expr {
             ast::Expr::PathExpr(path_expr) => {
-                cb(path_expr.path().and_then(|it| it.as_single_name_ref()))
+                add_name_if_local(path_expr.path().and_then(|it| it.as_single_name_ref()))
             }
             ast::Expr::ClosureExpr(closure_expr) => {
                 if let Some(body) = closure_expr.body() {
-                    body.syntax().descendants().map(ast::NameRef::cast).for_each(|it| cb(it));
+                    body.syntax()
+                        .descendants()
+                        .map(ast::NameRef::cast)
+                        .for_each(&mut add_name_if_local);
                 }
             }
             ast::Expr::MacroExpr(expr) => {
                 if let Some(tt) = expr.macro_call().and_then(|call| call.token_tree()) {
                     tt.syntax()
-                        .children_with_tokens()
-                        .flat_map(SyntaxElement::into_token)
-                        .filter(|it| it.kind() == SyntaxKind::IDENT)
+                        .descendants_with_tokens()
+                        .filter_map(SyntaxElement::into_token)
+                        .filter(|it| matches!(it.kind(), SyntaxKind::IDENT | T![self]))
                         .flat_map(|t| sema.descend_into_macros(t))
-                        .for_each(|t| cb(t.parent().and_then(ast::NameRef::cast)));
+                        .for_each(|t| add_name_if_local(t.parent().and_then(ast::NameRef::cast)));
                 }
             }
             _ => (),
@@ -4345,6 +4348,82 @@ fn $0fun_name(n: i32) -> i32 {
     }
 
     #[test]
+    fn param_usage_in_macro_with_nested_tt() {
+        check_assist(
+            extract_function,
+            r#"
+macro_rules! m {
+    ($val:expr) => { $val };
+}
+
+fn foo() {
+    let n = 1;
+    let t = 1;
+    $0let k = n * m!((n) + { t });$0
+    let m = k + 1;
+}
+"#,
+            r#"
+macro_rules! m {
+    ($val:expr) => { $val };
+}
+
+fn foo() {
+    let n = 1;
+    let t = 1;
+    let k = fun_name(n, t);
+    let m = k + 1;
+}
+
+fn $0fun_name(n: i32, t: i32) -> i32 {
+    let k = n * m!((n) + { t });
+    k
+}
+"#,
+        )
+    }
+
+    #[test]
+    fn param_usage_in_macro_with_nested_tt_2() {
+        check_assist(
+            extract_function,
+            r#"
+macro_rules! m {
+    ($val:expr) => { $val };
+}
+
+struct S(i32);
+impl S {
+    fn foo(&self) {
+        let n = 1;
+        $0let k = n * m!((n) + { self.0 });$0
+        let m = k + 1;
+    }
+}
+"#,
+            r#"
+macro_rules! m {
+    ($val:expr) => { $val };
+}
+
+struct S(i32);
+impl S {
+    fn foo(&self) {
+        let n = 1;
+        let k = self.fun_name(n);
+        let m = k + 1;
+    }
+
+    fn $0fun_name(&self, n: i32) -> i32 {
+        let k = n * m!((n) + { self.0 });
+        k
+    }
+}
+"#,
+        )
+    }
+
+    #[test]
     fn extract_with_await() {
         check_assist(
             extract_function,