about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJoshua Nelson <jyn514@gmail.com>2020-08-25 18:45:57 -0400
committerJoshua Nelson <jyn514@gmail.com>2020-09-05 13:48:19 -0400
commitf2826d9e9bcba3c161812fca893f98b3dc010f19 (patch)
treecfabaf8eca4dd27995477a48ab1ce8dcc711ae4c
parentbb9d1576044020851ff2f528879a41e1ca0b7b5d (diff)
downloadrust-f2826d9e9bcba3c161812fca893f98b3dc010f19.tar.gz
rust-f2826d9e9bcba3c161812fca893f98b3dc010f19.zip
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.
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links.rs30
-rw-r--r--src/test/rustdoc-ui/intra-link-errors.rs5
-rw-r--r--src/test/rustdoc-ui/intra-link-errors.stderr14
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 b35ec2e73cb..098ac13ffe2 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,
+                    &current,
+                    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 33c8d1b3c49..d8d4ebeb60b 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?)
 /// [<invalid syntax>]
 
-// 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 0b9149cd8ea..0275fd692fe 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