about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2018-06-03 23:04:11 +0000
committerbors <bors@rust-lang.org>2018-06-03 23:04:11 +0000
commit01a9b30c332810ad0c570e8fed91f956417dec3a (patch)
tree24881a8e56e8ee763cf5ebaec19e09a1fbaedc01
parent29f48ccf396be031ee8a54e74a3a4e81866c8872 (diff)
parent2886aca232361519a1a8c142b2c670fed1bd03b6 (diff)
downloadrust-01a9b30c332810ad0c570e8fed91f956417dec3a.tar.gz
rust-01a9b30c332810ad0c570e8fed91f956417dec3a.zip
Auto merge of #51111 - kennytm:intralink-resolution-failure-line-numbers, r=GuillaumeGomez
Point to the rustdoc attribute where intralink resolution failed.
-rw-r--r--src/librustdoc/clean/mod.rs58
-rw-r--r--src/librustdoc/html/markdown.rs25
-rw-r--r--src/librustdoc/lib.rs1
-rw-r--r--src/test/rustdoc-ui/intra-links-warning.rs4
-rw-r--r--src/test/rustdoc-ui/intra-links-warning.stderr33
5 files changed, 108 insertions, 13 deletions
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index a57f3a42939..1c1ba208678 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -57,6 +57,7 @@ use std::rc::Rc;
 use std::cell::RefCell;
 use std::sync::Arc;
 use std::u32;
+use std::ops::Range;
 
 use core::{self, DocContext};
 use doctree;
@@ -954,12 +955,20 @@ fn type_ns_kind(def: Def, path_str: &str) -> (&'static str, &'static str, String
     (kind, article, format!("{}@{}", kind, path_str))
 }
 
+fn span_of_attrs(attrs: &Attributes) -> syntax_pos::Span {
+    if attrs.doc_strings.is_empty() {
+        return DUMMY_SP;
+    }
+    let start = attrs.doc_strings[0].span();
+    let end = attrs.doc_strings.last().unwrap().span();
+    start.to(end)
+}
+
 fn ambiguity_error(cx: &DocContext, attrs: &Attributes,
                    path_str: &str,
                    article1: &str, kind1: &str, disambig1: &str,
                    article2: &str, kind2: &str, disambig2: &str) {
-    let sp = attrs.doc_strings.first()
-                  .map_or(DUMMY_SP, |a| a.span());
+    let sp = span_of_attrs(attrs);
     cx.sess()
       .struct_span_warn(sp,
                         &format!("`{}` is both {} {} and {} {}",
@@ -1174,8 +1183,39 @@ enum PathKind {
     Type,
 }
 
-fn resolution_failure(cx: &DocContext, path_str: &str) {
-    cx.sess().warn(&format!("[{}] cannot be resolved, ignoring it...", path_str));
+fn resolution_failure(
+    cx: &DocContext,
+    attrs: &Attributes,
+    path_str: &str,
+    dox: &str,
+    link_range: Option<Range<usize>>,
+) {
+    let sp = span_of_attrs(attrs);
+    let mut diag = cx.sess()
+        .struct_span_warn(sp, &format!("[{}] cannot be resolved, ignoring it...", path_str));
+
+    if let Some(link_range) = link_range {
+        // blah blah blah\nblah\nblah [blah] blah blah\nblah blah
+        //                       ^    ~~~~~~
+        //                       |    link_range
+        //                       last_new_line_offset
+
+        let last_new_line_offset = dox[..link_range.start].rfind('\n').map_or(0, |n| n + 1);
+        let line = dox[last_new_line_offset..].lines().next().unwrap_or("");
+
+        // Print the line containing the `link_range` and manually mark it with '^'s
+        diag.note(&format!(
+            "the link appears in this line:\n\n{line}\n{indicator: <before$}{indicator:^<found$}",
+            line=line,
+            indicator="",
+            before=link_range.start - last_new_line_offset,
+            found=link_range.len(),
+        ));
+    } else {
+
+    }
+
+    diag.emit();
 }
 
 impl Clean<Attributes> for [ast::Attribute] {
@@ -1184,7 +1224,7 @@ impl Clean<Attributes> for [ast::Attribute] {
 
         if UnstableFeatures::from_environment().is_nightly_build() {
             let dox = attrs.collapsed_doc_value().unwrap_or_else(String::new);
-            for ori_link in markdown_links(&dox) {
+            for (ori_link, link_range) in markdown_links(&dox) {
                 // bail early for real links
                 if ori_link.contains('/') {
                     continue;
@@ -1228,7 +1268,7 @@ impl Clean<Attributes> for [ast::Attribute] {
                             if let Ok(def) = resolve(cx, path_str, true) {
                                 def
                             } else {
-                                resolution_failure(cx, path_str);
+                                resolution_failure(cx, &attrs, path_str, &dox, link_range);
                                 // this could just be a normal link or a broken link
                                 // we could potentially check if something is
                                 // "intra-doc-link-like" and warn in that case
@@ -1239,7 +1279,7 @@ impl Clean<Attributes> for [ast::Attribute] {
                             if let Ok(def) = resolve(cx, path_str, false) {
                                 def
                             } else {
-                                resolution_failure(cx, path_str);
+                                resolution_failure(cx, &attrs, path_str, &dox, link_range);
                                 // this could just be a normal link
                                 continue;
                             }
@@ -1284,7 +1324,7 @@ impl Clean<Attributes> for [ast::Attribute] {
                             } else if let Ok(value_def) = resolve(cx, path_str, true) {
                                 value_def
                             } else {
-                                resolution_failure(cx, path_str);
+                                resolution_failure(cx, &attrs, path_str, &dox, link_range);
                                 // this could just be a normal link
                                 continue;
                             }
@@ -1293,7 +1333,7 @@ impl Clean<Attributes> for [ast::Attribute] {
                             if let Some(def) = macro_resolve(cx, path_str) {
                                 (def, None)
                             } else {
-                                resolution_failure(cx, path_str);
+                                resolution_failure(cx, &attrs, path_str, &dox, link_range);
                                 continue
                             }
                         }
diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs
index c09bd4cc84a..7088104cd7a 100644
--- a/src/librustdoc/html/markdown.rs
+++ b/src/librustdoc/html/markdown.rs
@@ -32,6 +32,8 @@ use std::cell::RefCell;
 use std::collections::{HashMap, VecDeque};
 use std::default::Default;
 use std::fmt::{self, Write};
+use std::borrow::Cow;
+use std::ops::Range;
 use std::str;
 use syntax::feature_gate::UnstableFeatures;
 use syntax::codemap::Span;
@@ -747,7 +749,7 @@ pub fn plain_summary_line(md: &str) -> String {
     s
 }
 
-pub fn markdown_links(md: &str) -> Vec<String> {
+pub fn markdown_links(md: &str) -> Vec<(String, Option<Range<usize>>)> {
     if md.is_empty() {
         return vec![];
     }
@@ -760,8 +762,22 @@ pub fn markdown_links(md: &str) -> Vec<String> {
     let shortcut_links = RefCell::new(vec![]);
 
     {
+        let locate = |s: &str| unsafe {
+            let s_start = s.as_ptr();
+            let s_end = s_start.add(s.len());
+            let md_start = md.as_ptr();
+            let md_end = md_start.add(md.len());
+            if md_start <= s_start && s_end <= md_end {
+                let start = s_start.offset_from(md_start) as usize;
+                let end = s_end.offset_from(md_start) as usize;
+                Some(start..end)
+            } else {
+                None
+            }
+        };
+
         let push = |_: &str, s: &str| {
-            shortcut_links.borrow_mut().push(s.to_owned());
+            shortcut_links.borrow_mut().push((s.to_owned(), locate(s)));
             None
         };
         let p = Parser::new_with_broken_link_callback(md, opts,
@@ -772,7 +788,10 @@ pub fn markdown_links(md: &str) -> Vec<String> {
         for ev in iter {
             if let Event::Start(Tag::Link(dest, _)) = ev {
                 debug!("found link: {}", dest);
-                links.push(dest.into_owned());
+                links.push(match dest {
+                    Cow::Borrowed(s) => (s.to_owned(), locate(s)),
+                    Cow::Owned(s) => (s, None),
+                });
             }
         }
     }
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index 1b713a446a0..97c84d8348f 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -23,6 +23,7 @@
 #![feature(test)]
 #![feature(vec_remove_item)]
 #![feature(entry_and_modify)]
+#![feature(ptr_offset_from)]
 
 #![recursion_limit="256"]
 
diff --git a/src/test/rustdoc-ui/intra-links-warning.rs b/src/test/rustdoc-ui/intra-links-warning.rs
index 2a00d31e3d7..830aaabf9d2 100644
--- a/src/test/rustdoc-ui/intra-links-warning.rs
+++ b/src/test/rustdoc-ui/intra-links-warning.rs
@@ -10,7 +10,9 @@
 
 // compile-pass
 
-//! Test with [Foo::baz], [Bar::foo], [Uniooon::X]
+//! Test with [Foo::baz], [Bar::foo], ...
+//!
+//! and [Uniooon::X].
 
 pub struct Foo {
     pub bar: usize,
diff --git a/src/test/rustdoc-ui/intra-links-warning.stderr b/src/test/rustdoc-ui/intra-links-warning.stderr
index 67d7bdd02b3..1e8e9f04c26 100644
--- a/src/test/rustdoc-ui/intra-links-warning.stderr
+++ b/src/test/rustdoc-ui/intra-links-warning.stderr
@@ -1,6 +1,39 @@
 warning: [Foo::baz] cannot be resolved, ignoring it...
+  --> $DIR/intra-links-warning.rs:13:1
+   |
+13 | / //! Test with [Foo::baz], [Bar::foo], ...
+14 | | //!
+15 | | //! and [Uniooon::X].
+   | |_____________________^
+   |
+   = note: the link appears in this line:
+           
+            Test with [Foo::baz], [Bar::foo], ...
+                       ^^^^^^^^
 
 warning: [Bar::foo] cannot be resolved, ignoring it...
+  --> $DIR/intra-links-warning.rs:13:1
+   |
+13 | / //! Test with [Foo::baz], [Bar::foo], ...
+14 | | //!
+15 | | //! and [Uniooon::X].
+   | |_____________________^
+   |
+   = note: the link appears in this line:
+           
+            Test with [Foo::baz], [Bar::foo], ...
+                                   ^^^^^^^^
 
 warning: [Uniooon::X] cannot be resolved, ignoring it...
+  --> $DIR/intra-links-warning.rs:13:1
+   |
+13 | / //! Test with [Foo::baz], [Bar::foo], ...
+14 | | //!
+15 | | //! and [Uniooon::X].
+   | |_____________________^
+   |
+   = note: the link appears in this line:
+           
+            and [Uniooon::X].
+                 ^^^^^^^^^^