Skip to content

Commit 2e465d1

Browse files
committed
generate correct completion edits for missing macro arguments
rust-analyzer used the token at the cursor after macro expansion to decide whether to replace the token at the cursor before macro expansion. In most cases these two are the same but in some cases these can mismatch which can lead to incorrect replacements. For example if an ident/expr macro argument is missing rust-analyzer generates a "missing" identifier as a placeholder, there is only a brace at the cursor. Therefore, rust-analyzer will incorrectly replace the macro brace with the completion in that case leading to #14246. Using the expanded token type was intentional. However, this doesn't seem to ever be desirable (this is supported by the fact that there were no tests that relied on this behavior) since the type of edit to perform should always be determined by the token it's actually applied to.
1 parent 73e2505 commit 2e465d1

File tree

2 files changed

+60
-2
lines changed

2 files changed

+60
-2
lines changed

crates/ide-completion/src/context.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -387,8 +387,7 @@ pub(crate) struct CompletionContext<'a> {
387387
impl<'a> CompletionContext<'a> {
388388
/// The range of the identifier that is being completed.
389389
pub(crate) fn source_range(&self) -> TextRange {
390-
// check kind of macro-expanded token, but use range of original token
391-
let kind = self.token.kind();
390+
let kind = self.original_token.kind();
392391
match kind {
393392
CHAR => {
394393
// assume we are completing a lifetime but the user has only typed the '

crates/ide-completion/src/render/macro_.rs

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,65 @@ macro_rules! foo {
264264
fn main() {
265265
foo!($0)
266266
}
267+
"#,
268+
);
269+
}
270+
271+
#[test]
272+
fn complete_missing_macro_arg() {
273+
// Regression test for https://github.com/rust-lang/rust-analyzer/issues/14246
274+
check_edit(
275+
"BAR",
276+
r#"
277+
macro_rules! foo {
278+
($val:ident, $val2: ident) => {
279+
$val $val2
280+
};
281+
}
282+
283+
const BAR: u32 = 9;
284+
fn main() {
285+
foo!(BAR, $0)
286+
}
287+
"#,
288+
r#"
289+
macro_rules! foo {
290+
($val:ident, $val2: ident) => {
291+
$val $val2
292+
};
293+
}
294+
295+
const BAR: u32 = 9;
296+
fn main() {
297+
foo!(BAR, BAR)
298+
}
299+
"#,
300+
);
301+
check_edit(
302+
"BAR",
303+
r#"
304+
macro_rules! foo {
305+
($val:ident, $val2: ident) => {
306+
$val $val2
307+
};
308+
}
309+
310+
const BAR: u32 = 9;
311+
fn main() {
312+
foo!($0)
313+
}
314+
"#,
315+
r#"
316+
macro_rules! foo {
317+
($val:ident, $val2: ident) => {
318+
$val $val2
319+
};
320+
}
321+
322+
const BAR: u32 = 9;
323+
fn main() {
324+
foo!(BAR)
325+
}
267326
"#,
268327
);
269328
}

0 commit comments

Comments
 (0)