Skip to content

Commit e2d3c15

Browse files
committed
Restrict auto-completion for only built-in macros
1 parent f458ea1 commit e2d3c15

File tree

1 file changed

+49
-12
lines changed

1 file changed

+49
-12
lines changed

crates/ide-completion/src/completions/env_vars.rs

Lines changed: 49 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
//! Completes environment variables defined by Cargo (https://doc.rust-lang.org/cargo/reference/environment-variables.html)
2-
use ide_db::syntax_helpers::node_ext::get_outer_macro_name;
2+
use hir::Semantics;
3+
use ide_db::{syntax_helpers::node_ext::get_outer_macro, RootDatabase};
34
use syntax::ast::{self, IsString};
45

5-
use crate::{CompletionItem, CompletionItemKind};
6+
use crate::{context::CompletionContext, CompletionItem, CompletionItemKind};
67

78
use super::Completions;
89
const CARGO_DEFINED_VARS: &[(&str, &str)] = &[
@@ -27,8 +28,12 @@ const CARGO_DEFINED_VARS: &[(&str, &str)] = &[
2728
("CARGO_TARGET_TMPDIR","Only set when building integration test or benchmark code. This is a path to a directory inside the target directory where integration tests or benchmarks are free to put any data needed by the tests/benches. Cargo initially creates this directory but doesn't manage its content in any way, this is the responsibility of the test code")
2829
];
2930

30-
pub(crate) fn complete_cargo_env_vars(acc: &mut Completions, expanded: &ast::String) -> Option<()> {
31-
guard_env_macro(expanded)?;
31+
pub(crate) fn complete_cargo_env_vars(
32+
acc: &mut Completions,
33+
ctx: &CompletionContext<'_>,
34+
expanded: &ast::String,
35+
) -> Option<()> {
36+
guard_env_macro(expanded, &ctx.sema, &ctx.db)?;
3237
let range = expanded.text_range_between_quotes()?;
3338

3439
CARGO_DEFINED_VARS.iter().for_each(|(var, detail)| {
@@ -40,13 +45,19 @@ pub(crate) fn complete_cargo_env_vars(acc: &mut Completions, expanded: &ast::Str
4045
Some(())
4146
}
4247

43-
fn guard_env_macro(string: &ast::String) -> Option<()> {
44-
let name = get_outer_macro_name(string)?;
45-
if !matches!(name.text().as_str(), "env" | "option_env") {
46-
return None;
48+
fn guard_env_macro(
49+
string: &ast::String,
50+
semantics: &Semantics<'_, RootDatabase>,
51+
db: &RootDatabase,
52+
) -> Option<()> {
53+
let call = get_outer_macro(string)?;
54+
let name = call.path()?.segment()?.name_ref()?;
55+
let makro = semantics.resolve_macro_call(&call)?;
56+
57+
match name.text().as_str() {
58+
"env" | "option_env" if makro.kind(db) == hir::MacroKind::BuiltIn => Some(()),
59+
_ => None,
4760
}
48-
49-
Some(())
5061
}
5162

5263
#[cfg(test)]
@@ -58,19 +69,29 @@ mod tests {
5869
"CARGO_BIN_NAME",
5970
&format!(
6071
r#"
72+
#[rustc_builtin_macro]
73+
macro_rules! {} {{
74+
($var:literal) => {{ 0 }}
75+
}}
76+
6177
fn main() {{
6278
let foo = {}!("CAR$0");
6379
}}
6480
"#,
65-
macro_name
81+
macro_name, macro_name
6682
),
6783
&format!(
6884
r#"
85+
#[rustc_builtin_macro]
86+
macro_rules! {} {{
87+
($var:literal) => {{ 0 }}
88+
}}
89+
6990
fn main() {{
7091
let foo = {}!("CARGO_BIN_NAME");
7192
}}
7293
"#,
73-
macro_name
94+
macro_name, macro_name
7495
),
7596
);
7697
}
@@ -112,4 +133,20 @@ mod tests {
112133
let completions = completion_list(fixture);
113134
assert!(completions.is_empty(), "Completions weren't empty: {}", completions);
114135
}
136+
137+
#[test]
138+
fn doesnt_complete_for_shadowed_macro() {
139+
let fixture = r#"
140+
macro_rules! env {
141+
($var:literal) => { 0 }
142+
}
143+
144+
fn main() {
145+
let foo = env!("CA$0");
146+
}
147+
"#;
148+
149+
let completions = completion_list(fixture);
150+
assert!(completions.is_empty(), "Completions weren't empty: {}", completions)
151+
}
115152
}

0 commit comments

Comments
 (0)