From 07da6fec9d61fc6454f48f7d6451dc9d6ca49c37 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 9 Oct 2024 11:25:38 +0200 Subject: [PATCH] Emit error for ambiguities still not resolved at later stage --- .../passes/collect_intra_doc_links.rs | 42 ++++++++++++------- .../intra-doc/filter-out-private.rs | 13 ++++++ .../intra-doc/filter-out-private.stderr | 22 ++++++++++ 3 files changed, 63 insertions(+), 14 deletions(-) create mode 100644 tests/rustdoc-ui/intra-doc/filter-out-private.rs create mode 100644 tests/rustdoc-ui/intra-doc/filter-out-private.stderr diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index bc02363c991b0..6966a69850869 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -249,7 +249,7 @@ pub(crate) struct ResolutionInfo { extra_fragment: Option, } -#[derive(Clone)] +#[derive(Clone, Debug)] pub(crate) struct DiagnosticInfo<'a> { item: &'a Item, dox: &'a str, @@ -259,6 +259,7 @@ pub(crate) struct DiagnosticInfo<'a> { pub(crate) struct OwnedDiagnosticInfo { item: Item, + dox: String, ori_link: String, link_range: MarkdownLinkRange, } @@ -267,6 +268,7 @@ impl From> for OwnedDiagnosticInfo { fn from(f: DiagnosticInfo<'_>) -> Self { Self { item: f.item.clone(), + dox: f.dox.to_string(), ori_link: f.ori_link.to_string(), link_range: f.link_range.clone(), } @@ -278,7 +280,7 @@ impl OwnedDiagnosticInfo { DiagnosticInfo { item: &self.item, ori_link: &self.ori_link, - dox: "", + dox: &self.dox, link_range: self.link_range.clone(), } } @@ -1156,18 +1158,30 @@ impl LinkCollector<'_, '_> { // Primitive types are always valid. Res::Primitive(_) => true, }); - if info.resolved.len() == 1 { - let (res, fragment) = info.resolved.pop().unwrap(); - let diag_info = info.diag_info.into_info(); - if let Some(link) = self.compute_link( - res, - fragment, - path_str, - info.disambiguator, - diag_info, - &info.link_text, - ) { - self.save_link(*item_id, link); + match info.resolved.len() { + 1 => { + let (res, fragment) = info.resolved.pop().unwrap(); + let diag_info = info.diag_info.into_info(); + if let Some(link) = self.compute_link( + res, + fragment, + path_str, + info.disambiguator, + diag_info, + &info.link_text, + ) { + self.save_link(*item_id, link); + } + } + 0 => {} + _ => { + let diag_info = info.diag_info.into_info(); + let candidates = info + .resolved + .iter() + .map(|(res, _)| (*res, res.def_id(self.cx.tcx))) + .collect::>(); + ambiguity_error(self.cx, &diag_info, path_str, &candidates, true); } } } diff --git a/tests/rustdoc-ui/intra-doc/filter-out-private.rs b/tests/rustdoc-ui/intra-doc/filter-out-private.rs new file mode 100644 index 0000000000000..f481b51dad066 --- /dev/null +++ b/tests/rustdoc-ui/intra-doc/filter-out-private.rs @@ -0,0 +1,13 @@ +// This test ensures that ambiguities resolved at a later stage still emit an error. + +#![deny(rustdoc::broken_intra_doc_links)] +#![crate_name = "foo"] + +pub struct Thing {} + +#[allow(non_snake_case)] +pub fn Thing() {} + +/// Do stuff with [`Thing`]. +//~^ ERROR `Thing` is both a function and a struct +pub fn repro(_: Thing) {} diff --git a/tests/rustdoc-ui/intra-doc/filter-out-private.stderr b/tests/rustdoc-ui/intra-doc/filter-out-private.stderr new file mode 100644 index 0000000000000..1d1830b1f1c37 --- /dev/null +++ b/tests/rustdoc-ui/intra-doc/filter-out-private.stderr @@ -0,0 +1,22 @@ +error: `Thing` is both a function and a struct + --> $DIR/filter-out-private.rs:11:21 + | +LL | /// Do stuff with [`Thing`]. + | ^^^^^ ambiguous link + | +note: the lint level is defined here + --> $DIR/filter-out-private.rs:3:9 + | +LL | #![deny(rustdoc::broken_intra_doc_links)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: to link to the function, add parentheses + | +LL | /// Do stuff with [`Thing()`]. + | ++ +help: to link to the struct, prefix with `struct@` + | +LL | /// Do stuff with [`struct@Thing`]. + | +++++++ + +error: aborting due to 1 previous error +