Skip to content

Commit 7ac161c

Browse files
committed
Auto merge of rust-lang#14863 - lowr:fix/extract-fn-nested-tt, r=lnicola
fix: consider all tokens in macro expr when analyzing locals Fixes rust-lang#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.
2 parents a04d845 + 7b70988 commit 7ac161c

File tree

1 file changed

+86
-7
lines changed

1 file changed

+86
-7
lines changed

crates/ide-assists/src/handlers/extract_function.rs

+86-7
Original file line numberDiff line numberDiff line change
@@ -707,7 +707,7 @@ impl FunctionBody {
707707
) -> (FxIndexSet<Local>, Option<ast::SelfParam>) {
708708
let mut self_param = None;
709709
let mut res = FxIndexSet::default();
710-
let mut cb = |name_ref: Option<_>| {
710+
let mut add_name_if_local = |name_ref: Option<_>| {
711711
let local_ref =
712712
match name_ref.and_then(|name_ref| NameRefClass::classify(sema, &name_ref)) {
713713
Some(
@@ -731,21 +731,24 @@ impl FunctionBody {
731731
};
732732
self.walk_expr(&mut |expr| match expr {
733733
ast::Expr::PathExpr(path_expr) => {
734-
cb(path_expr.path().and_then(|it| it.as_single_name_ref()))
734+
add_name_if_local(path_expr.path().and_then(|it| it.as_single_name_ref()))
735735
}
736736
ast::Expr::ClosureExpr(closure_expr) => {
737737
if let Some(body) = closure_expr.body() {
738-
body.syntax().descendants().map(ast::NameRef::cast).for_each(|it| cb(it));
738+
body.syntax()
739+
.descendants()
740+
.map(ast::NameRef::cast)
741+
.for_each(&mut add_name_if_local);
739742
}
740743
}
741744
ast::Expr::MacroExpr(expr) => {
742745
if let Some(tt) = expr.macro_call().and_then(|call| call.token_tree()) {
743746
tt.syntax()
744-
.children_with_tokens()
745-
.flat_map(SyntaxElement::into_token)
746-
.filter(|it| it.kind() == SyntaxKind::IDENT)
747+
.descendants_with_tokens()
748+
.filter_map(SyntaxElement::into_token)
749+
.filter(|it| matches!(it.kind(), SyntaxKind::IDENT | T![self]))
747750
.flat_map(|t| sema.descend_into_macros(t))
748-
.for_each(|t| cb(t.parent().and_then(ast::NameRef::cast)));
751+
.for_each(|t| add_name_if_local(t.parent().and_then(ast::NameRef::cast)));
749752
}
750753
}
751754
_ => (),
@@ -4344,6 +4347,82 @@ fn $0fun_name(n: i32) -> i32 {
43444347
);
43454348
}
43464349

4350+
#[test]
4351+
fn param_usage_in_macro_with_nested_tt() {
4352+
check_assist(
4353+
extract_function,
4354+
r#"
4355+
macro_rules! m {
4356+
($val:expr) => { $val };
4357+
}
4358+
4359+
fn foo() {
4360+
let n = 1;
4361+
let t = 1;
4362+
$0let k = n * m!((n) + { t });$0
4363+
let m = k + 1;
4364+
}
4365+
"#,
4366+
r#"
4367+
macro_rules! m {
4368+
($val:expr) => { $val };
4369+
}
4370+
4371+
fn foo() {
4372+
let n = 1;
4373+
let t = 1;
4374+
let k = fun_name(n, t);
4375+
let m = k + 1;
4376+
}
4377+
4378+
fn $0fun_name(n: i32, t: i32) -> i32 {
4379+
let k = n * m!((n) + { t });
4380+
k
4381+
}
4382+
"#,
4383+
)
4384+
}
4385+
4386+
#[test]
4387+
fn param_usage_in_macro_with_nested_tt_2() {
4388+
check_assist(
4389+
extract_function,
4390+
r#"
4391+
macro_rules! m {
4392+
($val:expr) => { $val };
4393+
}
4394+
4395+
struct S(i32);
4396+
impl S {
4397+
fn foo(&self) {
4398+
let n = 1;
4399+
$0let k = n * m!((n) + { self.0 });$0
4400+
let m = k + 1;
4401+
}
4402+
}
4403+
"#,
4404+
r#"
4405+
macro_rules! m {
4406+
($val:expr) => { $val };
4407+
}
4408+
4409+
struct S(i32);
4410+
impl S {
4411+
fn foo(&self) {
4412+
let n = 1;
4413+
let k = self.fun_name(n);
4414+
let m = k + 1;
4415+
}
4416+
4417+
fn $0fun_name(&self, n: i32) -> i32 {
4418+
let k = n * m!((n) + { self.0 });
4419+
k
4420+
}
4421+
}
4422+
"#,
4423+
)
4424+
}
4425+
43474426
#[test]
43484427
fn extract_with_await() {
43494428
check_assist(

0 commit comments

Comments
 (0)