about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--crates/ide-completion/src/lib.rs22
-rw-r--r--crates/ide-completion/src/tests/special.rs109
2 files changed, 131 insertions, 0 deletions
diff --git a/crates/ide-completion/src/lib.rs b/crates/ide-completion/src/lib.rs
index 2eaa42040a0..2fad293d16d 100644
--- a/crates/ide-completion/src/lib.rs
+++ b/crates/ide-completion/src/lib.rs
@@ -169,6 +169,28 @@ pub fn completions(
         return Some(completions.into());
     }
 
+    // when the user types a bare `_` (that is it does not belong to an identifier)
+    // the user might just wanted to type a `_` for type inference or pattern discarding
+    // so try to suppress completions in those cases
+    if trigger_character == Some('_') && ctx.original_token.kind() == syntax::SyntaxKind::UNDERSCORE
+    {
+        if let CompletionAnalysis::NameRef(NameRefContext {
+            kind:
+                NameRefKind::Path(
+                    path_ctx @ PathCompletionCtx {
+                        kind: PathKind::Type { .. } | PathKind::Pat { .. },
+                        ..
+                    },
+                ),
+            ..
+        }) = analysis
+        {
+            if path_ctx.is_trivial_path() {
+                return None;
+            }
+        }
+    }
+
     {
         let acc = &mut completions;
 
diff --git a/crates/ide-completion/src/tests/special.rs b/crates/ide-completion/src/tests/special.rs
index 83888e08f1c..d3dbd7cc227 100644
--- a/crates/ide-completion/src/tests/special.rs
+++ b/crates/ide-completion/src/tests/special.rs
@@ -1372,3 +1372,112 @@ fn main() {
         expect!("pub const fn baz<'foo>(&'foo mut self, x: &'foo Foo) -> !"),
     );
 }
+
+#[test]
+fn skips_underscore() {
+    check_with_trigger_character(
+        r#"
+fn foo(_$0) { }
+"#,
+        Some('_'),
+        expect![[r#""#]],
+    );
+    check_with_trigger_character(
+        r#"
+fn foo(_: _$0) { }
+"#,
+        Some('_'),
+        expect![[r#""#]],
+    );
+    check_with_trigger_character(
+        r#"
+fn foo<T>() {
+    foo::<_$0>();
+}
+"#,
+        Some('_'),
+        expect![[r#""#]],
+    );
+    // underscore expressions are fine, they are invalid so the user definitely meant to type an
+    // underscored name here
+    check_with_trigger_character(
+        r#"
+fn foo() {
+    _$0
+}
+"#,
+        Some('_'),
+        expect![[r#"
+            fn foo()       fn()
+            bt u32
+            kw const
+            kw crate::
+            kw enum
+            kw extern
+            kw false
+            kw fn
+            kw for
+            kw if
+            kw if let
+            kw impl
+            kw let
+            kw loop
+            kw match
+            kw mod
+            kw return
+            kw self::
+            kw static
+            kw struct
+            kw trait
+            kw true
+            kw type
+            kw union
+            kw unsafe
+            kw use
+            kw while
+            kw while let
+            sn macro_rules
+            sn pd
+            sn ppd
+        "#]],
+    );
+}
+
+#[test]
+fn no_skip_underscore_ident() {
+    check_with_trigger_character(
+        r#"
+fn foo(a_$0) { }
+"#,
+        Some('_'),
+        expect![[r#"
+            kw mut
+            kw ref
+        "#]],
+    );
+    check_with_trigger_character(
+        r#"
+fn foo(_: a_$0) { }
+"#,
+        Some('_'),
+        expect![[r#"
+            bt u32
+            kw crate::
+            kw self::
+        "#]],
+    );
+    check_with_trigger_character(
+        r#"
+fn foo<T>() {
+    foo::<a_$0>();
+}
+"#,
+        Some('_'),
+        expect![[r#"
+            tp T
+            bt u32
+            kw crate::
+            kw self::
+        "#]],
+    );
+}