Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions crates/hir-ty/src/method_resolution/probe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@

use std::{cell::RefCell, convert::Infallible, ops::ControlFlow};

use base_db::FxIndexMap;
use hir_def::{
AssocItemId, FunctionId, GenericParamId, ImplId, ItemContainerId, TraitId,
hir::generics::GenericParams,
signatures::{FunctionSignature, TraitFlags, TraitSignature},
};
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},
Expand Down Expand Up @@ -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,
}

Expand Down
112 changes: 107 additions & 5 deletions crates/ide-completion/src/completions/dot.rs
Original file line number Diff line number Diff line change
@@ -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;

Expand Down Expand Up @@ -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>
Expand All @@ -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(())
}
Expand Down Expand Up @@ -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(),
},
);
}

Expand Down Expand Up @@ -869,6 +891,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(
Expand Down
2 changes: 1 addition & 1 deletion crates/ide-completion/src/tests/flyimport.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
"#]],
);
}
Expand Down
Loading