mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-11-03 05:13:35 +00:00
Merge pull request #18179 from ChayimFriedman2/omit-trait-completion
feat: Allow excluding specific traits from completion
This commit is contained in:
commit
7e639ee3dd
20 changed files with 1028 additions and 100 deletions
|
|
@ -258,7 +258,7 @@ fn resolve_impl_trait_item(
|
|||
&traits_in_scope,
|
||||
method_resolution::VisibleFromModule::None,
|
||||
Some(name),
|
||||
&mut |assoc_item_id| {
|
||||
&mut |_, assoc_item_id: AssocItemId, _| {
|
||||
// If two traits in scope define the same item, Rustdoc links to no specific trait (for
|
||||
// instance, given two methods `a`, Rustdoc simply links to `method.a` with no
|
||||
// disambiguation) so we just pick the first one we find as well.
|
||||
|
|
|
|||
|
|
@ -5223,21 +5223,18 @@ impl Type {
|
|||
) -> Option<T> {
|
||||
let _p = tracing::info_span!("iterate_method_candidates_with_traits").entered();
|
||||
let mut slot = None;
|
||||
|
||||
self.iterate_method_candidates_dyn(
|
||||
self.iterate_method_candidates_split_inherent(
|
||||
db,
|
||||
scope,
|
||||
traits_in_scope,
|
||||
with_local_impls,
|
||||
name,
|
||||
&mut |assoc_item_id| {
|
||||
if let AssocItemId::FunctionId(func) = assoc_item_id {
|
||||
if let Some(res) = callback(func.into()) {
|
||||
slot = Some(res);
|
||||
return ControlFlow::Break(());
|
||||
}
|
||||
|f| match callback(f) {
|
||||
it @ Some(_) => {
|
||||
slot = it;
|
||||
ControlFlow::Break(())
|
||||
}
|
||||
ControlFlow::Continue(())
|
||||
None => ControlFlow::Continue(()),
|
||||
},
|
||||
);
|
||||
slot
|
||||
|
|
@ -5261,15 +5258,49 @@ impl Type {
|
|||
)
|
||||
}
|
||||
|
||||
fn iterate_method_candidates_dyn(
|
||||
/// Allows you to treat inherent and non-inherent methods differently.
|
||||
///
|
||||
/// Note that inherent methods may actually be trait methods! For example, in `dyn Trait`, the trait's methods
|
||||
/// are considered inherent methods.
|
||||
pub fn iterate_method_candidates_split_inherent(
|
||||
&self,
|
||||
db: &dyn HirDatabase,
|
||||
scope: &SemanticsScope<'_>,
|
||||
traits_in_scope: &FxHashSet<TraitId>,
|
||||
with_local_impls: Option<Module>,
|
||||
name: Option<&Name>,
|
||||
callback: &mut dyn FnMut(AssocItemId) -> ControlFlow<()>,
|
||||
callback: impl MethodCandidateCallback,
|
||||
) {
|
||||
struct Callback<T>(T);
|
||||
|
||||
impl<T: MethodCandidateCallback> method_resolution::MethodCandidateCallback for Callback<T> {
|
||||
fn on_inherent_method(
|
||||
&mut self,
|
||||
_adjustments: method_resolution::ReceiverAdjustments,
|
||||
item: AssocItemId,
|
||||
_is_visible: bool,
|
||||
) -> ControlFlow<()> {
|
||||
if let AssocItemId::FunctionId(func) = item {
|
||||
self.0.on_inherent_method(func.into())
|
||||
} else {
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
}
|
||||
|
||||
fn on_trait_method(
|
||||
&mut self,
|
||||
_adjustments: method_resolution::ReceiverAdjustments,
|
||||
item: AssocItemId,
|
||||
_is_visible: bool,
|
||||
) -> ControlFlow<()> {
|
||||
if let AssocItemId::FunctionId(func) = item {
|
||||
self.0.on_trait_method(func.into())
|
||||
} else {
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let _p = tracing::info_span!(
|
||||
"iterate_method_candidates_dyn",
|
||||
with_local_impls = traits_in_scope.len(),
|
||||
|
|
@ -5294,7 +5325,7 @@ impl Type {
|
|||
with_local_impls.and_then(|b| b.id.containing_block()).into(),
|
||||
name,
|
||||
method_resolution::LookupMode::MethodCall,
|
||||
&mut |_adj, id, _| callback(id),
|
||||
&mut Callback(callback),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -5310,33 +5341,61 @@ impl Type {
|
|||
) -> Option<T> {
|
||||
let _p = tracing::info_span!("iterate_path_candidates").entered();
|
||||
let mut slot = None;
|
||||
self.iterate_path_candidates_dyn(
|
||||
|
||||
self.iterate_path_candidates_split_inherent(
|
||||
db,
|
||||
scope,
|
||||
traits_in_scope,
|
||||
with_local_impls,
|
||||
name,
|
||||
&mut |assoc_item_id| {
|
||||
if let Some(res) = callback(assoc_item_id.into()) {
|
||||
slot = Some(res);
|
||||
return ControlFlow::Break(());
|
||||
|item| match callback(item) {
|
||||
it @ Some(_) => {
|
||||
slot = it;
|
||||
ControlFlow::Break(())
|
||||
}
|
||||
ControlFlow::Continue(())
|
||||
None => ControlFlow::Continue(()),
|
||||
},
|
||||
);
|
||||
slot
|
||||
}
|
||||
|
||||
/// Iterates over inherent methods.
|
||||
///
|
||||
/// In some circumstances, inherent methods methods may actually be trait methods!
|
||||
/// For example, when `dyn Trait` is a receiver, _trait_'s methods would be considered
|
||||
/// to be inherent methods.
|
||||
#[tracing::instrument(skip_all, fields(name = ?name))]
|
||||
fn iterate_path_candidates_dyn(
|
||||
pub fn iterate_path_candidates_split_inherent(
|
||||
&self,
|
||||
db: &dyn HirDatabase,
|
||||
scope: &SemanticsScope<'_>,
|
||||
traits_in_scope: &FxHashSet<TraitId>,
|
||||
with_local_impls: Option<Module>,
|
||||
name: Option<&Name>,
|
||||
callback: &mut dyn FnMut(AssocItemId) -> ControlFlow<()>,
|
||||
callback: impl PathCandidateCallback,
|
||||
) {
|
||||
struct Callback<T>(T);
|
||||
|
||||
impl<T: PathCandidateCallback> method_resolution::MethodCandidateCallback for Callback<T> {
|
||||
fn on_inherent_method(
|
||||
&mut self,
|
||||
_adjustments: method_resolution::ReceiverAdjustments,
|
||||
item: AssocItemId,
|
||||
_is_visible: bool,
|
||||
) -> ControlFlow<()> {
|
||||
self.0.on_inherent_item(item.into())
|
||||
}
|
||||
|
||||
fn on_trait_method(
|
||||
&mut self,
|
||||
_adjustments: method_resolution::ReceiverAdjustments,
|
||||
item: AssocItemId,
|
||||
_is_visible: bool,
|
||||
) -> ControlFlow<()> {
|
||||
self.0.on_trait_item(item.into())
|
||||
}
|
||||
}
|
||||
|
||||
let canonical = hir_ty::replace_errors_with_variables(&self.ty);
|
||||
|
||||
let krate = scope.krate();
|
||||
|
|
@ -5352,7 +5411,7 @@ impl Type {
|
|||
traits_in_scope,
|
||||
with_local_impls.and_then(|b| b.id.containing_block()).into(),
|
||||
name,
|
||||
callback,
|
||||
&mut Callback(callback),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -6060,3 +6119,41 @@ fn push_ty_diagnostics(
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub trait MethodCandidateCallback {
|
||||
fn on_inherent_method(&mut self, f: Function) -> ControlFlow<()>;
|
||||
|
||||
fn on_trait_method(&mut self, f: Function) -> ControlFlow<()>;
|
||||
}
|
||||
|
||||
impl<F> MethodCandidateCallback for F
|
||||
where
|
||||
F: FnMut(Function) -> ControlFlow<()>,
|
||||
{
|
||||
fn on_inherent_method(&mut self, f: Function) -> ControlFlow<()> {
|
||||
self(f)
|
||||
}
|
||||
|
||||
fn on_trait_method(&mut self, f: Function) -> ControlFlow<()> {
|
||||
self(f)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait PathCandidateCallback {
|
||||
fn on_inherent_item(&mut self, item: AssocItem) -> ControlFlow<()>;
|
||||
|
||||
fn on_trait_item(&mut self, item: AssocItem) -> ControlFlow<()>;
|
||||
}
|
||||
|
||||
impl<F> PathCandidateCallback for F
|
||||
where
|
||||
F: FnMut(AssocItem) -> ControlFlow<()>,
|
||||
{
|
||||
fn on_inherent_item(&mut self, item: AssocItem) -> ControlFlow<()> {
|
||||
self(item)
|
||||
}
|
||||
|
||||
fn on_trait_item(&mut self, item: AssocItem) -> ControlFlow<()> {
|
||||
self(item)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2060,6 +2060,11 @@ impl SemanticsScope<'_> {
|
|||
)
|
||||
}
|
||||
|
||||
pub fn resolve_mod_path(&self, path: &ModPath) -> impl Iterator<Item = ItemInNs> {
|
||||
let items = self.resolver.resolve_module_path_in_items(self.db.upcast(), path);
|
||||
items.iter_items().map(|(item, _)| item.into())
|
||||
}
|
||||
|
||||
/// Iterates over associated types that may be specified after the given path (using
|
||||
/// `Ty::Assoc` syntax).
|
||||
pub fn assoc_type_shorthand_candidates<R>(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue