From 4993807dd9416ed65b9cac0e507af34bfe04a4ad Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 24 Nov 2019 14:05:12 +0100 Subject: [PATCH 1/4] little intra-doc code cleanup --- .../passes/collect_intra_doc_links.rs | 27 ++++++++----------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 783168d7bd6..636f6bcb13b 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -121,23 +121,18 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { // Try looking for methods and associated items. let mut split = path_str.rsplitn(2, "::"); - let item_name = if let Some(first) = split.next() { - Symbol::intern(first) - } else { - return Err(ErrorKind::ResolutionFailure) - }; - - let mut path = if let Some(second) = split.next() { - second.to_owned() - } else { - return Err(ErrorKind::ResolutionFailure) - }; - - if path == "self" || path == "Self" { - if let Some(name) = current_item.as_ref() { - path = name.clone(); + let item_name = split.next() + .map(|f| Symbol::intern(f)) + .ok_or(ErrorKind::ResolutionFailure)?; + 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(ErrorKind::ResolutionFailure)?; + if let Some(prim) = is_primitive(&path, TypeNS) { let did = primitive_impl(cx, &path).ok_or(ErrorKind::ResolutionFailure)?; return cx.tcx.associated_items(did) From 4ab8aa37005c5044d989a8fa1f3495eb76dff7d2 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 24 Nov 2019 16:27:52 +0100 Subject: [PATCH 2/4] Add support for intra-doc link fields of enum variant --- .../passes/collect_intra_doc_links.rs | 67 +++++++++++++++++-- .../intra-doc-link-enum-struct-field.rs | 14 ++++ 2 files changed, 74 insertions(+), 7 deletions(-) create mode 100644 src/test/rustdoc/intra-doc-link-enum-struct-field.rs diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 636f6bcb13b..3c9b2f2154b 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -56,6 +56,59 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { } } + fn variant_field( + &self, + path_str: &str, + current_item: &Option, + module_id: syntax::ast::NodeId, + ) -> Result<(Res, Option), ()> { + 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 /// URL fragment in the case of variants and methods. fn resolve( @@ -149,7 +202,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { resolver.resolve_str_path_error(DUMMY_SP, &path, TypeNS, module_id) }).map_err(|_| ErrorKind::ResolutionFailure)?; 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")); match ty_res { @@ -165,7 +218,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { let out = match item.kind { ty::AssocKind::Method if ns == ValueNS => "method", 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() { Err(ErrorKind::AnchorFailure( @@ -206,10 +259,10 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { item.ident)))) } } 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), } } } @@ -228,7 +281,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { "tymethod" } } - _ => return Err(ErrorKind::ResolutionFailure) + _ => return self.variant_field(path_str, current_item, module_id), }; if extra_fragment.is_some() { @@ -244,10 +297,10 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { Ok((ty_res, Some(format!("{}.{}", kind, item_name)))) } } 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 { debug!("attempting to resolve item without parent module: {}", path_str); diff --git a/src/test/rustdoc/intra-doc-link-enum-struct-field.rs b/src/test/rustdoc/intra-doc-link-enum-struct-field.rs new file mode 100644 index 00000000000..70bf343a9a5 --- /dev/null +++ b/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' From b91a6fcd5d82da723d7af1bf6790fd93a7741e93 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 26 Nov 2019 13:25:14 +0100 Subject: [PATCH 3/4] Replace Iterator::find calls with Iterator::any when better --- src/librustdoc/passes/collect_intra_doc_links.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 3c9b2f2154b..3c632462168 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -84,17 +84,16 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { 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() { + if cx.tcx.inherent_impls(did) + .iter() + .flat_map(|imp| cx.tcx.associated_items(*imp)) + .any(|item| item.ident.name == variant_name) { 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() { + .any(|item| item.ident.name == variant_field_name) { Ok((ty_res, Some(format!("variant.{}.field.{}", variant_name, variant_field_name)))) From 97c427cc5ee8d1748ff3a3547bd22cd64d23a6e2 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 27 Nov 2019 13:15:16 +0100 Subject: [PATCH 4/4] Use new ErrorKind enum --- .../passes/collect_intra_doc_links.rs | 26 ++++++++++++------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 3c632462168..d8f2dbca835 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -61,12 +61,18 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { path_str: &str, current_item: &Option, module_id: syntax::ast::NodeId, - ) -> Result<(Res, Option), ()> { + ) -> Result<(Res, Option), ErrorKind> { 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 variant_field_name = split + .next() + .map(|f| Symbol::intern(f)) + .ok_or(ErrorKind::ResolutionFailure)?; + let variant_name = split + .next() + .map(|f| Symbol::intern(f)) + .ok_or(ErrorKind::ResolutionFailure)?; let path = split.next().map(|f| { if f == "self" || f == "Self" { if let Some(name) = current_item.as_ref() { @@ -74,12 +80,12 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { } } f.to_owned() - }).ok_or(())?; + }).ok_or(ErrorKind::ResolutionFailure)?; let (_, ty_res) = cx.enter_resolver(|resolver| { resolver.resolve_str_path_error(DUMMY_SP, &path, TypeNS, module_id) - })?; + }).map_err(|_| ErrorKind::ResolutionFailure)?; if let Res::Err = ty_res { - return Err(()); + return Err(ErrorKind::ResolutionFailure); } let ty_res = ty_res.map_id(|_| panic!("unexpected node_id")); match ty_res { @@ -88,7 +94,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { .iter() .flat_map(|imp| cx.tcx.associated_items(*imp)) .any(|item| item.ident.name == variant_name) { - return Err(()); + return Err(ErrorKind::ResolutionFailure); } match cx.tcx.type_of(did).kind { ty::Adt(def, _) if def.is_enum() => { @@ -98,13 +104,13 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { Some(format!("variant.{}.field.{}", variant_name, variant_field_name)))) } else { - Err(()) + Err(ErrorKind::ResolutionFailure) } } - _ => Err(()), + _ => Err(ErrorKind::ResolutionFailure), } } - _ => Err(()) + _ => Err(ErrorKind::ResolutionFailure) } }