about summary refs log tree commit diff
diff options
context:
space:
mode:
authorPascal Kuthe <pascal.kuthe@semimod.de>2023-03-04 02:05:09 +0100
committerPascal Kuthe <pascal.kuthe@semimod.de>2023-03-04 02:05:09 +0100
commit2e465d18f23f71f71f9c826087f78546e5aea529 (patch)
treef7de617eeef1bb9112a3253077cb6ec971aff216
parent73e2505cfa8be6838f5151b272f1d24869b2a3d6 (diff)
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.
-rw-r--r--crates/ide-completion/src/context.rs3
-rw-r--r--crates/ide-completion/src/render/macro_.rs59
2 files changed, 60 insertions, 2 deletions
diff --git a/crates/ide-completion/src/context.rs b/crates/ide-completion/src/context.rs
index 4dc4d212e60..7dc29c3d5ac 100644
--- a/crates/ide-completion/src/context.rs
+++ b/crates/ide-completion/src/context.rs
@@ -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 '
diff --git a/crates/ide-completion/src/render/macro_.rs b/crates/ide-completion/src/render/macro_.rs
index ffcad1185aa..44e88607633 100644
--- a/crates/ide-completion/src/render/macro_.rs
+++ b/crates/ide-completion/src/render/macro_.rs
@@ -267,4 +267,63 @@ fn main() {
 "#,
         );
     }
+
+    #[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)
+}
+"#,
+        );
+    }
 }