From f2826d9e9bcba3c161812fca893f98b3dc010f19 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Tue, 25 Aug 2020 18:45:57 -0400 Subject: [PATCH] Show the first path segment which failed to resolve. Before, it would arbitrarily pick the third-to-last if the last three or more did not resolve. --- .../passes/collect_intra_doc_links.rs | 30 +++++++++++++++---- src/test/rustdoc-ui/intra-link-errors.rs | 5 ++-- src/test/rustdoc-ui/intra-link-errors.stderr | 14 +++++---- 3 files changed, 36 insertions(+), 13 deletions(-) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index b35ec2e73cb2..098ac13ffe23 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -156,15 +156,35 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { .ok_or(ErrorKind::Resolve(ResolutionFailure::NotInScope( variant_name.to_string().into(), )))?; - let (_, ty_res) = cx + let ty_res = cx .enter_resolver(|resolver| { resolver.resolve_str_path_error(DUMMY_SP, &path, TypeNS, module_id) }) - .map_err(|_| { - ErrorKind::Resolve(ResolutionFailure::NotInScope(path.to_string().into())) - })?; + .map(|(_, res)| res) + .unwrap_or(Res::Err); + // This code only gets hit if three path segments in a row don't get resolved. + // It's a good time to check if _any_ parent of the path gets resolved. + // If so, report it and say the first which failed; if not, say the first path segment didn't resolve. if let Res::Err = ty_res { - return Err(ErrorKind::Resolve(ResolutionFailure::NotInScope(path.to_string().into()))); + let mut current = path.as_str(); + while let Some(parent) = current.rsplitn(2, "::").nth(1) { + current = parent; + if let Some(res) = self.check_full_res( + TypeNS, + ¤t, + Some(module_id), + current_item, + extra_fragment, + ) { + return Err(ErrorKind::Resolve(ResolutionFailure::NoAssocItem( + res, + Symbol::intern(&path), + ))); + } + } + return Err(ErrorKind::Resolve(ResolutionFailure::NotInScope( + current.to_string().into(), + ))); } let ty_res = ty_res.map_id(|_| panic!("unexpected node_id")); match ty_res { diff --git a/src/test/rustdoc-ui/intra-link-errors.rs b/src/test/rustdoc-ui/intra-link-errors.rs index 33c8d1b3c496..d8d4ebeb60bd 100644 --- a/src/test/rustdoc-ui/intra-link-errors.rs +++ b/src/test/rustdoc-ui/intra-link-errors.rs @@ -4,10 +4,9 @@ // FIXME: this should say that it was skipped (maybe an allowed by default lint?) /// [] -// FIXME: this could say which path was the first to not be found (in this case, `path`) /// [path::to::nonexistent::module] //~^ ERROR unresolved link -//~| NOTE no item named `path::to` is in scope +//~| NOTE no item named `path` is in scope //~| HELP to escape /// [std::io::not::here] @@ -44,7 +43,7 @@ /// [S!] //~^ ERROR unresolved link -//~| HELP to link to the struct, use its disambiguator +//~| HELP to link to the struct, prefix with the item kind //~| NOTE this link resolves to the struct `S` pub fn f() {} #[derive(Debug)] diff --git a/src/test/rustdoc-ui/intra-link-errors.stderr b/src/test/rustdoc-ui/intra-link-errors.stderr index 0b9149cd8ea4..0275fd692feb 100644 --- a/src/test/rustdoc-ui/intra-link-errors.stderr +++ b/src/test/rustdoc-ui/intra-link-errors.stderr @@ -9,7 +9,7 @@ note: the lint level is defined here | LL | #![deny(broken_intra_doc_links)] | ^^^^^^^^^^^^^^^^^^^^^^ - = note: no item named `path::to` is in scope + = note: no item named `path` is in scope = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` error: unresolved link to `std::io::not::here` @@ -80,15 +80,19 @@ error: unresolved link to `S` --> $DIR/intra-link-errors.rs:45:6 | LL | /// [S!] - | ^^ help: to link to the struct, use its disambiguator: `struct@S` + | ^^ | = note: this link resolves to the struct `S`, which is not in the macro namespace +help: to link to the struct, prefix with the item kind + | +LL | /// [struct@S] + | ^^^^^^^^ error: unresolved link to `T::g` --> $DIR/intra-link-errors.rs:63:6 | LL | /// [type@T::g] - | ^^^^^^^^^ help: to link to the associated function, use its disambiguator: `T::g()` + | ^^^^^^^^^ help: to link to the associated function, add parentheses: `T::g()` | = note: this link resolves to the associated function `g`, which is not in the type namespace @@ -105,7 +109,7 @@ error: unresolved link to `S::h` --> $DIR/intra-link-errors.rs:55:6 | LL | /// [type@S::h] - | ^^^^^^^^^ help: to link to the associated function, use its disambiguator: `S::h()` + | ^^^^^^^^^ help: to link to the associated function, add parentheses: `S::h()` | = note: this link resolves to the associated function `h`, which is not in the type namespace @@ -113,7 +117,7 @@ error: unresolved link to `m` --> $DIR/intra-link-errors.rs:76:6 | LL | /// [m()] - | ^^^ help: to link to the macro, use its disambiguator: `m!` + | ^^^ help: to link to the macro, add an exclamation mark: `m!` | = note: this link resolves to the macro `m`, which is not in the value namespace