diff --git a/crates/ide-completion/src/completions/dot.rs b/crates/ide-completion/src/completions/dot.rs index 129964f838..b9ef68cc2d 100644 --- a/crates/ide-completion/src/completions/dot.rs +++ b/crates/ide-completion/src/completions/dot.rs @@ -2,7 +2,7 @@ use std::ops::ControlFlow; -use hir::{Complete, HasContainer, ItemContainer, MethodCandidateCallback, Name}; +use hir::{Complete, Function, HasContainer, ItemContainer, MethodCandidateCallback}; use ide_db::FxHashSet; use syntax::SmolStr; @@ -237,7 +237,10 @@ fn complete_methods( struct Callback<'a, F> { ctx: &'a CompletionContext<'a>, f: F, - seen_methods: FxHashSet, + // We deliberately deduplicate by function ID and not name, because while inherent methods cannot be + // duplicated, trait methods can. And it is still useful to show all of them (even when there + // is also an inherent method, especially considering that it may be private, and filtered later). + seen_methods: FxHashSet, } impl MethodCandidateCallback for Callback<'_, F> @@ -247,9 +250,7 @@ fn complete_methods( // We don't want to exclude inherent trait methods - that is, methods of traits available from // `where` clauses or `dyn Trait`. fn on_inherent_method(&mut self, func: hir::Function) -> ControlFlow<()> { - if func.self_param(self.ctx.db).is_some() - && self.seen_methods.insert(func.name(self.ctx.db)) - { + if func.self_param(self.ctx.db).is_some() && self.seen_methods.insert(func) { (self.f)(func); } ControlFlow::Continue(()) @@ -265,9 +266,7 @@ fn complete_methods( return ControlFlow::Continue(()); } - if func.self_param(self.ctx.db).is_some() - && self.seen_methods.insert(func.name(self.ctx.db)) - { + if func.self_param(self.ctx.db).is_some() && self.seen_methods.insert(func) { (self.f)(func); } diff --git a/crates/ide-completion/src/tests/expression.rs b/crates/ide-completion/src/tests/expression.rs index 7a0d004441..af6ef34761 100644 --- a/crates/ide-completion/src/tests/expression.rs +++ b/crates/ide-completion/src/tests/expression.rs @@ -2632,3 +2632,43 @@ fn let_in_condition() { fn let_in_let_chain() { check_edit("let", r#"fn f() { if true && $0 {} }"#, r#"fn f() { if true && let $1 = $0 {} }"#); } + +#[test] +fn private_inherent_and_public_trait() { + check( + r#" +struct Foo; + +mod private { + impl super::Foo { + fn method(&self) {} + } +} + +trait Trait { + fn method(&self) {} +} +impl Trait for Foo {} + +fn main() { + Foo.$0 +} + "#, + expect![[r#" + me method() (as Trait) fn(&self) + sn box Box::new(expr) + sn call function(expr) + sn const const {} + sn dbg dbg!(expr) + sn dbgr dbg!(&expr) + sn deref *expr + sn let let + sn letm let mut + sn match match expr {} + sn ref &expr + sn refm &mut expr + sn return return expr + sn unsafe unsafe {} + "#]], + ); +}