From 472ae16bfbdb8983f7bf94dfe1429a028998a8ef Mon Sep 17 00:00:00 2001
From: yue4u <github@yue.coffee>
Date: Fri, 24 Jun 2022 00:00:51 +0900
Subject: [PATCH] fix: completes non exhaustive variant within the defining
 crate

---
 crates/hir/src/lib.rs                       | 18 ++++++++++
 crates/ide-completion/src/render/variant.rs | 11 +++---
 crates/ide-completion/src/tests/special.rs  | 40 +++++++++++++++++++++
 3 files changed, 64 insertions(+), 5 deletions(-)

diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 3f0d586bf6..cc4d14c12d 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -3497,12 +3497,30 @@ impl HasCrate for AssocItem {
     }
 }
 
+impl HasCrate for Struct {
+    fn krate(&self, db: &dyn HirDatabase) -> Crate {
+        self.module(db).krate()
+    }
+}
+
+impl HasCrate for Union {
+    fn krate(&self, db: &dyn HirDatabase) -> Crate {
+        self.module(db).krate()
+    }
+}
+
 impl HasCrate for Field {
     fn krate(&self, db: &dyn HirDatabase) -> Crate {
         self.parent_def(db).module(db).krate()
     }
 }
 
+impl HasCrate for Variant {
+    fn krate(&self, db: &dyn HirDatabase) -> Crate {
+        self.module(db).krate()
+    }
+}
+
 impl HasCrate for Function {
     fn krate(&self, db: &dyn HirDatabase) -> Crate {
         self.module(db).krate()
diff --git a/crates/ide-completion/src/render/variant.rs b/crates/ide-completion/src/render/variant.rs
index 39a37dc9f8..2c9fb9b35a 100644
--- a/crates/ide-completion/src/render/variant.rs
+++ b/crates/ide-completion/src/render/variant.rs
@@ -1,7 +1,7 @@
 //! Code common to structs, unions, and enum variants.
 
 use crate::context::CompletionContext;
-use hir::{db::HirDatabase, HasAttrs, HasVisibility, HirDisplay, StructKind};
+use hir::{db::HirDatabase, HasAttrs, HasCrate, HasVisibility, HirDisplay, StructKind};
 use ide_db::SnippetCap;
 use itertools::Itertools;
 use syntax::SmolStr;
@@ -70,7 +70,7 @@ pub(crate) fn render_tuple_lit(
 pub(crate) fn visible_fields(
     ctx: &CompletionContext,
     fields: &[hir::Field],
-    item: impl HasAttrs,
+    item: impl HasAttrs + HasCrate + Copy,
 ) -> Option<(Vec<hir::Field>, bool)> {
     let module = ctx.module;
     let n_fields = fields.len();
@@ -79,9 +79,10 @@ pub(crate) fn visible_fields(
         .filter(|field| field.is_visible_from(ctx.db, module))
         .copied()
         .collect::<Vec<_>>();
-
-    let fields_omitted =
-        n_fields - fields.len() > 0 || item.attrs(ctx.db).by_key("non_exhaustive").exists();
+    let has_invisible_field = n_fields - fields.len() > 0;
+    let is_foreign_non_exhaustive = item.attrs(ctx.db).by_key("non_exhaustive").exists()
+        && item.krate(ctx.db) != module.krate();
+    let fields_omitted = has_invisible_field || is_foreign_non_exhaustive;
     Some((fields, fields_omitted))
 }
 
diff --git a/crates/ide-completion/src/tests/special.rs b/crates/ide-completion/src/tests/special.rs
index 4535923b28..f1557107e0 100644
--- a/crates/ide-completion/src/tests/special.rs
+++ b/crates/ide-completion/src/tests/special.rs
@@ -540,6 +540,46 @@ impl Foo {
     );
 }
 
+#[test]
+fn completes_non_exhaustive_variant_within_the_defining_crate() {
+    check(
+        r#"
+enum Foo {
+    #[non_exhaustive]
+    Bar,
+    Baz,
+}
+
+fn foo(self) {
+    Foo::$0
+}
+"#,
+        expect![[r#"
+                ev Bar Bar
+                ev Baz Baz
+            "#]],
+    );
+
+    check(
+        r#"
+//- /main.rs crate:main deps:e
+fn foo(self) {
+    e::Foo::$0
+}
+
+//- /e.rs crate:e
+enum Foo {
+    #[non_exhaustive]
+    Bar,
+    Baz,
+}
+"#,
+        expect![[r#"
+                ev Baz Baz
+            "#]],
+    );
+}
+
 #[test]
 fn completes_primitive_assoc_const() {
     cov_mark::check!(completes_primitive_assoc_const);