From 34ba77d26064f9038fddd5349ceede088f8557f9 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 18 Feb 2023 13:47:04 +0400 Subject: [PATCH 1/3] rustdoc: Do not use Footnotes and HeadingLinks when extracting doc links they do not add any `Link` events --- src/librustdoc/html/markdown.rs | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index e4adee6ae4d..394bea3caee 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -1275,15 +1275,10 @@ pub(crate) fn markdown_links( .map(|link| links.borrow_mut().push(link)); None }; - let p = Parser::new_with_broken_link_callback(md, main_body_opts(), Some(&mut push)) - .into_offset_iter(); - // There's no need to thread an IdMap through to here because - // the IDs generated aren't going to be emitted anywhere. - let mut ids = IdMap::new(); - let iter = Footnotes::new(HeadingLinks::new(p, None, &mut ids, HeadingOffset::H1)); - - for ev in iter { + for ev in Parser::new_with_broken_link_callback(md, main_body_opts(), Some(&mut push)) + .into_offset_iter() + { if let Event::Start(Tag::Link( // `<>` links cannot be intra-doc links so we skip them. kind @ (LinkType::Inline From ccdb598d1b495952bdb09122dc53c39b40f23758 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 18 Feb 2023 14:10:38 +0400 Subject: [PATCH 2/3] rustdoc: Cleanup broken link callbacks --- compiler/rustc_resolve/src/rustdoc.rs | 23 ++++------ src/librustdoc/html/markdown.rs | 46 +++++++------------ .../intra-doc/unknown-disambiguator.stderr | 32 ++++++------- 3 files changed, 43 insertions(+), 58 deletions(-) diff --git a/compiler/rustc_resolve/src/rustdoc.rs b/compiler/rustc_resolve/src/rustdoc.rs index 3425e24585c..be49fbfaa29 100644 --- a/compiler/rustc_resolve/src/rustdoc.rs +++ b/compiler/rustc_resolve/src/rustdoc.rs @@ -5,7 +5,6 @@ use rustc_data_structures::fx::FxHashMap; use rustc_span::def_id::DefId; use rustc_span::symbol::{kw, Symbol}; use rustc_span::Span; -use std::cell::RefCell; use std::{cmp, mem}; #[derive(Clone, Copy, PartialEq, Eq, Debug)] @@ -354,16 +353,14 @@ pub(crate) fn attrs_to_preprocessed_links(attrs: &[ast::Attribute]) -> Vec| { - links.borrow_mut().push(preprocess_link(&link.reference)); - None - }; - for event in Parser::new_with_broken_link_callback(&doc, main_body_opts(), Some(&mut callback)) - { - if let Event::Start(Tag::Link(_, dest, _)) = event { - links.borrow_mut().push(preprocess_link(&dest)); - } - } - links.into_inner() + Parser::new_with_broken_link_callback( + &doc, + main_body_opts(), + Some(&mut |link: BrokenLink<'_>| Some((link.reference, "".into()))), + ) + .filter_map(|event| match event { + Event::Start(Tag::Link(_, dest, _)) => Some(preprocess_link(&dest)), + _ => None, + }) + .collect() } diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 394bea3caee..a34628991b2 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -34,7 +34,6 @@ use rustc_span::{Span, Symbol}; use once_cell::sync::Lazy; use std::borrow::Cow; -use std::cell::RefCell; use std::collections::VecDeque; use std::default::Default; use std::fmt::Write; @@ -1226,14 +1225,12 @@ pub(crate) struct MarkdownLink { pub(crate) fn markdown_links( md: &str, - filter_map: impl Fn(MarkdownLink) -> Option, + preprocess_link: impl Fn(MarkdownLink) -> Option, ) -> Vec { if md.is_empty() { return vec![]; } - let links = RefCell::new(vec![]); - // FIXME: remove this function once pulldown_cmark can provide spans for link definitions. let locate = |s: &str, fallback: Range| unsafe { let s_start = s.as_ptr(); @@ -1265,21 +1262,14 @@ pub(crate) fn markdown_links( } }; - let mut push = |link: BrokenLink<'_>| { - let span = span_for_link(&link.reference, link.span); - filter_map(MarkdownLink { - kind: LinkType::ShortcutUnknown, - link: link.reference.to_string(), - range: span, - }) - .map(|link| links.borrow_mut().push(link)); - None - }; - - for ev in Parser::new_with_broken_link_callback(md, main_body_opts(), Some(&mut push)) - .into_offset_iter() - { - if let Event::Start(Tag::Link( + Parser::new_with_broken_link_callback( + md, + main_body_opts(), + Some(&mut |link: BrokenLink<'_>| Some((link.reference, "".into()))), + ) + .into_offset_iter() + .filter_map(|(event, span)| match event { + Event::Start(Tag::Link( // `<>` links cannot be intra-doc links so we skip them. kind @ (LinkType::Inline | LinkType::Reference @@ -1290,16 +1280,14 @@ pub(crate) fn markdown_links( | LinkType::ShortcutUnknown), dest, _, - )) = ev.0 - { - debug!("found link: {dest}"); - let span = span_for_link(&dest, ev.1); - filter_map(MarkdownLink { kind, link: dest.into_string(), range: span }) - .map(|link| links.borrow_mut().push(link)); - } - } - - links.into_inner() + )) => preprocess_link(MarkdownLink { + kind, + range: span_for_link(&dest, span), + link: dest.into_string(), + }), + _ => None, + }) + .collect() } #[derive(Debug)] diff --git a/tests/rustdoc-ui/intra-doc/unknown-disambiguator.stderr b/tests/rustdoc-ui/intra-doc/unknown-disambiguator.stderr index 19e541736bd..741a7f51a77 100644 --- a/tests/rustdoc-ui/intra-doc/unknown-disambiguator.stderr +++ b/tests/rustdoc-ui/intra-doc/unknown-disambiguator.stderr @@ -20,22 +20,6 @@ LL | //! Linking to [foo@banana] and [`bar@banana!()`]. | = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators -error: unknown disambiguator `foo` - --> $DIR/unknown-disambiguator.rs:10:34 - | -LL | //! And with weird backticks: [``foo@hello``] [foo`@`hello]. - | ^^^ - | - = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators - -error: unknown disambiguator `foo` - --> $DIR/unknown-disambiguator.rs:10:48 - | -LL | //! And with weird backticks: [``foo@hello``] [foo`@`hello]. - | ^^^ - | - = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators - error: unknown disambiguator `` --> $DIR/unknown-disambiguator.rs:7:31 | @@ -52,5 +36,21 @@ LL | //! And to [no disambiguator](@nectarine) and [another](@apricot!()). | = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators +error: unknown disambiguator `foo` + --> $DIR/unknown-disambiguator.rs:10:34 + | +LL | //! And with weird backticks: [``foo@hello``] [foo`@`hello]. + | ^^^ + | + = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators + +error: unknown disambiguator `foo` + --> $DIR/unknown-disambiguator.rs:10:48 + | +LL | //! And with weird backticks: [``foo@hello``] [foo`@`hello]. + | ^^^ + | + = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators + error: aborting due to 6 previous errors From 97e73eea84e8302ae08f88645538ee27485770d6 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 18 Feb 2023 14:56:31 +0400 Subject: [PATCH 3/3] doc links: Filter away autolinks in both rustc and rustdoc --- compiler/rustc_resolve/src/rustdoc.rs | 21 +++++++++++++++++++-- src/librustdoc/html/markdown.rs | 24 ++++++++---------------- 2 files changed, 27 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_resolve/src/rustdoc.rs b/compiler/rustc_resolve/src/rustdoc.rs index be49fbfaa29..0c4b4bc3f62 100644 --- a/compiler/rustc_resolve/src/rustdoc.rs +++ b/compiler/rustc_resolve/src/rustdoc.rs @@ -1,4 +1,4 @@ -use pulldown_cmark::{BrokenLink, Event, Options, Parser, Tag}; +use pulldown_cmark::{BrokenLink, Event, LinkType, Options, Parser, Tag}; use rustc_ast as ast; use rustc_ast::util::comments::beautify_doc_string; use rustc_data_structures::fx::FxHashMap; @@ -347,6 +347,21 @@ fn preprocess_link(link: &str) -> String { strip_generics_from_path(link).unwrap_or_else(|_| link.to_string()) } +/// Keep inline and reference links `[]`, +/// but skip autolinks `<>` which we never consider to be intra-doc links. +pub fn may_be_doc_link(link_type: LinkType) -> bool { + match link_type { + LinkType::Inline + | LinkType::Reference + | LinkType::ReferenceUnknown + | LinkType::Collapsed + | LinkType::CollapsedUnknown + | LinkType::Shortcut + | LinkType::ShortcutUnknown => true, + LinkType::Autolink | LinkType::Email => false, + } +} + /// Simplified version of `preprocessed_markdown_links` from rustdoc. /// Must return at least the same links as it, but may add some more links on top of that. pub(crate) fn attrs_to_preprocessed_links(attrs: &[ast::Attribute]) -> Vec { @@ -359,7 +374,9 @@ pub(crate) fn attrs_to_preprocessed_links(attrs: &[ast::Attribute]) -> Vec| Some((link.reference, "".into()))), ) .filter_map(|event| match event { - Event::Start(Tag::Link(_, dest, _)) => Some(preprocess_link(&dest)), + Event::Start(Tag::Link(link_type, dest, _)) if may_be_doc_link(link_type) => { + Some(preprocess_link(&dest)) + } _ => None, }) .collect() diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index a34628991b2..9ef0b501c08 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -29,6 +29,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_hir::def_id::DefId; use rustc_middle::ty::TyCtxt; pub(crate) use rustc_resolve::rustdoc::main_body_opts; +use rustc_resolve::rustdoc::may_be_doc_link; use rustc_span::edition::Edition; use rustc_span::{Span, Symbol}; @@ -1269,22 +1270,13 @@ pub(crate) fn markdown_links( ) .into_offset_iter() .filter_map(|(event, span)| match event { - Event::Start(Tag::Link( - // `<>` links cannot be intra-doc links so we skip them. - kind @ (LinkType::Inline - | LinkType::Reference - | LinkType::ReferenceUnknown - | LinkType::Collapsed - | LinkType::CollapsedUnknown - | LinkType::Shortcut - | LinkType::ShortcutUnknown), - dest, - _, - )) => preprocess_link(MarkdownLink { - kind, - range: span_for_link(&dest, span), - link: dest.into_string(), - }), + Event::Start(Tag::Link(link_type, dest, _)) if may_be_doc_link(link_type) => { + preprocess_link(MarkdownLink { + kind: link_type, + range: span_for_link(&dest, span), + link: dest.into_string(), + }) + } _ => None, }) .collect()