Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/ide-completion/src/completions/dot.rs')
-rw-r--r--crates/ide-completion/src/completions/dot.rs56
1 files changed, 46 insertions, 10 deletions
diff --git a/crates/ide-completion/src/completions/dot.rs b/crates/ide-completion/src/completions/dot.rs
index 229ce7723b..26074672ba 100644
--- a/crates/ide-completion/src/completions/dot.rs
+++ b/crates/ide-completion/src/completions/dot.rs
@@ -1,6 +1,8 @@
//! Completes references after dot (fields and method calls).
-use hir::{sym, Name};
+use std::ops::ControlFlow;
+
+use hir::{sym, HasContainer, ItemContainer, MethodCandidateCallback, Name};
use ide_db::FxHashSet;
use syntax::SmolStr;
@@ -158,21 +160,55 @@ fn complete_fields(
fn complete_methods(
ctx: &CompletionContext<'_>,
receiver: &hir::Type,
- mut f: impl FnMut(hir::Function),
+ f: impl FnMut(hir::Function),
) {
- let mut seen_methods = FxHashSet::default();
- receiver.iterate_method_candidates_with_traits(
+ struct Callback<'a, F> {
+ ctx: &'a CompletionContext<'a>,
+ f: F,
+ seen_methods: FxHashSet<Name>,
+ }
+
+ impl<F> MethodCandidateCallback for Callback<'_, F>
+ where
+ F: FnMut(hir::Function),
+ {
+ // 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))
+ {
+ (self.f)(func);
+ }
+ ControlFlow::Continue(())
+ }
+
+ fn on_trait_method(&mut self, func: hir::Function) -> ControlFlow<()> {
+ // This needs to come before the `seen_methods` test, so that if we see the same method twice,
+ // once as inherent and once not, we will include it.
+ if let ItemContainer::Trait(trait_) = func.container(self.ctx.db) {
+ if self.ctx.exclude_traits.contains(&trait_) {
+ return ControlFlow::Continue(());
+ }
+ }
+
+ if func.self_param(self.ctx.db).is_some()
+ && self.seen_methods.insert(func.name(self.ctx.db))
+ {
+ (self.f)(func);
+ }
+
+ ControlFlow::Continue(())
+ }
+ }
+
+ receiver.iterate_method_candidates_split_inherent(
ctx.db,
&ctx.scope,
&ctx.traits_in_scope(),
Some(ctx.module),
None,
- |func| {
- if func.self_param(ctx.db).is_some() && seen_methods.insert(func.name(ctx.db)) {
- f(func);
- }
- None::<()>
- },
+ Callback { ctx, f, seen_methods: FxHashSet::default() },
);
}