mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-11-17 10:18:31 +00:00
Auto merge of #14247 - pascalkuthe:master, r=Veykril
generate correct completion edits for missing macro arguments Fixes #14246 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. Therefore this PR simply switches the relevant match to use the unexpanded token instead
This commit is contained in:
commit
4b330f52f6
2 changed files with 60 additions and 2 deletions
|
@ -387,8 +387,7 @@ pub(crate) struct CompletionContext<'a> {
|
|||
impl<'a> CompletionContext<'a> {
|
||||
/// The range of the identifier that is being completed.
|
||||
pub(crate) fn source_range(&self) -> TextRange {
|
||||
// check kind of macro-expanded token, but use range of original token
|
||||
let kind = self.token.kind();
|
||||
let kind = self.original_token.kind();
|
||||
match kind {
|
||||
CHAR => {
|
||||
// assume we are completing a lifetime but the user has only typed the '
|
||||
|
|
|
@ -264,6 +264,65 @@ macro_rules! foo {
|
|||
fn main() {
|
||||
foo!($0)
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn complete_missing_macro_arg() {
|
||||
// Regression test for https://github.com/rust-lang/rust-analyzer/issues/14246
|
||||
check_edit(
|
||||
"BAR",
|
||||
r#"
|
||||
macro_rules! foo {
|
||||
($val:ident, $val2: ident) => {
|
||||
$val $val2
|
||||
};
|
||||
}
|
||||
|
||||
const BAR: u32 = 9;
|
||||
fn main() {
|
||||
foo!(BAR, $0)
|
||||
}
|
||||
"#,
|
||||
r#"
|
||||
macro_rules! foo {
|
||||
($val:ident, $val2: ident) => {
|
||||
$val $val2
|
||||
};
|
||||
}
|
||||
|
||||
const BAR: u32 = 9;
|
||||
fn main() {
|
||||
foo!(BAR, BAR)
|
||||
}
|
||||
"#,
|
||||
);
|
||||
check_edit(
|
||||
"BAR",
|
||||
r#"
|
||||
macro_rules! foo {
|
||||
($val:ident, $val2: ident) => {
|
||||
$val $val2
|
||||
};
|
||||
}
|
||||
|
||||
const BAR: u32 = 9;
|
||||
fn main() {
|
||||
foo!($0)
|
||||
}
|
||||
"#,
|
||||
r#"
|
||||
macro_rules! foo {
|
||||
($val:ident, $val2: ident) => {
|
||||
$val $val2
|
||||
};
|
||||
}
|
||||
|
||||
const BAR: u32 = 9;
|
||||
fn main() {
|
||||
foo!(BAR)
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue