about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2022-06-16 09:14:09 +0000
committerbors <bors@rust-lang.org>2022-06-16 09:14:09 +0000
commit7ade4d49fc59ec939294897890375a8b86c743e2 (patch)
treeb830dfa6541f266682500727f9f4ec63637ab179
parent519d7484f3b1beb25dec9f2249adeaaa21033433 (diff)
parent534d71a852264cced80290afb2f994b179ddb40a (diff)
downloadrust-7ade4d49fc59ec939294897890375a8b86c743e2.tar.gz
rust-7ade4d49fc59ec939294897890375a8b86c743e2.zip
Auto merge of #12517 - xuhongxu96:master, r=Veykril
fix methods in pub trait generated by macro cannot be completed

Fix #12483

Check if the container is trait and inherit the visibility to associate items during collection.
-rw-r--r--crates/hir-def/src/data.rs21
-rw-r--r--crates/hir-def/src/item_tree/lower.rs52
-rw-r--r--crates/hir-def/src/item_tree/tests.rs37
-rw-r--r--crates/ide-completion/src/completions/dot.rs112
-rw-r--r--crates/ide-completion/src/tests.rs8
-rw-r--r--crates/ide-completion/src/tests/special.rs106
6 files changed, 252 insertions, 84 deletions
diff --git a/crates/hir-def/src/data.rs b/crates/hir-def/src/data.rs
index f2d8318f7d7..7436f0100bd 100644
--- a/crates/hir-def/src/data.rs
+++ b/crates/hir-def/src/data.rs
@@ -40,6 +40,11 @@ impl FunctionData {
         let cfg_options = &crate_graph[krate].cfg_options;
         let item_tree = loc.id.item_tree(db);
         let func = &item_tree[loc.id.value];
+        let visibility = if let ItemContainerId::TraitId(trait_id) = loc.container {
+            db.trait_data(trait_id).visibility.clone()
+        } else {
+            item_tree[func.visibility].clone()
+        };
 
         let enabled_params = func
             .params
@@ -93,7 +98,7 @@ impl FunctionData {
             ret_type: func.ret_type.clone(),
             async_ret_type: func.async_ret_type.clone(),
             attrs: item_tree.attrs(db, krate, ModItem::from(loc.id.value).into()),
-            visibility: item_tree[func.visibility].clone(),
+            visibility,
             abi: func.abi.clone(),
             legacy_const_generics_indices,
             flags,
@@ -171,11 +176,16 @@ impl TypeAliasData {
         let loc = typ.lookup(db);
         let item_tree = loc.id.item_tree(db);
         let typ = &item_tree[loc.id.value];
+        let visibility = if let ItemContainerId::TraitId(trait_id) = loc.container {
+            db.trait_data(trait_id).visibility.clone()
+        } else {
+            item_tree[typ.visibility].clone()
+        };
 
         Arc::new(TypeAliasData {
             name: typ.name.clone(),
             type_ref: typ.type_ref.clone(),
-            visibility: item_tree[typ.visibility].clone(),
+            visibility,
             is_extern: matches!(loc.container, ItemContainerId::ExternBlockId(_)),
             bounds: typ.bounds.to_vec(),
         })
@@ -385,11 +395,16 @@ impl ConstData {
         let loc = konst.lookup(db);
         let item_tree = loc.id.item_tree(db);
         let konst = &item_tree[loc.id.value];
+        let visibility = if let ItemContainerId::TraitId(trait_id) = loc.container {
+            db.trait_data(trait_id).visibility.clone()
+        } else {
+            item_tree[konst.visibility].clone()
+        };
 
         Arc::new(ConstData {
             name: konst.name.clone(),
             type_ref: konst.type_ref.clone(),
-            visibility: item_tree[konst.visibility].clone(),
+            visibility,
         })
     }
 }
diff --git a/crates/hir-def/src/item_tree/lower.rs b/crates/hir-def/src/item_tree/lower.rs
index cdae0d0803b..7f2551e9418 100644
--- a/crates/hir-def/src/item_tree/lower.rs
+++ b/crates/hir-def/src/item_tree/lower.rs
@@ -1,6 +1,6 @@
 //! AST -> `ItemTree` lowering code.
 
-use std::{collections::hash_map::Entry, mem, sync::Arc};
+use std::{collections::hash_map::Entry, sync::Arc};
 
 use hir_expand::{ast_id_map::AstIdMap, hygiene::Hygiene, HirFileId};
 use syntax::ast::{self, HasModuleItem};
@@ -21,7 +21,6 @@ pub(super) struct Ctx<'a> {
     tree: ItemTree,
     source_ast_id_map: Arc<AstIdMap>,
     body_ctx: crate::body::LowerCtx<'a>,
-    forced_visibility: Option<RawVisibilityId>,
 }
 
 impl<'a> Ctx<'a> {
@@ -31,7 +30,6 @@ impl<'a> Ctx<'a> {
             tree: ItemTree::default(),
             source_ast_id_map: db.ast_id_map(file),
             body_ctx: crate::body::LowerCtx::new(db, file),
-            forced_visibility: None,
         }
     }
 
@@ -225,11 +223,10 @@ impl<'a> Ctx<'a> {
         let visibility = self.lower_visibility(enum_);
         let name = enum_.name()?.as_name();
         let generic_params = self.lower_generic_params(GenericsOwner::Enum, enum_);
-        let variants =
-            self.with_inherited_visibility(visibility, |this| match &enum_.variant_list() {
-                Some(variant_list) => this.lower_variants(variant_list),
-                None => IdxRange::new(this.next_variant_idx()..this.next_variant_idx()),
-            });
+        let variants = match &enum_.variant_list() {
+            Some(variant_list) => self.lower_variants(variant_list),
+            None => IdxRange::new(self.next_variant_idx()..self.next_variant_idx()),
+        };
         let ast_id = self.source_ast_id_map.ast_id(enum_);
         let res = Enum { name, visibility, generic_params, variants, ast_id };
         Some(id(self.data().enums.alloc(res)))
@@ -440,18 +437,15 @@ impl<'a> Ctx<'a> {
         let is_auto = trait_def.auto_token().is_some();
         let is_unsafe = trait_def.unsafe_token().is_some();
         let items = trait_def.assoc_item_list().map(|list| {
-            let db = self.db;
-            self.with_inherited_visibility(visibility, |this| {
-                list.assoc_items()
-                    .filter_map(|item| {
-                        let attrs = RawAttrs::new(db, &item, this.hygiene());
-                        this.lower_assoc_item(&item).map(|item| {
-                            this.add_attrs(ModItem::from(item).into(), attrs);
-                            item
-                        })
+            list.assoc_items()
+                .filter_map(|item| {
+                    let attrs = RawAttrs::new(self.db, &item, self.hygiene());
+                    self.lower_assoc_item(&item).map(|item| {
+                        self.add_attrs(ModItem::from(item).into(), attrs);
+                        item
                     })
-                    .collect()
-            })
+                })
+                .collect()
         });
         let ast_id = self.source_ast_id_map.ast_id(trait_def);
         let res = Trait {
@@ -622,13 +616,7 @@ impl<'a> Ctx<'a> {
     }
 
     fn lower_visibility(&mut self, item: &dyn ast::HasVisibility) -> RawVisibilityId {
-        let vis = match self.forced_visibility {
-            Some(vis) => return vis,
-            None => {
-                RawVisibility::from_ast_with_hygiene(self.db, item.visibility(), self.hygiene())
-            }
-        };
-
+        let vis = RawVisibility::from_ast_with_hygiene(self.db, item.visibility(), self.hygiene());
         self.data().vis.alloc(vis)
     }
 
@@ -649,18 +637,6 @@ impl<'a> Ctx<'a> {
         }
     }
 
-    /// Forces the visibility `vis` to be used for all items lowered during execution of `f`.
-    fn with_inherited_visibility<R>(
-        &mut self,
-        vis: RawVisibilityId,
-        f: impl FnOnce(&mut Self) -> R,
-    ) -> R {
-        let old = mem::replace(&mut self.forced_visibility, Some(vis));
-        let res = f(self);
-        self.forced_visibility = old;
-        res
-    }
-
     fn next_field_idx(&self) -> Idx<Field> {
         Idx::from_raw(RawIdx::from(
             self.tree.data.as_ref().map_or(0, |data| data.fields.len() as u32),
diff --git a/crates/hir-def/src/item_tree/tests.rs b/crates/hir-def/src/item_tree/tests.rs
index fb3811dbd56..5cdf36cc61b 100644
--- a/crates/hir-def/src/item_tree/tests.rs
+++ b/crates/hir-def/src/item_tree/tests.rs
@@ -358,40 +358,3 @@ trait Tr<'a, T: 'a>: Super where Self: for<'a> Tr<'a, T> {}
         "#]],
     )
 }
-
-#[test]
-fn inherit_visibility() {
-    check(
-        r#"
-pub(crate) enum En {
-    Var1(u8),
-    Var2 {
-        fld: u8,
-    },
-}
-
-pub(crate) trait Tr {
-    fn f();
-    fn method(&self) {}
-}
-        "#,
-        expect![[r#"
-            pub(crate) enum En {
-                Var1(
-                    pub(crate) 0: u8,
-                ),
-                Var2 {
-                    pub(crate) fld: u8,
-                },
-            }
-
-            pub(crate) trait Tr<Self> {
-                pub(crate) fn f() -> ();
-
-                pub(crate) fn method(
-                    _: &Self,  // self
-                ) -> () { ... }
-            }
-        "#]],
-    )
-}
diff --git a/crates/ide-completion/src/completions/dot.rs b/crates/ide-completion/src/completions/dot.rs
index a11652ca302..4eb1fccd7d3 100644
--- a/crates/ide-completion/src/completions/dot.rs
+++ b/crates/ide-completion/src/completions/dot.rs
@@ -117,13 +117,20 @@ fn complete_methods(
 mod tests {
     use expect_test::{expect, Expect};
 
-    use crate::tests::{check_edit, completion_list_no_kw};
+    use crate::tests::{
+        check_edit, completion_list_no_kw, completion_list_no_kw_with_private_editable,
+    };
 
     fn check(ra_fixture: &str, expect: Expect) {
         let actual = completion_list_no_kw(ra_fixture);
         expect.assert_eq(&actual);
     }
 
+    fn check_with_private_editable(ra_fixture: &str, expect: Expect) {
+        let actual = completion_list_no_kw_with_private_editable(ra_fixture);
+        expect.assert_eq(&actual);
+    }
+
     #[test]
     fn test_struct_field_and_method_completion() {
         check(
@@ -202,6 +209,101 @@ pub mod m {
 fn foo(a: lib::m::A) { a.$0 }
 "#,
             expect![[r#"
+                fd pub_field u32
+            "#]],
+        );
+
+        check(
+            r#"
+//- /lib.rs crate:lib new_source_root:library
+pub mod m {
+    pub struct A {
+        private_field: u32,
+        pub pub_field: u32,
+        pub(crate) crate_field: u32,
+        pub(super) super_field: u32,
+    }
+}
+//- /main.rs crate:main deps:lib new_source_root:local
+fn foo(a: lib::m::A) { a.$0 }
+"#,
+            expect![[r#"
+                fd pub_field u32
+            "#]],
+        );
+
+        check(
+            r#"
+//- /lib.rs crate:lib new_source_root:library
+pub mod m {
+    pub struct A(
+        i32,
+        pub f64,
+    );
+}
+//- /main.rs crate:main deps:lib new_source_root:local
+fn foo(a: lib::m::A) { a.$0 }
+"#,
+            expect![[r#"
+                fd 1 f64
+            "#]],
+        );
+
+        check(
+            r#"
+//- /lib.rs crate:lib new_source_root:local
+pub struct A {}
+mod m {
+    impl super::A {
+        fn private_method(&self) {}
+        pub(crate) fn crate_method(&self) {}
+        pub fn pub_method(&self) {}
+    }
+}
+//- /main.rs crate:main deps:lib new_source_root:local
+fn foo(a: lib::A) { a.$0 }
+"#,
+            expect![[r#"
+                me pub_method() fn(&self)
+            "#]],
+        );
+        check(
+            r#"
+//- /lib.rs crate:lib new_source_root:library
+pub struct A {}
+mod m {
+    impl super::A {
+        fn private_method(&self) {}
+        pub(crate) fn crate_method(&self) {}
+        pub fn pub_method(&self) {}
+    }
+}
+//- /main.rs crate:main deps:lib new_source_root:local
+fn foo(a: lib::A) { a.$0 }
+"#,
+            expect![[r#"
+                me pub_method() fn(&self)
+            "#]],
+        );
+    }
+
+    #[test]
+    fn test_visibility_filtering_with_private_editable_enabled() {
+        check_with_private_editable(
+            r#"
+//- /lib.rs crate:lib new_source_root:local
+pub mod m {
+    pub struct A {
+        private_field: u32,
+        pub pub_field: u32,
+        pub(crate) crate_field: u32,
+        pub(super) super_field: u32,
+    }
+}
+//- /main.rs crate:main deps:lib new_source_root:local
+fn foo(a: lib::m::A) { a.$0 }
+"#,
+            expect![[r#"
                 fd crate_field   u32
                 fd private_field u32
                 fd pub_field     u32
@@ -209,7 +311,7 @@ fn foo(a: lib::m::A) { a.$0 }
             "#]],
         );
 
-        check(
+        check_with_private_editable(
             r#"
 //- /lib.rs crate:lib new_source_root:library
 pub mod m {
@@ -228,7 +330,7 @@ fn foo(a: lib::m::A) { a.$0 }
             "#]],
         );
 
-        check(
+        check_with_private_editable(
             r#"
 //- /lib.rs crate:lib new_source_root:library
 pub mod m {
@@ -245,7 +347,7 @@ fn foo(a: lib::m::A) { a.$0 }
             "#]],
         );
 
-        check(
+        check_with_private_editable(
             r#"
 //- /lib.rs crate:lib new_source_root:local
 pub struct A {}
@@ -265,7 +367,7 @@ fn foo(a: lib::A) { a.$0 }
                 me pub_method()     fn(&self)
             "#]],
         );
-        check(
+        check_with_private_editable(
             r#"
 //- /lib.rs crate:lib new_source_root:library
 pub struct A {}
diff --git a/crates/ide-completion/src/tests.rs b/crates/ide-completion/src/tests.rs
index d30ff77bab6..4be6acbe846 100644
--- a/crates/ide-completion/src/tests.rs
+++ b/crates/ide-completion/src/tests.rs
@@ -65,7 +65,7 @@ pub(crate) const TEST_CONFIG: CompletionConfig = CompletionConfig {
     enable_postfix_completions: true,
     enable_imports_on_the_fly: true,
     enable_self_on_the_fly: true,
-    enable_private_editable: true,
+    enable_private_editable: false,
     callable: Some(CallableSnippets::FillArguments),
     snippet_cap: SnippetCap::new(true),
     insert_use: InsertUseConfig {
@@ -86,6 +86,12 @@ pub(crate) fn completion_list_no_kw(ra_fixture: &str) -> String {
     completion_list_with_config(TEST_CONFIG, ra_fixture, false, None)
 }
 
+pub(crate) fn completion_list_no_kw_with_private_editable(ra_fixture: &str) -> String {
+    let mut config = TEST_CONFIG.clone();
+    config.enable_private_editable = true;
+    completion_list_with_config(config, ra_fixture, false, None)
+}
+
 pub(crate) fn completion_list_with_trigger_character(
     ra_fixture: &str,
     trigger_character: Option<char>,
diff --git a/crates/ide-completion/src/tests/special.rs b/crates/ide-completion/src/tests/special.rs
index 6195537a18e..4535923b28b 100644
--- a/crates/ide-completion/src/tests/special.rs
+++ b/crates/ide-completion/src/tests/special.rs
@@ -636,3 +636,109 @@ fn bar() -> Bar {
             "#]],
     )
 }
+
+#[test]
+fn completes_fn_in_pub_trait_generated_by_macro() {
+    check(
+        r#"
+mod other_mod {
+    macro_rules! make_method {
+        ($name:ident) => {
+            fn $name(&self) {}
+        };
+    }
+
+    pub trait MyTrait {
+        make_method! { by_macro }
+        fn not_by_macro(&self) {}
+    }
+
+    pub struct Foo {}
+
+    impl MyTrait for Foo {}
+}
+
+fn main() {
+    use other_mod::{Foo, MyTrait};
+    let f = Foo {};
+    f.$0
+}
+"#,
+        expect![[r#"
+            me by_macro() (as MyTrait) fn(&self)
+            me not_by_macro() (as MyTrait) fn(&self)
+        "#]],
+    )
+}
+
+#[test]
+fn completes_fn_in_pub_trait_generated_by_recursive_macro() {
+    check(
+        r#"
+mod other_mod {
+    macro_rules! make_method {
+        ($name:ident) => {
+            fn $name(&self) {}
+        };
+    }
+
+    macro_rules! make_trait {
+        () => {
+            pub trait MyTrait {
+                make_method! { by_macro }
+                fn not_by_macro(&self) {}
+            }
+        }
+    }
+
+    make_trait!();
+
+    pub struct Foo {}
+
+    impl MyTrait for Foo {}
+}
+
+fn main() {
+    use other_mod::{Foo, MyTrait};
+    let f = Foo {};
+    f.$0
+}
+"#,
+        expect![[r#"
+            me by_macro() (as MyTrait) fn(&self)
+            me not_by_macro() (as MyTrait) fn(&self)
+        "#]],
+    )
+}
+
+#[test]
+fn completes_const_in_pub_trait_generated_by_macro() {
+    check(
+        r#"
+mod other_mod {
+    macro_rules! make_const {
+        ($name:ident) => {
+            const $name: u8 = 1;
+        };
+    }
+
+    pub trait MyTrait {
+        make_const! { by_macro }
+    }
+
+    pub struct Foo {}
+
+    impl MyTrait for Foo {}
+}
+
+fn main() {
+    use other_mod::{Foo, MyTrait};
+    let f = Foo {};
+    Foo::$0
+}
+"#,
+        expect![[r#"
+            ct by_macro (as MyTrait) pub const by_macro: u8
+        "#]],
+    )
+}