Repository: rust-lang/rust-analyzer (rust)

Issue:
Function extraction doesn't pick up a fn parameter
<!--
Troubleshooting guide: https://rust-analyzer.github.io/manual.html#troubleshooting
Forum for questions: https://users.rust-lang.org/c/ide/14

Before submitting, please make sure that you're not running into one of these known issues:

 1. on-the-fly diagnostics are mostly unimplemented (`cargo check` diagnostics will be shown when saving a file): #3107

Otherwise please try to provide information which will help us to fix the issue faster. Minimal reproducible examples with few dependencies are especially lovely <3.
-->

**rust-analyzer version**: 0.3.1489-standalone (bc78ebd9d 2023-04-23)

**rustc version**: rustc 1.71.0-nightly (7f94b314c 2023-04-23)

**relevant settings**: None(?) Please advise. 

I have the following block of code: 

```rust
fn make_field_from_name(performance: &Path) -> Field {
    let field_name = format_ident!(
        "{}",
        get_leaf_name(performance).to_string().to_case(Case::Snake)
    );

    Field::parse_named
        .parse2(quote! {#field_name : <<Self as #performance>::Info as troupe::RoleInfo>::Sender})
        .unwrap_or_else(|_| {
            panic!(
                "Parse failure trying to create actor field - this is a bug, please file an issue"
            )
        })
}
```

I then [select the first let statement](https://imgur.com/a/3C36Vdn), and try to refactor it into a new function: 


I **expect**: the new function to take a parameter of `performance: &Path` or similar.
What actually happens: the new function takes no parameters and then fails to compile because `performance` is undefined.




Pull request description:
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.

Patch:
diff --git a/crates/hir-expand/src/proc_macro.rs b/crates/hir-expand/src/proc_macro.rs
index c9539210ab..dc04a41155 100644
--- a/crates/hir-expand/src/proc_macro.rs
+++ b/crates/hir-expand/src/proc_macro.rs
@@ -7,23 +7,20 @@ use crate::{db::ExpandDatabase, tt, ExpandError, ExpandResult};
 
 #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
 pub struct ProcMacroExpander {
-    proc_macro_id: ProcMacroId,
+    proc_macro_id: Option<ProcMacroId>,
 }
 
-const DUMMY_ID: u32 = !0;
-
 impl ProcMacroExpander {
     pub fn new(proc_macro_id: ProcMacroId) -> Self {
-        assert_ne!(proc_macro_id.0, DUMMY_ID);
-        Self { proc_macro_id }
+        Self { proc_macro_id: Some(proc_macro_id) }
     }
 
     pub fn dummy() -> Self {
-        Self { proc_macro_id: ProcMacroId(DUMMY_ID) }
+        Self { proc_macro_id: None }
     }
 
     pub fn is_dummy(&self) -> bool {
-        self.proc_macro_id.0 == DUMMY_ID
+        self.proc_macro_id.is_none()
     }
 
     pub fn expand(
@@ -35,10 +32,7 @@ impl ProcMacroExpander {
         attr_arg: Option<&tt::Subtree>,
     ) -> ExpandResult<tt::Subtree> {
         match self.proc_macro_id {
-            ProcMacroId(DUMMY_ID) => {
-                ExpandResult::new(tt::Subtree::empty(), ExpandError::UnresolvedProcMacro(def_crate))
-            }
-            ProcMacroId(id) => {
+            Some(id) => {
                 let proc_macros = db.proc_macros();
                 let proc_macros = match proc_macros.get(&def_crate) {
                     Some(Ok(proc_macros)) => proc_macros,
@@ -50,13 +44,13 @@ impl ProcMacroExpander {
                         );
                     }
                 };
-                let proc_macro = match proc_macros.get(id as usize) {
+                let proc_macro = match proc_macros.get(id.0 as usize) {
                     Some(proc_macro) => proc_macro,
                     None => {
                         never!(
                             "Proc macro index out of bounds: the length is {} but the index is {}",
                             proc_macros.len(),
-                            id
+                            id.0
                         );
                         return ExpandResult::new(
                             tt::Subtree::empty(),
@@ -87,6 +81,9 @@ impl ProcMacroExpander {
                     },
                 }
             }
+            None => {
+                ExpandResult::new(tt::Subtree::empty(), ExpandError::UnresolvedProcMacro(def_crate))
+            }
         }
     }
 }
diff --git a/crates/hir-ty/src/method_resolution.rs b/crates/hir-ty/src/method_resolution.rs
index 7208bebb3b..bf1e875858 100644
--- a/crates/hir-ty/src/method_resolution.rs
+++ b/crates/hir-ty/src/method_resolution.rs
@@ -729,16 +729,8 @@ fn lookup_impl_assoc_item_for_trait_ref(
     let self_ty = trait_ref.self_type_parameter(Interner);
     let self_ty_fp = TyFingerprint::for_trait_impl(&self_ty)?;
     let impls = db.trait_impls_in_deps(env.krate);
-    let self_impls = match self_ty.kind(Interner) {
-        TyKind::Adt(id, _) => {
-            id.0.module(db.upcast()).containing_block().map(|x| db.trait_impls_in_block(x))
-        }
-        _ => None,
-    };
-    let impls = impls
-        .iter()
-        .chain(self_impls.as_ref())
-        .flat_map(|impls| impls.for_trait_and_self_ty(hir_trait_id, self_ty_fp));
+    let impls =
+        impls.iter().flat_map(|impls| impls.for_trait_and_self_ty(hir_trait_id, self_ty_fp));
 
     let table = InferenceTable::new(db, env);
 
diff --git a/crates/hir/src/symbols.rs b/crates/hir/src/symbols.rs
index af37206ead..4eaf99e3e7 100644
--- a/crates/hir/src/symbols.rs
+++ b/crates/hir/src/symbols.rs
@@ -50,7 +50,7 @@ impl DeclarationLocation {
     pub fn original_name_range(&self, db: &dyn HirDatabase) -> Option<FileRange> {
         if let Some(file_id) = self.hir_file_id.file_id() {
             // fast path to prevent parsing
-            return Some(FileRange { file_id, range: self.name_ptr.text_range() });
+            return Some(FileRange { file_id, range: self.ptr.text_range() });
         }
         let node = resolve_node(db, self.hir_file_id, &self.name_ptr);
         node.as_ref().original_file_range_opt(db.upcast())
diff --git a/crates/ide-assists/src/handlers/extract_function.rs b/crates/ide-assists/src/handlers/extract_function.rs
index 58605f7ed5..c29721b464 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)));
                 }
             }
             _ => (),
@@ -4344,6 +4347,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(
diff --git a/crates/ide/src/goto_definition.rs b/crates/ide/src/goto_definition.rs
index ef3f14d79d..1518b49515 100644
--- a/crates/ide/src/goto_definition.rs
+++ b/crates/ide/src/goto_definition.rs
@@ -1492,29 +1492,6 @@ impl Twait for Stwuct {
 fn f() {
     let s = Stwuct;
     s.a$0();
-}
-        "#,
-            );
-        }
-        #[test]
-        fn method_call_inside_block() {
-            check(
-                r#"
-trait Twait {
-    fn a(&self);
-}
-
-fn outer() {
-    struct Stwuct;
-
-    impl Twait for Stwuct {
-        fn a(&self){}
-         //^
-    }
-    fn f() {
-        let s = Stwuct;
-        s.a$0();
-    }
 }
         "#,
             );


Test patch:
diff --git a/crates/hir-ty/src/consteval/tests.rs b/crates/hir-ty/src/consteval/tests.rs
index b336fa5f0f..b4b5fdd891 100644
--- a/crates/hir-ty/src/consteval/tests.rs
+++ b/crates/hir-ty/src/consteval/tests.rs
@@ -503,35 +503,6 @@ fn trait_method() {
     );
 }
 
-#[test]
-fn trait_method_inside_block() {
-    check_number(
-        r#"
-trait Twait {
-    fn a(&self) -> i32;
-}
-
-fn outer() -> impl Twait {
-    struct Stwuct;
-
-    impl Twait for Stwuct {
-        fn a(&self) -> i32 {
-            5
-        }
-    }
-    fn f() -> impl Twait {
-        let s = Stwuct;
-        s
-    }
-    f()
-}
-
-const GOAL: i32 = outer().a();
-        "#,
-        5,
-    );
-}
-
 #[test]
 fn generic_fn() {
     check_number(