|
1 | 1 | use hir::{Ty, AdtDef, TypeCtor};
|
2 | 2 |
|
3 | 3 | use crate::completion::{CompletionContext, Completions};
|
| 4 | +use rustc_hash::FxHashSet; |
4 | 5 |
|
5 | 6 | /// Complete dot accesses, i.e. fields or methods (currently only fields).
|
6 | 7 | pub(super) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) {
|
@@ -36,9 +37,10 @@ fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: Ty)
|
36 | 37 | }
|
37 | 38 |
|
38 | 39 | fn complete_methods(acc: &mut Completions, ctx: &CompletionContext, receiver: Ty) {
|
| 40 | + let mut seen_methods = FxHashSet::default(); |
39 | 41 | ctx.analyzer.iterate_method_candidates(ctx.db, receiver, None, |_ty, func| {
|
40 | 42 | let data = func.data(ctx.db);
|
41 |
| - if data.has_self_param() { |
| 43 | + if data.has_self_param() && seen_methods.insert(data.name().clone()) { |
42 | 44 | acc.add_function(ctx, func);
|
43 | 45 | }
|
44 | 46 | None::<()>
|
@@ -230,6 +232,34 @@ mod tests {
|
230 | 232 | );
|
231 | 233 | }
|
232 | 234 |
|
| 235 | + #[test] |
| 236 | + fn test_trait_method_completion_deduplicated() { |
| 237 | + assert_debug_snapshot_matches!( |
| 238 | + do_ref_completion( |
| 239 | + r" |
| 240 | + struct A {} |
| 241 | + trait Trait { fn the_method(&self); } |
| 242 | + impl<T> Trait for T {} |
| 243 | + fn foo(a: &A) { |
| 244 | + a.<|> |
| 245 | + } |
| 246 | + ", |
| 247 | + ), |
| 248 | + @r###" |
| 249 | + ⋮[ |
| 250 | + ⋮ CompletionItem { |
| 251 | + ⋮ label: "the_method", |
| 252 | + ⋮ source_range: [155; 155), |
| 253 | + ⋮ delete: [155; 155), |
| 254 | + ⋮ insert: "the_method()$0", |
| 255 | + ⋮ kind: Method, |
| 256 | + ⋮ detail: "fn the_method(&self)", |
| 257 | + ⋮ }, |
| 258 | + ⋮] |
| 259 | + "### |
| 260 | + ); |
| 261 | + } |
| 262 | + |
233 | 263 | #[test]
|
234 | 264 | fn test_no_non_self_method() {
|
235 | 265 | assert_debug_snapshot_matches!(
|
|
0 commit comments