diff options
| author | Hayashi Mikihiro <34ttrweoewiwe28@gmail.com> | 2025-04-14 20:29:42 +0900 |
|---|---|---|
| committer | Hayashi Mikihiro <34ttrweoewiwe28@gmail.com> | 2025-04-15 11:19:50 +0900 |
| commit | db2de2ab3f9764917c25ebb796850b47bc2cb28b (patch) | |
| tree | 4b58abbec9d4cba46af68f47cf815487966596e1 /src/tools/rust-analyzer | |
| parent | d9b61b3382e83c8e3aaab0239da74e0526aed283 (diff) | |
| download | rust-db2de2ab3f9764917c25ebb796850b47bc2cb28b.tar.gz rust-db2de2ab3f9764917c25ebb796850b47bc2cb28b.zip | |
fix: `Extract into function include inline variable in fmt macro
Signed-off-by: Hayashi Mikihiro <34ttrweoewiwe28@gmail.com>
Diffstat (limited to 'src/tools/rust-analyzer')
| -rw-r--r-- | src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs | 85 |
1 files changed, 71 insertions, 14 deletions
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs index 27c901c2f3a..046af71a9dc 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs @@ -797,15 +797,21 @@ impl FunctionBody { ) -> (FxIndexSet<Local>, Option<ast::SelfParam>) { let mut self_param = None; let mut res = FxIndexSet::default(); - 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( - NameRefClass::Definition(Definition::Local(local_ref), _) - | NameRefClass::FieldShorthand { local_ref, field_ref: _, adt_subst: _ }, - ) => local_ref, - _ => return, - }; + + fn local_from_name_ref( + sema: &Semantics<'_, RootDatabase>, + name_ref: ast::NameRef, + ) -> Option<hir::Local> { + match NameRefClass::classify(sema, &name_ref) { + Some( + NameRefClass::Definition(Definition::Local(local_ref), _) + | NameRefClass::FieldShorthand { local_ref, field_ref: _, adt_subst: _ }, + ) => Some(local_ref), + _ => None, + } + } + + let mut add_name_if_local = |local_ref: Local| { let InFile { file_id, value } = local_ref.primary_source(sema.db).source; // locals defined inside macros are not relevant to us if !file_id.is_macro() { @@ -821,13 +827,20 @@ impl FunctionBody { }; self.walk_expr(&mut |expr| match expr { ast::Expr::PathExpr(path_expr) => { - add_name_if_local(path_expr.path().and_then(|it| it.as_single_name_ref())) + if let Some(local) = path_expr + .path() + .and_then(|it| it.as_single_name_ref()) + .and_then(|name_ref| local_from_name_ref(sema, name_ref)) + { + add_name_if_local(local); + } } ast::Expr::ClosureExpr(closure_expr) => { if let Some(body) = closure_expr.body() { body.syntax() .descendants() - .map(ast::NameRef::cast) + .filter_map(ast::NameRef::cast) + .filter_map(|name_ref| local_from_name_ref(sema, name_ref)) .for_each(&mut add_name_if_local); } } @@ -836,9 +849,31 @@ impl FunctionBody { tt.syntax() .descendants_with_tokens() .filter_map(SyntaxElement::into_token) - .filter(|it| matches!(it.kind(), SyntaxKind::IDENT | T![self])) - .flat_map(|t| sema.descend_into_macros_exact(t)) - .for_each(|t| add_name_if_local(t.parent().and_then(ast::NameRef::cast))); + .filter(|it| { + matches!(it.kind(), SyntaxKind::STRING | SyntaxKind::IDENT | T![self]) + }) + .for_each(|t| { + if ast::String::can_cast(t.kind()) { + if let Some(parts) = + ast::String::cast(t).and_then(|s| sema.as_format_args_parts(&s)) + { + parts + .into_iter() + .filter_map(|(_, value)| value.and_then(|it| it.left())) + .filter_map(|path| match path { + PathResolution::Local(local) => Some(local), + _ => None, + }) + .for_each(&mut add_name_if_local); + } + } else { + sema.descend_into_macros_exact(t) + .into_iter() + .filter_map(|t| t.parent().and_then(ast::NameRef::cast)) + .filter_map(|name_ref| local_from_name_ref(sema, name_ref)) + .for_each(&mut add_name_if_local); + } + }); } } _ => (), @@ -6131,6 +6166,28 @@ fn $0fun_name(a: i32, b: i32, c: i32, x: i32) -> i32 { } #[test] + fn fmt_macro_argument() { + check_assist( + extract_function, + r#" +//- minicore: fmt +fn existing(a: i32, b: i32, c: i32) { + $0print!("{a}{}{}", b, "{c}");$0 +} +"#, + r#" +fn existing(a: i32, b: i32, c: i32) { + fun_name(a, b); +} + +fn $0fun_name(a: i32, b: i32) { + print!("{a}{}{}", b, "{c}"); +} +"#, + ); + } + + #[test] fn in_left_curly_is_not_applicable() { cov_mark::check!(extract_function_in_braces_is_not_applicable); check_assist_not_applicable(extract_function, r"fn foo() { $0}$0"); |
