Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir/src/attrs.rs')
-rw-r--r--crates/hir/src/attrs.rs66
1 files changed, 48 insertions, 18 deletions
diff --git a/crates/hir/src/attrs.rs b/crates/hir/src/attrs.rs
index cba1b39e52..cfb95e07c3 100644
--- a/crates/hir/src/attrs.rs
+++ b/crates/hir/src/attrs.rs
@@ -3,7 +3,8 @@
use cfg::CfgExpr;
use either::Either;
use hir_def::{
- AssocItemId, AttrDefId, FieldId, LifetimeParamId, ModuleDefId, TypeOrConstParamId,
+ AssocItemId, AttrDefId, FieldId, GenericDefId, ItemContainerId, LifetimeParamId, ModuleDefId,
+ TraitId, TypeOrConstParamId,
attrs::{AttrFlags, Docs, IsInnerDoc},
expr_store::path::Path,
item_scope::ItemInNs,
@@ -22,6 +23,7 @@ use hir_ty::{
next_solver::{DbInterner, TypingMode, infer::DbInternerInferExt},
};
use intern::Symbol;
+use stdx::never;
use crate::{
Adt, AsAssocItem, AssocItem, BuiltinType, Const, ConstParam, DocLinkDef, Enum, ExternCrateDecl,
@@ -357,13 +359,46 @@ fn resolve_assoc_or_field(
ns: Option<Namespace>,
) -> Option<DocLinkDef> {
let path = Path::from_known_path_with_no_generic(path);
- // FIXME: This does not handle `Self` on trait definitions, which we should resolve to the
- // trait itself.
let base_def = resolver.resolve_path_in_type_ns_fully(db, &path)?;
+ let handle_trait = |id: TraitId| {
+ // Doc paths in this context may only resolve to an item of this trait
+ // (i.e. no items of its supertraits), so we need to handle them here
+ // independently of others.
+ id.trait_items(db).items.iter().find(|it| it.0 == name).map(|(_, assoc_id)| {
+ let def = match *assoc_id {
+ AssocItemId::FunctionId(it) => ModuleDef::Function(it.into()),
+ AssocItemId::ConstId(it) => ModuleDef::Const(it.into()),
+ AssocItemId::TypeAliasId(it) => ModuleDef::TypeAlias(it.into()),
+ };
+ DocLinkDef::ModuleDef(def)
+ })
+ };
let ty = match base_def {
TypeNs::SelfType(id) => Impl::from(id).self_ty(db),
- TypeNs::GenericParam(_) => {
+ TypeNs::GenericParam(param) => {
+ let generic_params = db.generic_params(param.parent());
+ if generic_params[param.local_id()].is_trait_self() {
+ // `Self::assoc` in traits should refer to the trait itself.
+ let parent_trait = |container| match container {
+ ItemContainerId::TraitId(trait_) => handle_trait(trait_),
+ _ => {
+ never!("container {container:?} should be a trait");
+ None
+ }
+ };
+ return match param.parent() {
+ GenericDefId::TraitId(trait_) => handle_trait(trait_),
+ GenericDefId::ConstId(it) => parent_trait(it.loc(db).container),
+ GenericDefId::FunctionId(it) => parent_trait(it.loc(db).container),
+ GenericDefId::TypeAliasId(it) => parent_trait(it.loc(db).container),
+ _ => {
+ never!("type param {param:?} should belong to a trait");
+ None
+ }
+ };
+ }
+
// Even if this generic parameter has some trait bounds, rustdoc doesn't
// resolve `name` to trait items.
return None;
@@ -384,19 +419,7 @@ fn resolve_assoc_or_field(
alias.ty(db)
}
TypeNs::BuiltinType(id) => BuiltinType::from(id).ty(db),
- TypeNs::TraitId(id) => {
- // Doc paths in this context may only resolve to an item of this trait
- // (i.e. no items of its supertraits), so we need to handle them here
- // independently of others.
- return id.trait_items(db).items.iter().find(|it| it.0 == name).map(|(_, assoc_id)| {
- let def = match *assoc_id {
- AssocItemId::FunctionId(it) => ModuleDef::Function(it.into()),
- AssocItemId::ConstId(it) => ModuleDef::Const(it.into()),
- AssocItemId::TypeAliasId(it) => ModuleDef::TypeAlias(it.into()),
- };
- DocLinkDef::ModuleDef(def)
- });
- }
+ TypeNs::TraitId(id) => return handle_trait(id),
TypeNs::ModuleId(_) => {
return None;
}
@@ -414,7 +437,14 @@ fn resolve_assoc_or_field(
let variant_def = match ty.as_adt()? {
Adt::Struct(it) => it.into(),
Adt::Union(it) => it.into(),
- Adt::Enum(_) => return None,
+ Adt::Enum(enum_) => {
+ // Can happen on `Self::Variant` (otherwise would be fully resolved by the resolver).
+ return enum_
+ .id
+ .enum_variants(db)
+ .variant(&name)
+ .map(|variant| DocLinkDef::ModuleDef(ModuleDef::Variant(variant.into())));
+ }
};
resolve_field(db, variant_def, name, ns)
}