Skip to content

Commit 39d3441

Browse files
Allow excluding specific traits from completion
To be accurate, only their methods are excluded, the trait themselves are still available. I also excluded a bunch of std traits by default. Some less opinionated, like `AsRef`, which should never be used directly except in generic scenarios (and won't be excluded there), some more opinionated, like the ops traits, which I know some users sometimes want to use directly. Either way it's configurable. It should be pretty easy to extend support to excluding only specific methods, but I didn't do that currently. Traits configured to be excluded are resolved in each completion request from scratch. If this proves too expensive, it is easy enough to cache them in the DB.
1 parent 2f55a91 commit 39d3441

File tree

18 files changed

+1012
-81
lines changed

18 files changed

+1012
-81
lines changed

crates/hir-def/src/item_scope.rs

+7
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,13 @@ impl ItemScope {
342342
.chain(self.unnamed_trait_imports.keys().copied())
343343
}
344344

345+
pub fn trait_by_name(&self, name: &Name) -> Option<TraitId> {
346+
self.types.get(name).and_then(|(def, _, _)| match def {
347+
ModuleDefId::TraitId(it) => Some(*it),
348+
_ => None,
349+
})
350+
}
351+
345352
pub(crate) fn resolutions(&self) -> impl Iterator<Item = (Option<Name>, PerNs)> + '_ {
346353
self.entries().map(|(name, res)| (Some(name.clone()), res)).chain(
347354
self.unnamed_trait_imports.iter().map(|(tr, (vis, i))| {

crates/hir-ty/src/method_resolution.rs

+58-11
Original file line numberDiff line numberDiff line change
@@ -914,7 +914,7 @@ pub fn iterate_path_candidates(
914914
traits_in_scope: &FxHashSet<TraitId>,
915915
visible_from_module: VisibleFromModule,
916916
name: Option<&Name>,
917-
callback: &mut dyn FnMut(AssocItemId) -> ControlFlow<()>,
917+
callback: &mut dyn MethodCandidateCallback,
918918
) -> ControlFlow<()> {
919919
iterate_method_candidates_dyn(
920920
ty,
@@ -925,7 +925,7 @@ pub fn iterate_path_candidates(
925925
name,
926926
LookupMode::Path,
927927
// the adjustments are not relevant for path lookup
928-
&mut |_, id, _| callback(id),
928+
callback,
929929
)
930930
}
931931

@@ -937,7 +937,7 @@ pub fn iterate_method_candidates_dyn(
937937
visible_from_module: VisibleFromModule,
938938
name: Option<&Name>,
939939
mode: LookupMode,
940-
callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId, bool) -> ControlFlow<()>,
940+
callback: &mut dyn MethodCandidateCallback,
941941
) -> ControlFlow<()> {
942942
let _p = tracing::info_span!(
943943
"iterate_method_candidates_dyn",
@@ -1007,7 +1007,7 @@ fn iterate_method_candidates_with_autoref(
10071007
traits_in_scope: &FxHashSet<TraitId>,
10081008
visible_from_module: VisibleFromModule,
10091009
name: Option<&Name>,
1010-
mut callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId, bool) -> ControlFlow<()>,
1010+
callback: &mut dyn MethodCandidateCallback,
10111011
) -> ControlFlow<()> {
10121012
if receiver_ty.value.is_general_var(Interner, &receiver_ty.binders) {
10131013
// don't try to resolve methods on unknown types
@@ -1022,7 +1022,7 @@ fn iterate_method_candidates_with_autoref(
10221022
traits_in_scope,
10231023
visible_from_module,
10241024
name,
1025-
&mut callback,
1025+
callback,
10261026
)
10271027
};
10281028

@@ -1052,6 +1052,45 @@ fn iterate_method_candidates_with_autoref(
10521052
iterate_method_candidates_by_receiver(ref_muted, first_adjustment.with_autoref(Mutability::Mut))
10531053
}
10541054

1055+
pub trait MethodCandidateCallback {
1056+
fn on_inherent_method(
1057+
&mut self,
1058+
adjustments: ReceiverAdjustments,
1059+
item: AssocItemId,
1060+
is_visible: bool,
1061+
) -> ControlFlow<()>;
1062+
1063+
fn on_trait_method(
1064+
&mut self,
1065+
adjustments: ReceiverAdjustments,
1066+
item: AssocItemId,
1067+
is_visible: bool,
1068+
) -> ControlFlow<()>;
1069+
}
1070+
1071+
impl<F> MethodCandidateCallback for F
1072+
where
1073+
F: FnMut(ReceiverAdjustments, AssocItemId, bool) -> ControlFlow<()>,
1074+
{
1075+
fn on_inherent_method(
1076+
&mut self,
1077+
adjustments: ReceiverAdjustments,
1078+
item: AssocItemId,
1079+
is_visible: bool,
1080+
) -> ControlFlow<()> {
1081+
self(adjustments, item, is_visible)
1082+
}
1083+
1084+
fn on_trait_method(
1085+
&mut self,
1086+
adjustments: ReceiverAdjustments,
1087+
item: AssocItemId,
1088+
is_visible: bool,
1089+
) -> ControlFlow<()> {
1090+
self(adjustments, item, is_visible)
1091+
}
1092+
}
1093+
10551094
#[tracing::instrument(skip_all, fields(name = ?name))]
10561095
fn iterate_method_candidates_by_receiver(
10571096
table: &mut InferenceTable<'_>,
@@ -1060,7 +1099,7 @@ fn iterate_method_candidates_by_receiver(
10601099
traits_in_scope: &FxHashSet<TraitId>,
10611100
visible_from_module: VisibleFromModule,
10621101
name: Option<&Name>,
1063-
mut callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId, bool) -> ControlFlow<()>,
1102+
callback: &mut dyn MethodCandidateCallback,
10641103
) -> ControlFlow<()> {
10651104
let receiver_ty = table.instantiate_canonical(receiver_ty);
10661105
// We're looking for methods with *receiver* type receiver_ty. These could
@@ -1076,7 +1115,9 @@ fn iterate_method_candidates_by_receiver(
10761115
Some(&receiver_ty),
10771116
Some(receiver_adjustments.clone()),
10781117
visible_from_module,
1079-
&mut callback,
1118+
&mut |adjustments, item, is_visible| {
1119+
callback.on_inherent_method(adjustments, item, is_visible)
1120+
},
10801121
)?
10811122
}
10821123
ControlFlow::Continue(())
@@ -1096,7 +1137,9 @@ fn iterate_method_candidates_by_receiver(
10961137
name,
10971138
Some(&receiver_ty),
10981139
Some(receiver_adjustments.clone()),
1099-
&mut callback,
1140+
&mut |adjustments, item, is_visible| {
1141+
callback.on_trait_method(adjustments, item, is_visible)
1142+
},
11001143
)?
11011144
}
11021145
ControlFlow::Continue(())
@@ -1111,7 +1154,7 @@ fn iterate_method_candidates_for_self_ty(
11111154
traits_in_scope: &FxHashSet<TraitId>,
11121155
visible_from_module: VisibleFromModule,
11131156
name: Option<&Name>,
1114-
mut callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId, bool) -> ControlFlow<()>,
1157+
callback: &mut dyn MethodCandidateCallback,
11151158
) -> ControlFlow<()> {
11161159
let mut table = InferenceTable::new(db, env);
11171160
let self_ty = table.instantiate_canonical(self_ty.clone());
@@ -1122,7 +1165,9 @@ fn iterate_method_candidates_for_self_ty(
11221165
None,
11231166
None,
11241167
visible_from_module,
1125-
&mut callback,
1168+
&mut |adjustments, item, is_visible| {
1169+
callback.on_inherent_method(adjustments, item, is_visible)
1170+
},
11261171
)?;
11271172
iterate_trait_method_candidates(
11281173
&self_ty,
@@ -1131,7 +1176,9 @@ fn iterate_method_candidates_for_self_ty(
11311176
name,
11321177
None,
11331178
None,
1134-
callback,
1179+
&mut |adjustments, item, is_visible| {
1180+
callback.on_trait_method(adjustments, item, is_visible)
1181+
},
11351182
)
11361183
}
11371184

crates/hir/src/attrs.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ fn resolve_impl_trait_item(
258258
&traits_in_scope,
259259
method_resolution::VisibleFromModule::None,
260260
Some(name),
261-
&mut |assoc_item_id| {
261+
&mut |_, assoc_item_id: AssocItemId, _| {
262262
// If two traits in scope define the same item, Rustdoc links to no specific trait (for
263263
// instance, given two methods `a`, Rustdoc simply links to `method.a` with no
264264
// disambiguation) so we just pick the first one we find as well.

0 commit comments

Comments
 (0)