Unnamed repository; edit this file 'description' to name the repository.
Merge pull request #22376 from A4-Tacks/method-hide-same-name
fix: not complete same name inherent deref methods
Chayim Refael Friedman 3 weeks ago
parent 7a4f9e8 · parent be99012 · commit 4c52c35
-rw-r--r--crates/hir-ty/src/method_resolution/probe.rs5
-rw-r--r--crates/ide-completion/src/completions/dot.rs112
-rw-r--r--crates/ide-completion/src/tests/flyimport.rs2
3 files changed, 111 insertions, 8 deletions
diff --git a/crates/hir-ty/src/method_resolution/probe.rs b/crates/hir-ty/src/method_resolution/probe.rs
index 4b2f0cfd70..60344490d5 100644
--- a/crates/hir-ty/src/method_resolution/probe.rs
+++ b/crates/hir-ty/src/method_resolution/probe.rs
@@ -3,6 +3,7 @@
use std::{cell::RefCell, convert::Infallible, ops::ControlFlow};
+use base_db::FxIndexMap;
use hir_def::{
AssocItemId, FunctionId, GenericParamId, ImplId, ItemContainerId, TraitId,
hir::generics::GenericParams,
@@ -10,7 +11,7 @@ use hir_def::{
};
use hir_expand::name::Name;
use rustc_ast_ir::Mutability;
-use rustc_hash::{FxHashMap, FxHashSet};
+use rustc_hash::FxHashSet;
use rustc_type_ir::{
InferTy, TypeVisitableExt, Upcast, Variance,
elaborate::{self, supertrait_def_ids},
@@ -719,7 +720,7 @@ impl<'db> ProbeChoice<'db> for ProbeForNameChoice<'db> {
#[derive(Debug)]
struct ProbeAllChoice<'db> {
- candidates: RefCell<FxHashMap<CandidateId, CandidateWithPrivate<'db>>>,
+ candidates: RefCell<FxIndexMap<CandidateId, CandidateWithPrivate<'db>>>,
considering_visible_candidates: bool,
}
diff --git a/crates/ide-completion/src/completions/dot.rs b/crates/ide-completion/src/completions/dot.rs
index c64bdf6bc5..59c6c55c22 100644
--- a/crates/ide-completion/src/completions/dot.rs
+++ b/crates/ide-completion/src/completions/dot.rs
@@ -1,9 +1,9 @@
//! Completes references after dot (fields and method calls).
-use std::ops::ControlFlow;
+use std::{collections::hash_map, ops::ControlFlow};
-use hir::{Complete, Function, HasContainer, ItemContainer, MethodCandidateCallback};
-use ide_db::FxHashSet;
+use hir::{Complete, Function, HasContainer, ItemContainer, MethodCandidateCallback, Name};
+use ide_db::{FxHashMap, FxHashSet};
use itertools::Either;
use syntax::SmolStr;
@@ -239,6 +239,9 @@ fn complete_methods(
// 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<Function>,
+ // However, duplicate inherent methods is usually meaningless
+ // https://github.com/rust-lang/rust-analyzer/issues/20773#issuecomment-4302781553
+ seen_inherent_methods: FxHashMap<Name, Function>,
}
impl<F> MethodCandidateCallback for Callback<'_, '_, F>
@@ -249,7 +252,21 @@ fn complete_methods(
// `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) {
- (self.f)(func);
+ let same_name = self.seen_inherent_methods.entry(func.name(self.ctx.db));
+ let do_complete = match &same_name {
+ hash_map::Entry::Vacant(_) => true,
+ hash_map::Entry::Occupied(same_func) => {
+ match self.ctx.is_visible(same_func.get()) {
+ crate::context::Visible::Yes => false,
+ crate::context::Visible::Editable => true,
+ crate::context::Visible::No => true,
+ }
+ }
+ };
+ if do_complete {
+ same_name.insert_entry(func);
+ (self.f)(func);
+ }
}
ControlFlow::Continue(())
}
@@ -277,7 +294,12 @@ fn complete_methods(
&ctx.scope,
traits_in_scope,
None,
- Callback { ctx, f, seen_methods: FxHashSet::default() },
+ Callback {
+ ctx,
+ f,
+ seen_methods: FxHashSet::default(),
+ seen_inherent_methods: FxHashMap::default(),
+ },
);
}
@@ -870,6 +892,86 @@ fn test(a: A) {
}
#[test]
+ fn test_inherent_method_no_same_name() {
+ check_no_kw(
+ r#"
+//- minicore: deref
+struct A {}
+struct B {}
+impl core::ops::Deref for A {
+ type Target = B;
+ fn deref(&self) -> &Self::Target { loop {} }
+}
+trait Foo { fn foo(&self) -> u32 {} }
+impl Foo for A {}
+impl Foo for B {}
+impl A { fn foo(&self) -> u8 {} }
+impl B { fn foo(&self) -> u16 {} }
+fn test(a: A) {
+ a.$0
+}
+"#,
+ expect![[r#"
+ me deref() (use core::ops::Deref) fn(&self) -> &<Self as Deref>::Target
+ me foo() fn(&self) -> u8
+ me foo() (as Foo) fn(&self) -> u32
+ "#]],
+ );
+
+ check_no_kw(
+ r#"
+//- minicore: deref
+//- /dep.rs crate:dep
+pub struct A {}
+pub struct B {}
+pub struct C {}
+pub struct D {}
+pub struct E {}
+pub struct F {}
+impl core::ops::Deref for A {
+ type Target = B;
+ fn deref(&self) -> &Self::Target { loop {} }
+}
+impl core::ops::Deref for B {
+ type Target = C;
+ fn deref(&self) -> &Self::Target { loop {} }
+}
+impl core::ops::Deref for C {
+ type Target = D;
+ fn deref(&self) -> &Self::Target { loop {} }
+}
+impl core::ops::Deref for D {
+ type Target = E;
+ fn deref(&self) -> &Self::Target { loop {} }
+}
+impl core::ops::Deref for E {
+ type Target = F;
+ fn deref(&self) -> &Self::Target { loop {} }
+}
+pub trait Foo { fn foo(&self) -> u32 {} }
+impl Foo for A {}
+impl Foo for B {}
+impl A { fn foo(&self) -> u8 {} }
+impl B { pub fn foo(&self) -> u16 {} }
+impl C { fn foo(&self) -> i8 {} }
+impl D { fn foo(&self) -> i16 {} }
+impl E { pub fn foo(&self) -> i32 {} }
+impl F { pub fn foo(&self) -> f32 {} }
+//- /main.rs crate:main deps:dep
+use dep::*;
+fn test(a: A) {
+ a.$0
+}
+"#,
+ expect![[r#"
+ me deref() (use core::ops::Deref) fn(&self) -> &<Self as Deref>::Target
+ me foo() fn(&self) -> u16
+ me foo() (as Foo) fn(&self) -> u32
+ "#]],
+ );
+ }
+
+ #[test]
fn test_completion_works_in_consts() {
check_no_kw(
r#"
diff --git a/crates/ide-completion/src/tests/flyimport.rs b/crates/ide-completion/src/tests/flyimport.rs
index 231623a42f..45db8ecfc6 100644
--- a/crates/ide-completion/src/tests/flyimport.rs
+++ b/crates/ide-completion/src/tests/flyimport.rs
@@ -781,9 +781,9 @@ fn main() {
}
"#,
expect![[r#"
- me random_method(…) (use dep::test_mod::TestTrait) fn(&self) DEPRECATED
ct SPECIAL_CONST (use dep::test_mod::TestTrait) u8 DEPRECATED
fn weird_function() (use dep::test_mod::TestTrait) fn() DEPRECATED
+ me random_method(…) (use dep::test_mod::TestTrait) fn(&self) DEPRECATED
"#]],
);
}