Repository: rust-analyzer/rust-analyzer
Pull request #11265 (2022-01-12 12:07:30)

fix: Fix postfix completion panic
Fixes https://github.com/rust-analyzer/rust-analyzer/issues/11233
bors r+


Patch:
diff --git a/crates/ide_completion/src/completions/attribute.rs b/crates/ide_completion/src/completions/attribute.rs
index 2603ad2003..f67d7d56d8 100644
--- a/crates/ide_completion/src/completions/attribute.rs
+++ b/crates/ide_completion/src/completions/attribute.rs
@@ -56,7 +56,6 @@ pub(crate) fn complete_attribute(acc: &mut Completions, ctx: &CompletionContext)
             _ => (),
         },
         (_, Some(_)) => (),
-        (_, None) if attribute.expr().is_some() => (),
         (_, None) => complete_new_attribute(acc, ctx, attribute),
     }
     Some(())
diff --git a/crates/ide_completion/src/completions/fn_param.rs b/crates/ide_completion/src/completions/fn_param.rs
index a55bab67e1..bb4ce0a24d 100644
--- a/crates/ide_completion/src/completions/fn_param.rs
+++ b/crates/ide_completion/src/completions/fn_param.rs
@@ -83,15 +83,9 @@ fn remove_duplicated(
         let whole_param = param.syntax().text().to_string();
         file_params.remove(&whole_param);
 
-        match param.pat() {
-            // remove suggestions for patterns that already exist
-            // if the type is missing we are checking the current param to be completed
-            // in which case this would find itself removing the suggestions due to itself
-            Some(pattern) if param.ty().is_some() => {
-                let binding = pattern.syntax().text().to_string();
-                file_params.retain(|_, v| v != &binding);
-            }
-            _ => (),
+        if let Some(pattern) = param.pat() {
+            let binding = pattern.syntax().text().to_string();
+            file_params.retain(|_, v| v != &binding);
         }
     })
 }
diff --git a/crates/ide_completion/src/completions/postfix.rs b/crates/ide_completion/src/completions/postfix.rs
index a212a98461..0dfb8abb8b 100644
--- a/crates/ide_completion/src/completions/postfix.rs
+++ b/crates/ide_completion/src/completions/postfix.rs
@@ -225,6 +225,10 @@ fn build_postfix_snippet_builder<'ctx>(
 ) -> Option<impl Fn(&str, &str, &str) -> Builder + 'ctx> {
     let receiver_syntax = receiver.syntax();
     let receiver_range = ctx.sema.original_range_opt(receiver_syntax)?.range;
+    if ctx.source_range().end() < receiver_range.start() {
+        // This shouldn't happen, yet it does. I assume this might be due to an incorrect token mapping.
+        return None;
+    }
     let delete_range = TextRange::new(receiver_range.start(), ctx.source_range().end());
 
     // Wrapping impl Fn in an option ruins lifetime inference for the parameters in a way that


Test patch:
diff --git a/crates/ide_completion/src/tests/attribute.rs b/crates/ide_completion/src/tests/attribute.rs
index 2d2a1b867a..c2bd26e2d8 100644
--- a/crates/ide_completion/src/tests/attribute.rs
+++ b/crates/ide_completion/src/tests/attribute.rs
@@ -40,19 +40,6 @@ struct Foo;
     )
 }
 
-#[test]
-fn proc_macros_on_comment() {
-    check(
-        r#"
-//- proc_macros: identity
-/// $0
-#[proc_macros::identity]
-struct Foo;
-"#,
-        expect![[r#""#]],
-    )
-}
-
 #[test]
 fn proc_macros_qualified() {
     check(
diff --git a/crates/ide_completion/src/tests/pattern.rs b/crates/ide_completion/src/tests/pattern.rs
index 7f437e1a07..c9a31eea84 100644
--- a/crates/ide_completion/src/tests/pattern.rs
+++ b/crates/ide_completion/src/tests/pattern.rs
@@ -368,17 +368,3 @@ fn foo() {
         "#]],
     )
 }
-
-#[test]
-fn completes_fully_equal() {
-    check_empty(
-        r#"
-fn foo(bar: u32) {}
-fn bar(bar$0) {}
-"#,
-        expect![[r#"
-            bn bar: u32
-            kw mut
-        "#]],
-    )
-}