Skip to content

Commit

Permalink
Add support for intra-doc link fields of enum variant
Browse files Browse the repository at this point in the history
  • Loading branch information
GuillaumeGomez committed Nov 27, 2019
1 parent 4993807 commit 4ab8aa3
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 7 deletions.
67 changes: 60 additions & 7 deletions src/librustdoc/passes/collect_intra_doc_links.rs
Expand Up @@ -56,6 +56,59 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
} }
} }


fn variant_field(
&self,
path_str: &str,
current_item: &Option<String>,
module_id: syntax::ast::NodeId,
) -> Result<(Res, Option<String>), ()> {
let cx = self.cx;

let mut split = path_str.rsplitn(3, "::");
let variant_field_name = split.next().map(|f| Symbol::intern(f)).ok_or(())?;
let variant_name = split.next().map(|f| Symbol::intern(f)).ok_or(())?;
let path = split.next().map(|f| {
if f == "self" || f == "Self" {
if let Some(name) = current_item.as_ref() {
return name.clone();
}
}
f.to_owned()
}).ok_or(())?;
let (_, ty_res) = cx.enter_resolver(|resolver| {
resolver.resolve_str_path_error(DUMMY_SP, &path, TypeNS, module_id)
})?;
if let Res::Err = ty_res {
return Err(());
}
let ty_res = ty_res.map_id(|_| panic!("unexpected node_id"));
match ty_res {
Res::Def(DefKind::Enum, did) => {
let item = cx.tcx.inherent_impls(did)
.iter()
.flat_map(|imp| cx.tcx.associated_items(*imp))
.find(|item| item.ident.name == variant_name);
if item.is_some() {
return Err(());
}
match cx.tcx.type_of(did).kind {
ty::Adt(def, _) if def.is_enum() => {
if def.all_fields()
.find(|item| item.ident.name == variant_field_name).is_some() {
Ok((ty_res,
Some(format!("variant.{}.field.{}",
variant_name, variant_field_name))))
} else {
Err(())
}
}
_ => Err(()),
}
}
_ => Err(())
}
}

/// Resolves a string as a path within a particular namespace. Also returns an optional /// Resolves a string as a path within a particular namespace. Also returns an optional
/// URL fragment in the case of variants and methods. /// URL fragment in the case of variants and methods.
fn resolve( fn resolve(
Expand Down Expand Up @@ -149,7 +202,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
resolver.resolve_str_path_error(DUMMY_SP, &path, TypeNS, module_id) resolver.resolve_str_path_error(DUMMY_SP, &path, TypeNS, module_id)
}).map_err(|_| ErrorKind::ResolutionFailure)?; }).map_err(|_| ErrorKind::ResolutionFailure)?;
if let Res::Err = ty_res { if let Res::Err = ty_res {
return Err(ErrorKind::ResolutionFailure); return self.variant_field(path_str, current_item, module_id);
} }
let ty_res = ty_res.map_id(|_| panic!("unexpected node_id")); let ty_res = ty_res.map_id(|_| panic!("unexpected node_id"));
match ty_res { match ty_res {
Expand All @@ -165,7 +218,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
let out = match item.kind { let out = match item.kind {
ty::AssocKind::Method if ns == ValueNS => "method", ty::AssocKind::Method if ns == ValueNS => "method",
ty::AssocKind::Const if ns == ValueNS => "associatedconstant", ty::AssocKind::Const if ns == ValueNS => "associatedconstant",
_ => return Err(ErrorKind::ResolutionFailure) _ => return self.variant_field(path_str, current_item, module_id),
}; };
if extra_fragment.is_some() { if extra_fragment.is_some() {
Err(ErrorKind::AnchorFailure( Err(ErrorKind::AnchorFailure(
Expand Down Expand Up @@ -206,10 +259,10 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
item.ident)))) item.ident))))
} }
} else { } else {
Err(ErrorKind::ResolutionFailure) self.variant_field(path_str, current_item, module_id)
} }
} }
_ => Err(ErrorKind::ResolutionFailure), _ => self.variant_field(path_str, current_item, module_id),
} }
} }
} }
Expand All @@ -228,7 +281,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
"tymethod" "tymethod"
} }
} }
_ => return Err(ErrorKind::ResolutionFailure) _ => return self.variant_field(path_str, current_item, module_id),
}; };


if extra_fragment.is_some() { if extra_fragment.is_some() {
Expand All @@ -244,10 +297,10 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
Ok((ty_res, Some(format!("{}.{}", kind, item_name)))) Ok((ty_res, Some(format!("{}.{}", kind, item_name))))
} }
} else { } else {
Err(ErrorKind::ResolutionFailure) self.variant_field(path_str, current_item, module_id)
} }
} }
_ => Err(ErrorKind::ResolutionFailure) _ => self.variant_field(path_str, current_item, module_id),
} }
} else { } else {
debug!("attempting to resolve item without parent module: {}", path_str); debug!("attempting to resolve item without parent module: {}", path_str);
Expand Down
14 changes: 14 additions & 0 deletions src/test/rustdoc/intra-doc-link-enum-struct-field.rs
@@ -0,0 +1,14 @@
#![crate_name = "foo"]

pub enum Foo {
X {
y: u8,
}
}

/// Hello
///
/// I want [Foo::X::y].
pub fn foo() {}

// @has foo/fn.foo.html '//a/@href' '../foo/enum.Foo.html#variant.X.field.y'

0 comments on commit 4ab8aa3

Please sign in to comment.