From c8cfd96365b4444b8c95fc8f79adb11936827b69 Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Sun, 29 Mar 2026 07:05:59 +0800 Subject: [PATCH] fix: complete envs in nested `env!()` Example --- ```rust fn main() { println!("{}", env!("CA$0")); } ``` **Before this PR** Cannot complete any env **After this PR** ```rust fn main() { println!("{}", env!("CARGO_BIN_NAME")); } ``` --- .../src/completions/env_vars.rs | 50 +++++++++++++++++-- 1 file changed, 45 insertions(+), 5 deletions(-) diff --git a/crates/ide-completion/src/completions/env_vars.rs b/crates/ide-completion/src/completions/env_vars.rs index 92cbf411c1e3..885d1a30750f 100644 --- a/crates/ide-completion/src/completions/env_vars.rs +++ b/crates/ide-completion/src/completions/env_vars.rs @@ -51,11 +51,10 @@ pub(crate) fn complete_cargo_env_vars( original: &ast::String, expanded: &ast::String, ) -> Option<()> { - let is_in_env_expansion = ctx - .sema - .hir_file_for(&expanded.syntax().parent()?) - .macro_file() - .is_some_and(|it| it.is_env_or_option_env(ctx.sema.db)); + let descends = ctx.sema.descend_into_macros_exact_with_file(original.syntax().clone()); + let macro_file = descends.first()?.file_id.macro_file(); + + let is_in_env_expansion = macro_file.is_some_and(|it| it.is_env_or_option_env(ctx.sema.db)); if !is_in_env_expansion { let call = macro_call_for_string_token(expanded)?; let makro = ctx.sema.resolve_macro_call(&call)?; @@ -116,6 +115,47 @@ fn main() { ); } + #[test] + fn complete_in_expanded_env_macro() { + check_edit( + "CARGO_BIN_NAME", + r#" +//- minicore: env +macro_rules! bar { + ($($arg:tt)*) => { $($arg)* } +} + +fn main() { + let foo = bar!(env!("CA$0")); +} + "#, + r#" +macro_rules! bar { + ($($arg:tt)*) => { $($arg)* } +} + +fn main() { + let foo = bar!(env!("CARGO_BIN_NAME")); +} + "#, + ); + + check_edit( + "CARGO_BIN_NAME", + r#" +//- minicore: env, fmt +fn main() { + let foo = format_args!("{}", env!("CA$0")); +} + "#, + r#" +fn main() { + let foo = format_args!("{}", env!("CARGO_BIN_NAME")); +} + "#, + ); + } + #[test] fn doesnt_complete_in_random_strings() { let fixture = r#"