Unnamed repository; edit this file 'description' to name the repository.
Auto merge of #12168 - Veykril:completion-rev, r=Veykril
internal: Remove unqualified_path completions module
bors 2022-05-06
parent cc9ae2b · parent 0c4e23b · commit dd3f5e0
-rw-r--r--crates/hir/src/lib.rs2
-rw-r--r--crates/hir/src/semantics.rs8
-rw-r--r--crates/ide-assists/src/handlers/convert_iter_for_each_to_for.rs3
-rw-r--r--crates/ide-assists/src/handlers/generate_is_empty_from_len.rs12
-rw-r--r--crates/ide-completion/src/completions.rs1
-rw-r--r--crates/ide-completion/src/completions/dot.rs11
-rw-r--r--crates/ide-completion/src/completions/expr.rs145
-rw-r--r--crates/ide-completion/src/completions/pattern.rs3
-rw-r--r--crates/ide-completion/src/completions/qualified_path.rs670
-rw-r--r--crates/ide-completion/src/completions/type.rs155
-rw-r--r--crates/ide-completion/src/completions/use_.rs2
-rw-r--r--crates/ide-completion/src/context.rs31
-rw-r--r--crates/ide-completion/src/lib.rs1
-rw-r--r--crates/ide-completion/src/tests/special.rs455
-rw-r--r--crates/ide-ssr/src/resolving.rs2
15 files changed, 769 insertions, 732 deletions
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index c91fbce5ea..8b537a1d38 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -88,7 +88,7 @@ pub use crate::{
UnresolvedModule, UnresolvedProcMacro,
},
has_source::HasSource,
- semantics::{PathResolution, Semantics, SemanticsScope, TypeInfo},
+ semantics::{PathResolution, Semantics, SemanticsScope, TypeInfo, VisibleTraits},
};
// Be careful with these re-exports.
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs
index 8b565ef1fa..d887dae99c 100644
--- a/crates/hir/src/semantics.rs
+++ b/crates/hir/src/semantics.rs
@@ -1370,10 +1370,10 @@ impl<'a> SemanticsScope<'a> {
&self.resolver
}
- /// Note: `FxHashSet<TraitId>` should be treated as an opaque type, passed into `Type
- pub fn visible_traits(&self) -> FxHashSet<TraitId> {
+ /// Note: `VisibleTraits` should be treated as an opaque type, passed into `Type
+ pub fn visible_traits(&self) -> VisibleTraits {
let resolver = &self.resolver;
- resolver.traits_in_scope(self.db.upcast())
+ VisibleTraits(resolver.traits_in_scope(self.db.upcast()))
}
pub fn process_all_names(&self, f: &mut dyn FnMut(Name, ScopeDef)) {
@@ -1424,3 +1424,5 @@ impl<'a> SemanticsScope<'a> {
)
}
}
+
+pub struct VisibleTraits(pub FxHashSet<TraitId>);
diff --git a/crates/ide-assists/src/handlers/convert_iter_for_each_to_for.rs b/crates/ide-assists/src/handlers/convert_iter_for_each_to_for.rs
index 711b914561..82a67fb51d 100644
--- a/crates/ide-assists/src/handlers/convert_iter_for_each_to_for.rs
+++ b/crates/ide-assists/src/handlers/convert_iter_for_each_to_for.rs
@@ -148,14 +148,13 @@ fn is_ref_and_impls_iter_method(
let ty = sema.type_of_expr(&expr_behind_ref)?.adjusted();
let scope = sema.scope(iterable.syntax())?;
let krate = scope.krate();
- let traits_in_scope = scope.visible_traits();
let iter_trait = FamousDefs(sema, krate).core_iter_Iterator()?;
let has_wanted_method = ty
.iterate_method_candidates(
sema.db,
&scope,
- &traits_in_scope,
+ &scope.visible_traits().0,
None,
Some(&wanted_method),
|func| {
diff --git a/crates/ide-assists/src/handlers/generate_is_empty_from_len.rs b/crates/ide-assists/src/handlers/generate_is_empty_from_len.rs
index 1ad1cea43f..062b12a50b 100644
--- a/crates/ide-assists/src/handlers/generate_is_empty_from_len.rs
+++ b/crates/ide-assists/src/handlers/generate_is_empty_from_len.rs
@@ -95,10 +95,14 @@ fn get_impl_method(
let scope = ctx.sema.scope(impl_.syntax())?;
let ty = impl_def.self_ty(db);
- let traits_in_scope = scope.visible_traits();
- ty.iterate_method_candidates(db, &scope, &traits_in_scope, None, Some(fn_name), |func| {
- Some(func)
- })
+ ty.iterate_method_candidates(
+ db,
+ &scope,
+ &scope.visible_traits().0,
+ None,
+ Some(fn_name),
+ |func| Some(func),
+ )
}
#[cfg(test)]
diff --git a/crates/ide-completion/src/completions.rs b/crates/ide-completion/src/completions.rs
index b22124cc69..687a598bac 100644
--- a/crates/ide-completion/src/completions.rs
+++ b/crates/ide-completion/src/completions.rs
@@ -13,7 +13,6 @@ pub(crate) mod lifetime;
pub(crate) mod mod_;
pub(crate) mod pattern;
pub(crate) mod postfix;
-pub(crate) mod qualified_path;
pub(crate) mod record;
pub(crate) mod snippet;
pub(crate) mod trait_impl;
diff --git a/crates/ide-completion/src/completions/dot.rs b/crates/ide-completion/src/completions/dot.rs
index c660e8f8fa..03d9d3fa87 100644
--- a/crates/ide-completion/src/completions/dot.rs
+++ b/crates/ide-completion/src/completions/dot.rs
@@ -78,18 +78,10 @@ fn complete_methods(
mut f: impl FnMut(hir::Function),
) {
let mut seen_methods = FxHashSet::default();
- let mut traits_in_scope = ctx.scope.visible_traits();
-
- // Remove drop from the environment as calling `Drop::drop` is not allowed
- if let Some(drop_trait) = ctx.famous_defs().core_ops_Drop() {
- cov_mark::hit!(dot_remove_drop_trait);
- traits_in_scope.remove(&drop_trait.into());
- }
-
receiver.iterate_method_candidates(
ctx.db,
&ctx.scope,
- &traits_in_scope,
+ &ctx.traits_in_scope().0,
Some(ctx.module),
None,
|func| {
@@ -758,7 +750,6 @@ fn main() {
#[test]
fn postfix_drop_completion() {
- cov_mark::check!(dot_remove_drop_trait);
cov_mark::check!(postfix_drop_completion);
check_edit(
"drop",
diff --git a/crates/ide-completion/src/completions/expr.rs b/crates/ide-completion/src/completions/expr.rs
index f9717f1c2c..fb9955c5e8 100644
--- a/crates/ide-completion/src/completions/expr.rs
+++ b/crates/ide-completion/src/completions/expr.rs
@@ -1,6 +1,7 @@
//! Completion of names from the current scope in expression position.
use hir::ScopeDef;
+use ide_db::FxHashSet;
use crate::{
context::{PathCompletionCtx, PathKind, PathQualifierCtx},
@@ -20,8 +21,129 @@ pub(crate) fn complete_expr_path(acc: &mut Completions, ctx: &CompletionContext)
_ => return,
};
+ let scope_def_applicable = |def| {
+ use hir::{GenericParam::*, ModuleDef::*};
+ match def {
+ ScopeDef::GenericParam(LifetimeParam(_)) | ScopeDef::Label(_) => false,
+ // Don't suggest attribute macros and derives.
+ ScopeDef::ModuleDef(Macro(mac)) => mac.is_fn_like(ctx.db),
+ _ => true,
+ }
+ };
+
match qualifier {
- Some(PathQualifierCtx { .. }) => return,
+ Some(PathQualifierCtx { is_infer_qualifier, resolution, .. }) => {
+ if *is_infer_qualifier {
+ ctx.traits_in_scope()
+ .0
+ .into_iter()
+ .flat_map(|it| hir::Trait::from(it).items(ctx.sema.db))
+ .for_each(|item| add_assoc_item(acc, ctx, item));
+ return;
+ }
+ let resolution = match resolution {
+ Some(it) => it,
+ None => return,
+ };
+ // Add associated types on type parameters and `Self`.
+ ctx.scope.assoc_type_shorthand_candidates(resolution, |_, alias| {
+ acc.add_type_alias(ctx, alias);
+ None::<()>
+ });
+ match resolution {
+ hir::PathResolution::Def(hir::ModuleDef::Module(module)) => {
+ let module_scope = module.scope(ctx.db, Some(ctx.module));
+ for (name, def) in module_scope {
+ if scope_def_applicable(def) {
+ acc.add_resolution(ctx, name, def);
+ }
+ }
+ }
+
+ hir::PathResolution::Def(
+ def @ (hir::ModuleDef::Adt(_)
+ | hir::ModuleDef::TypeAlias(_)
+ | hir::ModuleDef::BuiltinType(_)),
+ ) => {
+ if let &hir::ModuleDef::Adt(hir::Adt::Enum(e)) = def {
+ add_enum_variants(acc, ctx, e);
+ }
+ let ty = match def {
+ hir::ModuleDef::Adt(adt) => adt.ty(ctx.db),
+ hir::ModuleDef::TypeAlias(a) => {
+ let ty = a.ty(ctx.db);
+ if let Some(hir::Adt::Enum(e)) = ty.as_adt() {
+ cov_mark::hit!(completes_variant_through_alias);
+ add_enum_variants(acc, ctx, e);
+ }
+ ty
+ }
+ hir::ModuleDef::BuiltinType(builtin) => {
+ cov_mark::hit!(completes_primitive_assoc_const);
+ builtin.ty(ctx.db)
+ }
+ _ => unreachable!(),
+ };
+
+ // XXX: For parity with Rust bug #22519, this does not complete Ty::AssocType.
+ // (where AssocType is defined on a trait, not an inherent impl)
+
+ ty.iterate_path_candidates(
+ ctx.db,
+ &ctx.scope,
+ &ctx.traits_in_scope().0,
+ Some(ctx.module),
+ None,
+ |item| {
+ add_assoc_item(acc, ctx, item);
+ None::<()>
+ },
+ );
+
+ // Iterate assoc types separately
+ ty.iterate_assoc_items(ctx.db, ctx.krate, |item| {
+ if let hir::AssocItem::TypeAlias(ty) = item {
+ acc.add_type_alias(ctx, ty)
+ }
+ None::<()>
+ });
+ }
+ hir::PathResolution::Def(hir::ModuleDef::Trait(t)) => {
+ // Handles `Trait::assoc` as well as `<Ty as Trait>::assoc`.
+ for item in t.items(ctx.db) {
+ add_assoc_item(acc, ctx, item);
+ }
+ }
+ hir::PathResolution::TypeParam(_) | hir::PathResolution::SelfType(_) => {
+ let ty = match resolution {
+ hir::PathResolution::TypeParam(param) => param.ty(ctx.db),
+ hir::PathResolution::SelfType(impl_def) => impl_def.self_ty(ctx.db),
+ _ => return,
+ };
+
+ if let Some(hir::Adt::Enum(e)) = ty.as_adt() {
+ add_enum_variants(acc, ctx, e);
+ }
+ let mut seen = FxHashSet::default();
+ ty.iterate_path_candidates(
+ ctx.db,
+ &ctx.scope,
+ &ctx.traits_in_scope().0,
+ Some(ctx.module),
+ None,
+ |item| {
+ // We might iterate candidates of a trait multiple times here, so deduplicate
+ // them.
+ if seen.insert(item) {
+ add_assoc_item(acc, ctx, item);
+ }
+ None::<()>
+ },
+ );
+ }
+ _ => (),
+ }
+ }
None if is_absolute_path => acc.add_crate_roots(ctx),
None => {
acc.add_nameref_keywords_with_colon(ctx);
@@ -33,17 +155,22 @@ pub(crate) fn complete_expr_path(acc: &mut Completions, ctx: &CompletionContext)
});
}
ctx.process_all_names(&mut |name, def| {
- use hir::{GenericParam::*, ModuleDef::*};
- let add_resolution = match def {
- ScopeDef::GenericParam(LifetimeParam(_)) | ScopeDef::Label(_) => false,
- // Don't suggest attribute macros and derives.
- ScopeDef::ModuleDef(Macro(mac)) => mac.is_fn_like(ctx.db),
- _ => true,
- };
- if add_resolution {
+ if scope_def_applicable(def) {
acc.add_resolution(ctx, name, def);
}
});
}
}
}
+
+fn add_assoc_item(acc: &mut Completions, ctx: &CompletionContext, item: hir::AssocItem) {
+ match item {
+ hir::AssocItem::Function(func) => acc.add_function(ctx, func, None),
+ hir::AssocItem::Const(ct) => acc.add_const(ctx, ct),
+ hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty),
+ }
+}
+
+fn add_enum_variants(acc: &mut Completions, ctx: &CompletionContext, e: hir::Enum) {
+ e.variants(ctx.db).into_iter().for_each(|variant| acc.add_enum_variant(ctx, variant, None));
+}
diff --git a/crates/ide-completion/src/completions/pattern.rs b/crates/ide-completion/src/completions/pattern.rs
index a761eeebb2..963ee30959 100644
--- a/crates/ide-completion/src/completions/pattern.rs
+++ b/crates/ide-completion/src/completions/pattern.rs
@@ -163,12 +163,11 @@ fn pattern_path_completion(
_ => return,
};
- let traits_in_scope = ctx.scope.visible_traits();
let mut seen = FxHashSet::default();
ty.iterate_path_candidates(
ctx.db,
&ctx.scope,
- &traits_in_scope,
+ &ctx.scope.visible_traits().0,
Some(ctx.module),
None,
|item| {
diff --git a/crates/ide-completion/src/completions/qualified_path.rs b/crates/ide-completion/src/completions/qualified_path.rs
deleted file mode 100644
index d12f8490bd..0000000000
--- a/crates/ide-completion/src/completions/qualified_path.rs
+++ /dev/null
@@ -1,670 +0,0 @@
-//! Completion of paths, i.e. `some::prefix::$0`.
-
-use hir::{ScopeDef, Trait};
-use ide_db::FxHashSet;
-use syntax::ast;
-
-use crate::{
- context::{PathCompletionCtx, PathKind},
- CompletionContext, Completions,
-};
-
-pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionContext) {
- if ctx.is_path_disallowed() || ctx.has_unfinished_impl_or_trait_prev_sibling() {
- return;
- }
- if ctx.pattern_ctx.is_some() {
- return;
- }
- let (qualifier, kind) = match ctx.path_context {
- // let ... else, syntax would come in really handy here right now
- Some(PathCompletionCtx { qualifier: Some(ref qualifier), kind, .. }) => (qualifier, kind),
- _ => return,
- };
- let traits_in_scope = |ctx: &CompletionContext| {
- let mut traits_in_scope = ctx.scope.visible_traits();
- if let Some(drop) = ctx.famous_defs().core_ops_Drop() {
- traits_in_scope.remove(&drop.into());
- }
- traits_in_scope
- };
-
- // special case `<_>::$0` as this doesn't resolve to anything.
- if qualifier.path.qualifier().is_none() {
- if matches!(
- qualifier.path.segment().and_then(|it| it.kind()),
- Some(ast::PathSegmentKind::Type {
- type_ref: Some(ast::Type::InferType(_)),
- trait_ref: None,
- })
- ) {
- cov_mark::hit!(completion_type_anchor_empty);
- traits_in_scope(ctx)
- .into_iter()
- .flat_map(|it| Trait::from(it).items(ctx.sema.db))
- .for_each(|item| add_assoc_item(acc, ctx, item));
- return;
- }
- }
-
- let resolution = match &qualifier.resolution {
- Some(res) => res,
- None => return,
- };
-
- match kind {
- Some(
- PathKind::Pat
- | PathKind::Attr { .. }
- | PathKind::Vis { .. }
- | PathKind::Use
- | PathKind::Item
- | PathKind::Derive,
- ) => {
- return;
- }
- _ => {
- // Add associated types on type parameters and `Self`.
- ctx.scope.assoc_type_shorthand_candidates(resolution, |_, alias| {
- acc.add_type_alias(ctx, alias);
- None::<()>
- });
- }
- }
-
- match resolution {
- hir::PathResolution::Def(hir::ModuleDef::Module(module)) => {
- let module_scope = module.scope(ctx.db, Some(ctx.module));
- for (name, def) in module_scope {
- let add_resolution = match def {
- // Don't suggest attribute macros and derives.
- ScopeDef::ModuleDef(hir::ModuleDef::Macro(mac)) => mac.is_fn_like(ctx.db),
- // no values in type places
- ScopeDef::ModuleDef(
- hir::ModuleDef::Function(_)
- | hir::ModuleDef::Variant(_)
- | hir::ModuleDef::Static(_),
- )
- | ScopeDef::Local(_) => !ctx.expects_type(),
- // unless its a constant in a generic arg list position
- ScopeDef::ModuleDef(hir::ModuleDef::Const(_)) => {
- !ctx.expects_type() || ctx.expects_generic_arg()
- }
- _ => true,
- };
-
- if add_resolution {
- acc.add_resolution(ctx, name, def);
- }
- }
- }
- hir::PathResolution::Def(
- def @ (hir::ModuleDef::Adt(_)
- | hir::ModuleDef::TypeAlias(_)
- | hir::ModuleDef::BuiltinType(_)),
- ) => {
- if let &hir::ModuleDef::Adt(hir::Adt::Enum(e)) = def {
- add_enum_variants(acc, ctx, e);
- }
- let ty = match def {
- hir::ModuleDef::Adt(adt) => adt.ty(ctx.db),
- hir::ModuleDef::TypeAlias(a) => {
- let ty = a.ty(ctx.db);
- if let Some(hir::Adt::Enum(e)) = ty.as_adt() {
- cov_mark::hit!(completes_variant_through_alias);
- add_enum_variants(acc, ctx, e);
- }
- ty
- }
- hir::ModuleDef::BuiltinType(builtin) => {
- cov_mark::hit!(completes_primitive_assoc_const);
- builtin.ty(ctx.db)
- }
- _ => unreachable!(),
- };
-
- // XXX: For parity with Rust bug #22519, this does not complete Ty::AssocType.
- // (where AssocType is defined on a trait, not an inherent impl)
-
- let traits_in_scope = traits_in_scope(ctx);
- ty.iterate_path_candidates(
- ctx.db,
- &ctx.scope,
- &traits_in_scope,
- Some(ctx.module),
- None,
- |item| {
- add_assoc_item(acc, ctx, item);
- None::<()>
- },
- );
-
- // Iterate assoc types separately
- ty.iterate_assoc_items(ctx.db, ctx.krate, |item| {
- if let hir::AssocItem::TypeAlias(ty) = item {
- acc.add_type_alias(ctx, ty)
- }
- None::<()>
- });
- }
- hir::PathResolution::Def(hir::ModuleDef::Trait(t)) => {
- // Handles `Trait::assoc` as well as `<Ty as Trait>::assoc`.
- for item in t.items(ctx.db) {
- add_assoc_item(acc, ctx, item);
- }
- }
- hir::PathResolution::TypeParam(_) | hir::PathResolution::SelfType(_) => {
- let ty = match resolution {
- hir::PathResolution::TypeParam(param) => param.ty(ctx.db),
- hir::PathResolution::SelfType(impl_def) => impl_def.self_ty(ctx.db),
- _ => return,
- };
-
- if let Some(hir::Adt::Enum(e)) = ty.as_adt() {
- add_enum_variants(acc, ctx, e);
- }
- let traits_in_scope = traits_in_scope(ctx);
- let mut seen = FxHashSet::default();
- ty.iterate_path_candidates(
- ctx.db,
- &ctx.scope,
- &traits_in_scope,
- Some(ctx.module),
- None,
- |item| {
- // We might iterate candidates of a trait multiple times here, so deduplicate
- // them.
- if seen.insert(item) {
- add_assoc_item(acc, ctx, item);
- }
- None::<()>
- },
- );
- }
- _ => {}
- }
-}
-
-fn add_assoc_item(acc: &mut Completions, ctx: &CompletionContext, item: hir::AssocItem) {
- match item {
- hir::AssocItem::Function(func) if !ctx.expects_type() => acc.add_function(ctx, func, None),
- hir::AssocItem::Const(ct) if !ctx.expects_type() || ctx.expects_generic_arg() => {
- acc.add_const(ctx, ct)
- }
- hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty),
- _ => (),
- }
-}
-
-fn add_enum_variants(acc: &mut Completions, ctx: &CompletionContext, e: hir::Enum) {
- if ctx.expects_type() {
- return;
- }
- e.variants(ctx.db).into_iter().for_each(|variant| acc.add_enum_variant(ctx, variant, None));
-}
-
-#[cfg(test)]
-mod tests {
- use expect_test::{expect, Expect};
-
- use crate::tests::{check_edit, completion_list_no_kw};
-
- fn check(ra_fixture: &str, expect: Expect) {
- let actual = completion_list_no_kw(ra_fixture);
- expect.assert_eq(&actual);
- }
-
- #[test]
- fn associated_item_visibility() {
- check(
- r#"
-//- /lib.rs crate:lib new_source_root:library
-pub struct S;
-
-impl S {
- pub fn public_method() { }
- fn private_method() { }
- pub type PublicType = u32;
- type PrivateType = u32;
- pub const PUBLIC_CONST: u32 = 1;
- const PRIVATE_CONST: u32 = 1;
-}
-
-//- /main.rs crate:main deps:lib new_source_root:local
-fn foo() { let _ = lib::S::$0 }
-"#,
- expect![[r#"
- ct PUBLIC_CONST pub const PUBLIC_CONST: u32
- fn public_method() fn()
- ta PublicType pub type PublicType = u32
- "#]],
- );
- }
-
- #[test]
- fn completes_union_associated_method() {
- check(
- r#"
-union U {};
-impl U { fn m() { } }
-
-fn foo() { let _ = U::$0 }
-"#,
- expect![[r#"
- fn m() fn()
- "#]],
- );
- }
-
- #[test]
- fn completes_trait_associated_method_1() {
- check(
- r#"
-trait Trait { fn m(); }
-
-fn foo() { let _ = Trait::$0 }
-"#,
- expect![[r#"
- fn m() (as Trait) fn()
- "#]],
- );
- }
-
- #[test]
- fn completes_trait_associated_method_2() {
- check(
- r#"
-trait Trait { fn m(); }
-
-struct S;
-impl Trait for S {}
-
-fn foo() { let _ = S::$0 }
-"#,
- expect![[r#"
- fn m() (as Trait) fn()
- "#]],
- );
- }
-
- #[test]
- fn completes_trait_associated_method_3() {
- check(
- r#"
-trait Trait { fn m(); }
-
-struct S;
-impl Trait for S {}
-
-fn foo() { let _ = <S as Trait>::$0 }
-"#,
- expect![[r#"
- fn m() (as Trait) fn()
- "#]],
- );
- }
-
- #[test]
- fn completes_ty_param_assoc_ty() {
- check(
- r#"
-trait Super {
- type Ty;
- const CONST: u8;
- fn func() {}
- fn method(&self) {}
-}
-
-trait Sub: Super {
- type SubTy;
- const C2: ();
- fn subfunc() {}
- fn submethod(&self) {}
-}
-
-fn foo<T: Sub>() { T::$0 }
-"#,
- expect![[r#"
- ct C2 (as Sub) const C2: ()
- ct CONST (as Super) const CONST: u8
- fn func() (as Super) fn()
- fn subfunc() (as Sub) fn()
- ta SubTy (as Sub) type SubTy
- ta Ty (as Super) type Ty
- me method(…) (as Super) fn(&self)
- me submethod(…) (as Sub) fn(&self)
- "#]],
- );
- }
-
- #[test]
- fn completes_self_param_assoc_ty() {
- check(
- r#"
-trait Super {
- type Ty;
- const CONST: u8 = 0;
- fn func() {}
- fn method(&self) {}
-}
-
-trait Sub: Super {
- type SubTy;
- const C2: () = ();
- fn subfunc() {}
- fn submethod(&self) {}
-}
-
-struct Wrap<T>(T);
-impl<T> Super for Wrap<T> {}
-impl<T> Sub for Wrap<T> {
- fn subfunc() {
- // Should be able to assume `Self: Sub + Super`
- Self::$0
- }
-}
-"#,
- expect![[r#"
- ct C2 (as Sub) const C2: ()
- ct CONST (as Super) const CONST: u8
- fn func() (as Super) fn()
- fn subfunc() (as Sub) fn()
- ta SubTy (as Sub) type SubTy
- ta Ty (as Super) type Ty
- me method(…) (as Super) fn(&self)
- me submethod(…) (as Sub) fn(&self)
- "#]],
- );
- }
-
- #[test]
- fn completes_type_alias() {
- check(
- r#"
-struct S;
-impl S { fn foo() {} }
-type T = S;
-impl T { fn bar() {} }
-
-fn main() { T::$0; }
-"#,
- expect![[r#"
- fn bar() fn()
- fn foo() fn()
- "#]],
- );
- }
-
- #[test]
- fn completes_qualified_macros() {
- check(
- r#"
-#[macro_export]
-macro_rules! foo { () => {} }
-
-fn main() { let _ = crate::$0 }
-"#,
- expect![[r#"
- fn main() fn()
- ma foo!(…) macro_rules! foo
- "#]],
- );
- }
-
- #[test]
- fn does_not_complete_non_fn_macros() {
- check(
- r#"
-mod m {
- #[rustc_builtin_macro]
- pub macro Clone {}
-}
-
-fn f() {m::$0}
-"#,
- expect![[r#""#]],
- );
- check(
- r#"
-mod m {
- #[rustc_builtin_macro]
- pub macro bench {}
-}
-
-fn f() {m::$0}
-"#,
- expect![[r#""#]],
- );
- }
-
- #[test]
- fn completes_reexported_items_under_correct_name() {
- check(
- r#"
-fn foo() { self::m::$0 }
-
-mod m {
- pub use super::p::wrong_fn as right_fn;
- pub use super::p::WRONG_CONST as RIGHT_CONST;
- pub use super::p::WrongType as RightType;
-}
-mod p {
- fn wrong_fn() {}
- const WRONG_CONST: u32 = 1;
- struct WrongType {};
-}
-"#,
- expect![[r#"
- ct RIGHT_CONST
- fn right_fn() fn()
- st RightType
- "#]],
- );
-
- check_edit(
- "RightType",
- r#"
-fn foo() { self::m::$0 }
-
-mod m {
- pub use super::p::wrong_fn as right_fn;
- pub use super::p::WRONG_CONST as RIGHT_CONST;
- pub use super::p::WrongType as RightType;
-}
-mod p {
- fn wrong_fn() {}
- const WRONG_CONST: u32 = 1;
- struct WrongType {};
-}
-"#,
- r#"
-fn foo() { self::m::RightType }
-
-mod m {
- pub use super::p::wrong_fn as right_fn;
- pub use super::p::WRONG_CONST as RIGHT_CONST;
- pub use super::p::WrongType as RightType;
-}
-mod p {
- fn wrong_fn() {}
- const WRONG_CONST: u32 = 1;
- struct WrongType {};
-}
-"#,
- );
- }
-
- #[test]
- fn completes_in_simple_macro_call() {
- check(
- r#"
-macro_rules! m { ($e:expr) => { $e } }
-fn main() { m!(self::f$0); }
-fn foo() {}
-"#,
- expect![[r#"
- fn foo() fn()
- fn main() fn()
- "#]],
- );
- }
-
- #[test]
- fn function_mod_share_name() {
- check(
- r#"
-fn foo() { self::m::$0 }
-
-mod m {
- pub mod z {}
- pub fn z() {}
-}
-"#,
- expect![[r#"
- fn z() fn()
- md z
- "#]],
- );
- }
-
- #[test]
- fn completes_hashmap_new() {
- check(
- r#"
-struct RandomState;
-struct HashMap<K, V, S = RandomState> {}
-
-impl<K, V> HashMap<K, V, RandomState> {
- pub fn new() -> HashMap<K, V, RandomState> { }
-}
-fn foo() {
- HashMap::$0
-}
-"#,
- expect![[r#"
- fn new() fn() -> HashMap<K, V, RandomState>
- "#]],
- );
- }
-
- #[test]
- fn completes_variant_through_self() {
- check(
- r#"
-enum Foo {
- Bar,
- Baz,
-}
-
-impl Foo {
- fn foo(self) {
- Self::$0
- }
-}
-"#,
- expect![[r#"
- ev Bar Bar
- ev Baz Baz
- me foo(…) fn(self)
- "#]],
- );
- }
-
- #[test]
- fn completes_primitive_assoc_const() {
- cov_mark::check!(completes_primitive_assoc_const);
- check(
- r#"
-//- /lib.rs crate:lib deps:core
-fn f() {
- u8::$0
-}
-
-//- /core.rs crate:core
-#[lang = "u8"]
-impl u8 {
- pub const MAX: Self = 255;
-
- pub fn func(self) {}
-}
-"#,
- expect![[r#"
- ct MAX pub const MAX: Self
- me func(…) fn(self)
- "#]],
- );
- }
-
- #[test]
- fn completes_variant_through_alias() {
- cov_mark::check!(completes_variant_through_alias);
- check(
- r#"
-enum Foo {
- Bar
-}
-type Foo2 = Foo;
-fn main() {
- Foo2::$0
-}
-"#,
- expect![[r#"
- ev Bar Bar
- "#]],
- );
- }
-
- #[test]
- fn respects_doc_hidden() {
- cov_mark::check!(qualified_path_doc_hidden);
- check(
- r#"
-//- /lib.rs crate:lib deps:dep
-fn f() {
- dep::$0
-}
-
-//- /dep.rs crate:dep
-#[doc(hidden)]
-#[macro_export]
-macro_rules! m {
- () => {}
-}
-
-#[doc(hidden)]
-pub fn f() {}
-
-#[doc(hidden)]
-pub struct S;
-
-#[doc(hidden)]
-pub mod m {}
- "#,
- expect![[r#""#]],
- )
- }
-
- #[test]
- fn type_anchor_empty() {
- cov_mark::check!(completion_type_anchor_empty);
- check(
- r#"
-trait Foo {
- fn foo() -> Self;
-}
-struct Bar;
-impl Foo for Bar {
- fn foo() -> {
- Bar
- }
-}
-fn bar() -> Bar {
- <_>::$0
-}
-"#,
- expect![[r#"
- fn foo() (as Foo) fn() -> Self
- "#]],
- )
- }
-}
diff --git a/crates/ide-completion/src/completions/type.rs b/crates/ide-completion/src/completions/type.rs
index 4d0e2fb59a..64c3bd3fdf 100644
--- a/crates/ide-completion/src/completions/type.rs
+++ b/crates/ide-completion/src/completions/type.rs
@@ -1,6 +1,7 @@
//! Completion of names from the current scope in type position.
use hir::ScopeDef;
+use ide_db::FxHashSet;
use syntax::{ast, AstNode};
use crate::{
@@ -22,8 +23,126 @@ pub(crate) fn complete_type_path(acc: &mut Completions, ctx: &CompletionContext)
_ => return,
};
+ let scope_def_applicable = |def| {
+ use hir::{GenericParam::*, ModuleDef::*};
+ match def {
+ ScopeDef::GenericParam(LifetimeParam(_)) | ScopeDef::Label(_) => false,
+ // no values in type places
+ ScopeDef::ModuleDef(Function(_) | Variant(_) | Static(_)) | ScopeDef::Local(_) => false,
+ // unless its a constant in a generic arg list position
+ ScopeDef::ModuleDef(Const(_)) | ScopeDef::GenericParam(ConstParam(_)) => {
+ ctx.expects_generic_arg()
+ }
+ ScopeDef::ImplSelfType(_) => {
+ !ctx.previous_token_is(syntax::T![impl]) && !ctx.previous_token_is(syntax::T![for])
+ }
+ // Don't suggest attribute macros and derives.
+ ScopeDef::ModuleDef(Macro(mac)) => mac.is_fn_like(ctx.db),
+ // Type things are fine
+ ScopeDef::ModuleDef(BuiltinType(_) | Adt(_) | Module(_) | Trait(_) | TypeAlias(_))
+ | ScopeDef::AdtSelfType(_)
+ | ScopeDef::Unknown
+ | ScopeDef::GenericParam(TypeParam(_)) => true,
+ }
+ };
+
match qualifier {
- Some(PathQualifierCtx { .. }) => return,
+ Some(PathQualifierCtx { is_infer_qualifier, resolution, .. }) => {
+ if *is_infer_qualifier {
+ ctx.traits_in_scope()
+ .0
+ .into_iter()
+ .flat_map(|it| hir::Trait::from(it).items(ctx.sema.db))
+ .for_each(|item| add_assoc_item(acc, ctx, item));
+ return;
+ }
+ let resolution = match resolution {
+ Some(it) => it,
+ None => return,
+ };
+ // Add associated types on type parameters and `Self`.
+ ctx.scope.assoc_type_shorthand_candidates(resolution, |_, alias| {
+ acc.add_type_alias(ctx, alias);
+ None::<()>
+ });
+
+ match resolution {
+ hir::PathResolution::Def(hir::ModuleDef::Module(module)) => {
+ let module_scope = module.scope(ctx.db, Some(ctx.module));
+ for (name, def) in module_scope {
+ if scope_def_applicable(def) {
+ acc.add_resolution(ctx, name, def);
+ }
+ }
+ }
+ hir::PathResolution::Def(
+ def @ (hir::ModuleDef::Adt(_)
+ | hir::ModuleDef::TypeAlias(_)
+ | hir::ModuleDef::BuiltinType(_)),
+ ) => {
+ let ty = match def {
+ hir::ModuleDef::Adt(adt) => adt.ty(ctx.db),
+ hir::ModuleDef::TypeAlias(a) => a.ty(ctx.db),
+ hir::ModuleDef::BuiltinType(builtin) => builtin.ty(ctx.db),
+ _ => unreachable!(),
+ };
+
+ // XXX: For parity with Rust bug #22519, this does not complete Ty::AssocType.
+ // (where AssocType is defined on a trait, not an inherent impl)
+
+ ty.iterate_path_candidates(
+ ctx.db,
+ &ctx.scope,
+ &ctx.traits_in_scope().0,
+ Some(ctx.module),
+ None,
+ |item| {
+ add_assoc_item(acc, ctx, item);
+ None::<()>
+ },
+ );
+
+ // Iterate assoc types separately
+ ty.iterate_assoc_items(ctx.db, ctx.krate, |item| {
+ if let hir::AssocItem::TypeAlias(ty) = item {
+ acc.add_type_alias(ctx, ty)
+ }
+ None::<()>
+ });
+ }
+ hir::PathResolution::Def(hir::ModuleDef::Trait(t)) => {
+ // Handles `Trait::assoc` as well as `<Ty as Trait>::assoc`.
+ for item in t.items(ctx.db) {
+ add_assoc_item(acc, ctx, item);
+ }
+ }
+ hir::PathResolution::TypeParam(_) | hir::PathResolution::SelfType(_) => {
+ let ty = match resolution {
+ hir::PathResolution::TypeParam(param) => param.ty(ctx.db),
+ hir::PathResolution::SelfType(impl_def) => impl_def.self_ty(ctx.db),
+ _ => return,
+ };
+
+ let mut seen = FxHashSet::default();
+ ty.iterate_path_candidates(
+ ctx.db,
+ &ctx.scope,
+ &ctx.traits_in_scope().0,
+ Some(ctx.module),
+ None,
+ |item| {
+ // We might iterate candidates of a trait multiple times here, so deduplicate
+ // them.
+ if seen.insert(item) {
+ add_assoc_item(acc, ctx, item);
+ }
+ None::<()>
+ },
+ );
+ }
+ _ => (),
+ }
+ }
None if is_absolute_path => acc.add_crate_roots(ctx),
None => {
acc.add_nameref_keywords_with_colon(ctx);
@@ -57,34 +176,18 @@ pub(crate) fn complete_type_path(acc: &mut Completions, ctx: &CompletionContext)
}
}
ctx.process_all_names(&mut |name, def| {
- use hir::{GenericParam::*, ModuleDef::*};
- let add_resolution = match def {
- ScopeDef::GenericParam(LifetimeParam(_)) | ScopeDef::Label(_) => false,
- // no values in type places
- ScopeDef::ModuleDef(Function(_) | Variant(_) | Static(_))
- | ScopeDef::Local(_) => false,
- // unless its a constant in a generic arg list position
- ScopeDef::ModuleDef(Const(_)) | ScopeDef::GenericParam(ConstParam(_)) => {
- ctx.expects_generic_arg()
- }
- ScopeDef::ImplSelfType(_) => {
- !ctx.previous_token_is(syntax::T![impl])
- && !ctx.previous_token_is(syntax::T![for])
- }
- // Don't suggest attribute macros and derives.
- ScopeDef::ModuleDef(Macro(mac)) => mac.is_fn_like(ctx.db),
- // Type things are fine
- ScopeDef::ModuleDef(
- BuiltinType(_) | Adt(_) | Module(_) | Trait(_) | TypeAlias(_),
- )
- | ScopeDef::AdtSelfType(_)
- | ScopeDef::Unknown
- | ScopeDef::GenericParam(TypeParam(_)) => true,
- };
- if add_resolution {
+ if scope_def_applicable(def) {
acc.add_resolution(ctx, name, def);
}
});
}
}
}
+
+fn add_assoc_item(acc: &mut Completions, ctx: &CompletionContext, item: hir::AssocItem) {
+ match item {
+ hir::AssocItem::Const(ct) if ctx.expects_generic_arg() => acc.add_const(ctx, ct),
+ hir::AssocItem::Function(_) | hir::AssocItem::Const(_) => (),
+ hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty),
+ }
+}
diff --git a/crates/ide-completion/src/completions/use_.rs b/crates/ide-completion/src/completions/use_.rs
index 25eb3fb908..fd6d7709a0 100644
--- a/crates/ide-completion/src/completions/use_.rs
+++ b/crates/ide-completion/src/completions/use_.rs
@@ -19,7 +19,7 @@ pub(crate) fn complete_use_tree(acc: &mut Completions, ctx: &CompletionContext)
};
match qualifier {
- Some(PathQualifierCtx { path, resolution, is_super_chain, use_tree_parent }) => {
+ Some(PathQualifierCtx { path, resolution, is_super_chain, use_tree_parent, .. }) => {
if *is_super_chain {
acc.add_keyword(ctx, "super::");
}
diff --git a/crates/ide-completion/src/context.rs b/crates/ide-completion/src/context.rs
index 87677e28e8..c4de8dc52e 100644
--- a/crates/ide-completion/src/context.rs
+++ b/crates/ide-completion/src/context.rs
@@ -75,6 +75,7 @@ pub(crate) struct PathCompletionCtx {
// FIXME: use this
/// The parent of the path we are completing.
pub(super) parent: Option<ast::Path>,
+ // FIXME: This should be PathKind, the none case should never occur
pub(super) kind: Option<PathKind>,
/// Whether the path segment has type args or not.
pub(super) has_type_args: bool,
@@ -91,6 +92,8 @@ pub(crate) struct PathQualifierCtx {
pub(crate) is_super_chain: bool,
/// Whether the qualifier comes from a use tree parent or not
pub(crate) use_tree_parent: bool,
+ /// <_>
+ pub(crate) is_infer_qualifier: bool,
}
#[derive(Debug)]
@@ -378,6 +381,15 @@ impl<'a> CompletionContext<'a> {
}
}
+ /// Returns the traits in scope, with the [`Drop`] trait removed.
+ pub(crate) fn traits_in_scope(&self) -> hir::VisibleTraits {
+ let mut traits_in_scope = self.scope.visible_traits();
+ if let Some(drop) = self.famous_defs().core_ops_Drop() {
+ traits_in_scope.0.remove(&drop.into());
+ }
+ traits_in_scope
+ }
+
/// A version of [`SemanticsScope::process_all_names`] that filters out `#[doc(hidden)]` items.
pub(crate) fn process_all_names(&self, f: &mut dyn FnMut(Name, ScopeDef)) {
let _p = profile::span("CompletionContext::process_all_names");
@@ -1046,7 +1058,24 @@ impl<'a> CompletionContext<'a> {
let res = sema.resolve_path(&path);
let is_super_chain = iter::successors(Some(path.clone()), |p| p.qualifier())
.all(|p| p.segment().and_then(|s| s.super_token()).is_some());
- PathQualifierCtx { path, resolution: res, is_super_chain, use_tree_parent }
+
+ // `<_>::$0`
+ let is_infer_qualifier = path.qualifier().is_none()
+ && matches!(
+ path.segment().and_then(|it| it.kind()),
+ Some(ast::PathSegmentKind::Type {
+ type_ref: Some(ast::Type::InferType(_)),
+ trait_ref: None,
+ })
+ );
+
+ PathQualifierCtx {
+ path,
+ resolution: res,
+ is_super_chain,
+ use_tree_parent,
+ is_infer_qualifier,
+ }
});
return Some((path_ctx, pat_ctx));
}
diff --git a/crates/ide-completion/src/lib.rs b/crates/ide-completion/src/lib.rs
index 3a0bd042da..bc18e80516 100644
--- a/crates/ide-completion/src/lib.rs
+++ b/crates/ide-completion/src/lib.rs
@@ -166,7 +166,6 @@ pub fn completions(
completions::mod_::complete_mod(acc, ctx);
completions::pattern::complete_pattern(acc, ctx);
completions::postfix::complete_postfix(acc, ctx);
- completions::qualified_path::complete_qualified_path(acc, ctx);
completions::record::complete_record_literal(acc, ctx);
completions::record::complete_record(acc, ctx);
completions::snippet::complete_expr_snippet(acc, ctx);
diff --git a/crates/ide-completion/src/tests/special.rs b/crates/ide-completion/src/tests/special.rs
index 79235e5ca0..6195537a18 100644
--- a/crates/ide-completion/src/tests/special.rs
+++ b/crates/ide-completion/src/tests/special.rs
@@ -1,3 +1,5 @@
+//! Tests that don't fit into a specific category.
+
use expect_test::{expect, Expect};
use crate::tests::{check_edit, completion_list_no_kw};
@@ -181,3 +183,456 @@ pub mod prelude {
"#]],
);
}
+
+#[test]
+fn associated_item_visibility() {
+ check(
+ r#"
+//- /lib.rs crate:lib new_source_root:library
+pub struct S;
+
+impl S {
+ pub fn public_method() { }
+ fn private_method() { }
+ pub type PublicType = u32;
+ type PrivateType = u32;
+ pub const PUBLIC_CONST: u32 = 1;
+ const PRIVATE_CONST: u32 = 1;
+}
+
+//- /main.rs crate:main deps:lib new_source_root:local
+fn foo() { let _ = lib::S::$0 }
+"#,
+ expect![[r#"
+ ct PUBLIC_CONST pub const PUBLIC_CONST: u32
+ fn public_method() fn()
+ ta PublicType pub type PublicType = u32
+ "#]],
+ );
+}
+
+#[test]
+fn completes_union_associated_method() {
+ check(
+ r#"
+union U {};
+impl U { fn m() { } }
+
+fn foo() { let _ = U::$0 }
+"#,
+ expect![[r#"
+ fn m() fn()
+ "#]],
+ );
+}
+
+#[test]
+fn completes_trait_associated_method_1() {
+ check(
+ r#"
+trait Trait { fn m(); }
+
+fn foo() { let _ = Trait::$0 }
+"#,
+ expect![[r#"
+ fn m() (as Trait) fn()
+ "#]],
+ );
+}
+
+#[test]
+fn completes_trait_associated_method_2() {
+ check(
+ r#"
+trait Trait { fn m(); }
+
+struct S;
+impl Trait for S {}
+
+fn foo() { let _ = S::$0 }
+"#,
+ expect![[r#"
+ fn m() (as Trait) fn()
+ "#]],
+ );
+}
+
+#[test]
+fn completes_trait_associated_method_3() {
+ check(
+ r#"
+trait Trait { fn m(); }
+
+struct S;
+impl Trait for S {}
+
+fn foo() { let _ = <S as Trait>::$0 }
+"#,
+ expect![[r#"
+ fn m() (as Trait) fn()
+ "#]],
+ );
+}
+
+#[test]
+fn completes_ty_param_assoc_ty() {
+ check(
+ r#"
+trait Super {
+ type Ty;
+ const CONST: u8;
+ fn func() {}
+ fn method(&self) {}
+}
+
+trait Sub: Super {
+ type SubTy;
+ const C2: ();
+ fn subfunc() {}
+ fn submethod(&self) {}
+}
+
+fn foo<T: Sub>() { T::$0 }
+"#,
+ expect![[r#"
+ ct C2 (as Sub) const C2: ()
+ ct CONST (as Super) const CONST: u8
+ fn func() (as Super) fn()
+ fn subfunc() (as Sub) fn()
+ ta SubTy (as Sub) type SubTy
+ ta Ty (as Super) type Ty
+ me method(…) (as Super) fn(&self)
+ me submethod(…) (as Sub) fn(&self)
+ "#]],
+ );
+}
+
+#[test]
+fn completes_self_param_assoc_ty() {
+ check(
+ r#"
+trait Super {
+ type Ty;
+ const CONST: u8 = 0;
+ fn func() {}
+ fn method(&self) {}
+}
+
+trait Sub: Super {
+ type SubTy;
+ const C2: () = ();
+ fn subfunc() {}
+ fn submethod(&self) {}
+}
+
+struct Wrap<T>(T);
+impl<T> Super for Wrap<T> {}
+impl<T> Sub for Wrap<T> {
+ fn subfunc() {
+ // Should be able to assume `Self: Sub + Super`
+ Self::$0
+ }
+}
+"#,
+ expect![[r#"
+ ct C2 (as Sub) const C2: ()
+ ct CONST (as Super) const CONST: u8
+ fn func() (as Super) fn()
+ fn subfunc() (as Sub) fn()
+ ta SubTy (as Sub) type SubTy
+ ta Ty (as Super) type Ty
+ me method(…) (as Super) fn(&self)
+ me submethod(…) (as Sub) fn(&self)
+ "#]],
+ );
+}
+
+#[test]
+fn completes_type_alias() {
+ check(
+ r#"
+struct S;
+impl S { fn foo() {} }
+type T = S;
+impl T { fn bar() {} }
+
+fn main() { T::$0; }
+"#,
+ expect![[r#"
+ fn bar() fn()
+ fn foo() fn()
+ "#]],
+ );
+}
+
+#[test]
+fn completes_qualified_macros() {
+ check(
+ r#"
+#[macro_export]
+macro_rules! foo { () => {} }
+
+fn main() { let _ = crate::$0 }
+"#,
+ expect![[r#"
+ fn main() fn()
+ ma foo!(…) macro_rules! foo
+ "#]],
+ );
+}
+
+#[test]
+fn does_not_complete_non_fn_macros() {
+ check(
+ r#"
+mod m {
+ #[rustc_builtin_macro]
+ pub macro Clone {}
+}
+
+fn f() {m::$0}
+"#,
+ expect![[r#""#]],
+ );
+ check(
+ r#"
+mod m {
+ #[rustc_builtin_macro]
+ pub macro bench {}
+}
+
+fn f() {m::$0}
+"#,
+ expect![[r#""#]],
+ );
+}
+
+#[test]
+fn completes_reexported_items_under_correct_name() {
+ check(
+ r#"
+fn foo() { self::m::$0 }
+
+mod m {
+ pub use super::p::wrong_fn as right_fn;
+ pub use super::p::WRONG_CONST as RIGHT_CONST;
+ pub use super::p::WrongType as RightType;
+}
+mod p {
+ fn wrong_fn() {}
+ const WRONG_CONST: u32 = 1;
+ struct WrongType {};
+}
+"#,
+ expect![[r#"
+ ct RIGHT_CONST
+ fn right_fn() fn()
+ st RightType
+ "#]],
+ );
+
+ check_edit(
+ "RightType",
+ r#"
+fn foo() { self::m::$0 }
+
+mod m {
+ pub use super::p::wrong_fn as right_fn;
+ pub use super::p::WRONG_CONST as RIGHT_CONST;
+ pub use super::p::WrongType as RightType;
+}
+mod p {
+ fn wrong_fn() {}
+ const WRONG_CONST: u32 = 1;
+ struct WrongType {};
+}
+"#,
+ r#"
+fn foo() { self::m::RightType }
+
+mod m {
+ pub use super::p::wrong_fn as right_fn;
+ pub use super::p::WRONG_CONST as RIGHT_CONST;
+ pub use super::p::WrongType as RightType;
+}
+mod p {
+ fn wrong_fn() {}
+ const WRONG_CONST: u32 = 1;
+ struct WrongType {};
+}
+"#,
+ );
+}
+
+#[test]
+fn completes_in_simple_macro_call() {
+ check(
+ r#"
+macro_rules! m { ($e:expr) => { $e } }
+fn main() { m!(self::f$0); }
+fn foo() {}
+"#,
+ expect![[r#"
+ fn foo() fn()
+ fn main() fn()
+ "#]],
+ );
+}
+
+#[test]
+fn function_mod_share_name() {
+ check(
+ r#"
+fn foo() { self::m::$0 }
+
+mod m {
+ pub mod z {}
+ pub fn z() {}
+}
+"#,
+ expect![[r#"
+ fn z() fn()
+ md z
+ "#]],
+ );
+}
+
+#[test]
+fn completes_hashmap_new() {
+ check(
+ r#"
+struct RandomState;
+struct HashMap<K, V, S = RandomState> {}
+
+impl<K, V> HashMap<K, V, RandomState> {
+ pub fn new() -> HashMap<K, V, RandomState> { }
+}
+fn foo() {
+ HashMap::$0
+}
+"#,
+ expect![[r#"
+ fn new() fn() -> HashMap<K, V, RandomState>
+ "#]],
+ );
+}
+
+#[test]
+fn completes_variant_through_self() {
+ check(
+ r#"
+enum Foo {
+ Bar,
+ Baz,
+}
+
+impl Foo {
+ fn foo(self) {
+ Self::$0
+ }
+}
+"#,
+ expect![[r#"
+ ev Bar Bar
+ ev Baz Baz
+ me foo(…) fn(self)
+ "#]],
+ );
+}
+
+#[test]
+fn completes_primitive_assoc_const() {
+ cov_mark::check!(completes_primitive_assoc_const);
+ check(
+ r#"
+//- /lib.rs crate:lib deps:core
+fn f() {
+ u8::$0
+}
+
+//- /core.rs crate:core
+#[lang = "u8"]
+impl u8 {
+ pub const MAX: Self = 255;
+
+ pub fn func(self) {}
+}
+"#,
+ expect![[r#"
+ ct MAX pub const MAX: Self
+ me func(…) fn(self)
+ "#]],
+ );
+}
+
+#[test]
+fn completes_variant_through_alias() {
+ cov_mark::check!(completes_variant_through_alias);
+ check(
+ r#"
+enum Foo {
+ Bar
+}
+type Foo2 = Foo;
+fn main() {
+ Foo2::$0
+}
+"#,
+ expect![[r#"
+ ev Bar Bar
+ "#]],
+ );
+}
+
+#[test]
+fn respects_doc_hidden2() {
+ cov_mark::check!(qualified_path_doc_hidden);
+ check(
+ r#"
+//- /lib.rs crate:lib deps:dep
+fn f() {
+ dep::$0
+}
+
+//- /dep.rs crate:dep
+#[doc(hidden)]
+#[macro_export]
+macro_rules! m {
+ () => {}
+}
+
+#[doc(hidden)]
+pub fn f() {}
+
+#[doc(hidden)]
+pub struct S;
+
+#[doc(hidden)]
+pub mod m {}
+ "#,
+ expect![[r#""#]],
+ )
+}
+
+#[test]
+fn type_anchor_empty() {
+ check(
+ r#"
+trait Foo {
+ fn foo() -> Self;
+}
+struct Bar;
+impl Foo for Bar {
+ fn foo() -> {
+ Bar
+ }
+}
+fn bar() -> Bar {
+ <_>::$0
+}
+"#,
+ expect![[r#"
+ fn foo() (as Foo) fn() -> Self
+ "#]],
+ )
+}
diff --git a/crates/ide-ssr/src/resolving.rs b/crates/ide-ssr/src/resolving.rs
index d46ca05e55..f3b1af8e77 100644
--- a/crates/ide-ssr/src/resolving.rs
+++ b/crates/ide-ssr/src/resolving.rs
@@ -230,7 +230,7 @@ impl<'db> ResolutionScope<'db> {
adt.ty(self.scope.db).iterate_path_candidates(
self.scope.db,
&self.scope,
- &self.scope.visible_traits(),
+ &self.scope.visible_traits().0,
Some(module),
None,
|assoc_item| {