diff options
| -rw-r--r-- | src/librustdoc/core.rs | 4 | ||||
| -rw-r--r-- | src/librustdoc/html/markdown.rs | 10 | ||||
| -rw-r--r-- | src/librustdoc/passes/collect_intra_doc_links.rs | 84 | ||||
| -rw-r--r-- | src/librustdoc/passes/collect_intra_doc_links/early.rs | 15 |
4 files changed, 68 insertions, 45 deletions
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index adf19aa8e74..1db6064551c 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -29,13 +29,13 @@ use crate::clean::inline::build_external_trait; use crate::clean::{self, ItemId, TraitWithExtraInfo}; use crate::config::{Options as RustdocOptions, OutputFormat, RenderOptions}; use crate::formats::cache::Cache; -use crate::html::markdown::MarkdownLink; +use crate::passes::collect_intra_doc_links::PreprocessedMarkdownLink; use crate::passes::{self, Condition::*}; crate use rustc_session::config::{DebuggingOptions, Input, Options}; crate struct ResolverCaches { - crate markdown_links: Option<FxHashMap<String, Vec<MarkdownLink>>>, + crate markdown_links: Option<FxHashMap<String, Vec<PreprocessedMarkdownLink>>>, crate doc_link_resolutions: FxHashMap<(Symbol, Namespace, DefId), Option<Res<NodeId>>>, /// Traits in scope for a given module. /// See `collect_intra_doc_links::traits_implemented_by` for more details. diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 1ebb41b5933..eafe6f17d44 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -1255,7 +1255,7 @@ crate struct MarkdownLink { pub range: Range<usize>, } -crate fn markdown_links(md: &str) -> Vec<MarkdownLink> { +crate fn markdown_links<R>(md: &str, filter_map: impl Fn(MarkdownLink) -> Option<R>) -> Vec<R> { if md.is_empty() { return vec![]; } @@ -1295,11 +1295,12 @@ crate fn markdown_links(md: &str) -> Vec<MarkdownLink> { let mut push = |link: BrokenLink<'_>| { let span = span_for_link(&link.reference, link.span); - links.borrow_mut().push(MarkdownLink { + filter_map(MarkdownLink { kind: LinkType::ShortcutUnknown, link: link.reference.to_string(), range: span, - }); + }) + .map(|link| links.borrow_mut().push(link)); None }; let p = Parser::new_with_broken_link_callback(md, main_body_opts(), Some(&mut push)) @@ -1314,7 +1315,8 @@ crate fn markdown_links(md: &str) -> Vec<MarkdownLink> { if let Event::Start(Tag::Link(kind, dest, _)) = ev.0 { debug!("found link: {dest}"); let span = span_for_link(&dest, ev.1); - links.borrow_mut().push(MarkdownLink { kind, link: dest.into_string(), range: span }); + filter_map(MarkdownLink { kind, link: dest.into_string(), range: span }) + .map(|link| links.borrow_mut().push(link)); } } diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 823a94048eb..c9fc14d5f71 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -160,7 +160,7 @@ impl TryFrom<ResolveRes> for Res { } /// A link failed to resolve. -#[derive(Debug)] +#[derive(Clone, Debug)] enum ResolutionFailure<'a> { /// This resolved, but with the wrong namespace. WrongNamespace { @@ -200,7 +200,7 @@ enum ResolutionFailure<'a> { Dummy, } -#[derive(Debug)] +#[derive(Clone, Debug)] enum MalformedGenerics { /// This link has unbalanced angle brackets. /// @@ -253,6 +253,7 @@ impl ResolutionFailure<'_> { } } +#[derive(Clone, Copy)] enum AnchorFailure { /// User error: `[std#x#y]` is not valid MultipleAnchors, @@ -1064,7 +1065,7 @@ impl<'a, 'tcx> DocVisitor for LinkCollector<'a, 'tcx> { .take() .expect("`markdown_links` are already borrowed"); if !tmp_links.contains_key(&doc) { - tmp_links.insert(doc.clone(), markdown_links(&doc)); + tmp_links.insert(doc.clone(), preprocessed_markdown_links(&doc)); } for md_link in &tmp_links[&doc] { let link = self.resolve_link(&item, &doc, parent_node, md_link); @@ -1088,18 +1089,19 @@ impl<'a, 'tcx> DocVisitor for LinkCollector<'a, 'tcx> { } } -enum PreprocessingError<'a> { +enum PreprocessingError { Anchor(AnchorFailure), Disambiguator(Range<usize>, String), - Resolution(ResolutionFailure<'a>, String, Option<Disambiguator>), + Resolution(ResolutionFailure<'static>, String, Option<Disambiguator>), } -impl From<AnchorFailure> for PreprocessingError<'_> { +impl From<AnchorFailure> for PreprocessingError { fn from(err: AnchorFailure) -> Self { Self::Anchor(err) } } +#[derive(Clone)] struct PreprocessingInfo { path_str: String, disambiguator: Option<Disambiguator>, @@ -1107,15 +1109,18 @@ struct PreprocessingInfo { link_text: String, } +// Not a typedef to avoid leaking several private structures from this module. +crate struct PreprocessedMarkdownLink(Result<PreprocessingInfo, PreprocessingError>, MarkdownLink); + /// Returns: /// - `None` if the link should be ignored. /// - `Some(Err)` if the link should emit an error /// - `Some(Ok)` if the link is valid /// /// `link_buffer` is needed for lifetime reasons; it will always be overwritten and the contents ignored. -fn preprocess_link<'a>( - ori_link: &'a MarkdownLink, -) -> Option<Result<PreprocessingInfo, PreprocessingError<'a>>> { +fn preprocess_link( + ori_link: &MarkdownLink, +) -> Option<Result<PreprocessingInfo, PreprocessingError>> { // [] is mostly likely not supposed to be a link if ori_link.link.is_empty() { return None; @@ -1194,6 +1199,12 @@ fn preprocess_link<'a>( })) } +fn preprocessed_markdown_links(s: &str) -> Vec<PreprocessedMarkdownLink> { + markdown_links(s, |link| { + preprocess_link(&link).map(|pp_link| PreprocessedMarkdownLink(pp_link, link)) + }) +} + impl LinkCollector<'_, '_> { /// This is the entry point for resolving an intra-doc link. /// @@ -1203,8 +1214,9 @@ impl LinkCollector<'_, '_> { item: &Item, dox: &str, parent_node: Option<DefId>, - ori_link: &MarkdownLink, + link: &PreprocessedMarkdownLink, ) -> Option<ItemLink> { + let PreprocessedMarkdownLink(pp_link, ori_link) = link; trace!("considering link '{}'", ori_link.link); let diag_info = DiagnosticInfo { @@ -1214,28 +1226,29 @@ impl LinkCollector<'_, '_> { link_range: ori_link.range.clone(), }; - let PreprocessingInfo { ref path_str, disambiguator, extra_fragment, link_text } = - match preprocess_link(&ori_link)? { - Ok(x) => x, - Err(err) => { - match err { - PreprocessingError::Anchor(err) => anchor_failure(self.cx, diag_info, err), - PreprocessingError::Disambiguator(range, msg) => { - disambiguator_error(self.cx, diag_info, range, &msg) - } - PreprocessingError::Resolution(err, path_str, disambiguator) => { - resolution_failure( - self, - diag_info, - &path_str, - disambiguator, - smallvec![err], - ); - } + let PreprocessingInfo { path_str, disambiguator, extra_fragment, link_text } = match pp_link + { + Ok(x) => x, + Err(err) => { + match err { + PreprocessingError::Anchor(err) => anchor_failure(self.cx, diag_info, *err), + PreprocessingError::Disambiguator(range, msg) => { + disambiguator_error(self.cx, diag_info, range.clone(), msg) + } + PreprocessingError::Resolution(err, path_str, disambiguator) => { + resolution_failure( + self, + diag_info, + path_str, + *disambiguator, + smallvec![err.clone()], + ); } - return None; } - }; + return None; + } + }; + let disambiguator = *disambiguator; let inner_docs = item.inner_docs(self.cx.tcx); @@ -1272,7 +1285,7 @@ impl LinkCollector<'_, '_> { module_id, dis: disambiguator, path_str: path_str.to_owned(), - extra_fragment, + extra_fragment: extra_fragment.clone(), }, diag_info.clone(), // this struct should really be Copy, but Range is not :( matches!(ori_link.kind, LinkType::Reference | LinkType::Shortcut), @@ -1343,7 +1356,7 @@ impl LinkCollector<'_, '_> { Some(ItemLink { link: ori_link.link.clone(), - link_text, + link_text: link_text.clone(), did: res.def_id(self.cx.tcx), fragment, }) @@ -1365,7 +1378,12 @@ impl LinkCollector<'_, '_> { &diag_info, )?; let id = clean::register_res(self.cx, rustc_hir::def::Res::Def(kind, id)); - Some(ItemLink { link: ori_link.link.clone(), link_text, did: id, fragment }) + Some(ItemLink { + link: ori_link.link.clone(), + link_text: link_text.clone(), + did: id, + fragment, + }) } } } diff --git a/src/librustdoc/passes/collect_intra_doc_links/early.rs b/src/librustdoc/passes/collect_intra_doc_links/early.rs index e8920d5e288..a285c300b75 100644 --- a/src/librustdoc/passes/collect_intra_doc_links/early.rs +++ b/src/librustdoc/passes/collect_intra_doc_links/early.rs @@ -1,7 +1,7 @@ use crate::clean::Attributes; use crate::core::ResolverCaches; -use crate::html::markdown::{markdown_links, MarkdownLink}; -use crate::passes::collect_intra_doc_links::preprocess_link; +use crate::passes::collect_intra_doc_links::preprocessed_markdown_links; +use crate::passes::collect_intra_doc_links::PreprocessedMarkdownLink; use rustc_ast::visit::{self, AssocCtxt, Visitor}; use rustc_ast::{self as ast, ItemKind}; @@ -72,7 +72,7 @@ struct EarlyDocLinkResolver<'r, 'ra> { resolver: &'r mut Resolver<'ra>, current_mod: LocalDefId, visited_mods: DefIdSet, - markdown_links: FxHashMap<String, Vec<MarkdownLink>>, + markdown_links: FxHashMap<String, Vec<PreprocessedMarkdownLink>>, doc_link_resolutions: FxHashMap<(Symbol, Namespace, DefId), Option<Res<ast::NodeId>>>, traits_in_scope: DefIdMap<Vec<TraitCandidate>>, all_traits: Vec<DefId>, @@ -203,9 +203,12 @@ impl EarlyDocLinkResolver<'_, '_> { let mut need_traits_in_scope = false; for (doc_module, doc) in attrs.collapsed_doc_value_by_module_level() { assert_eq!(doc_module, None); - for link in self.markdown_links.entry(doc).or_insert_with_key(|doc| markdown_links(doc)) - { - if let Some(Ok(pinfo)) = preprocess_link(&link) { + let links = self + .markdown_links + .entry(doc) + .or_insert_with_key(|doc| preprocessed_markdown_links(doc)); + for PreprocessedMarkdownLink(pp_link, _) in links { + if let Ok(pinfo) = pp_link { // FIXME: Resolve the path in all namespaces and resolve its prefixes too. let ns = TypeNS; self.doc_link_resolutions |
