about summary refs log tree commit diff
diff options
context:
space:
mode:
authorkennytm <kennytm@gmail.com>2018-06-03 18:22:24 +0800
committerkennytm <kennytm@gmail.com>2018-06-03 18:25:04 +0800
commit2886aca232361519a1a8c142b2c670fed1bd03b6 (patch)
treeee25944905071cdd74d287a54c2b4b6c2fb13c10
parentbc20eb6fbc1109462147fbd5d0680b6015f71e94 (diff)
downloadrust-2886aca232361519a1a8c142b2c670fed1bd03b6.tar.gz
rust-2886aca232361519a1a8c142b2c670fed1bd03b6.zip
Show which line the link is coming from.
-rw-r--r--src/librustdoc/clean/mod.rs45
-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.stderr15
4 files changed, 76 insertions, 10 deletions
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 7c3df329bb7..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;
@@ -1182,9 +1183,39 @@ enum PathKind {
     Type,
 }
 
-fn resolution_failure(cx: &DocContext, attrs: &Attributes, path_str: &str) {
+fn resolution_failure(
+    cx: &DocContext,
+    attrs: &Attributes,
+    path_str: &str,
+    dox: &str,
+    link_range: Option<Range<usize>>,
+) {
     let sp = span_of_attrs(attrs);
-    cx.sess().span_warn(sp, &format!("[{}] cannot be resolved, ignoring it...", path_str));
+    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] {
@@ -1193,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;
@@ -1237,7 +1268,7 @@ impl Clean<Attributes> for [ast::Attribute] {
                             if let Ok(def) = resolve(cx, path_str, true) {
                                 def
                             } else {
-                                resolution_failure(cx, &attrs, 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
@@ -1248,7 +1279,7 @@ impl Clean<Attributes> for [ast::Attribute] {
                             if let Ok(def) = resolve(cx, path_str, false) {
                                 def
                             } else {
-                                resolution_failure(cx, &attrs, path_str);
+                                resolution_failure(cx, &attrs, path_str, &dox, link_range);
                                 // this could just be a normal link
                                 continue;
                             }
@@ -1293,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, &attrs, path_str);
+                                resolution_failure(cx, &attrs, path_str, &dox, link_range);
                                 // this could just be a normal link
                                 continue;
                             }
@@ -1302,7 +1333,7 @@ impl Clean<Attributes> for [ast::Attribute] {
                             if let Some(def) = macro_resolve(cx, path_str) {
                                 (def, None)
                             } else {
-                                resolution_failure(cx, &attrs, 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.stderr b/src/test/rustdoc-ui/intra-links-warning.stderr
index 539ae94c3a9..1e8e9f04c26 100644
--- a/src/test/rustdoc-ui/intra-links-warning.stderr
+++ b/src/test/rustdoc-ui/intra-links-warning.stderr
@@ -5,6 +5,11 @@ warning: [Foo::baz] cannot be resolved, ignoring it...
 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,6 +18,11 @@ warning: [Bar::foo] cannot be resolved, ignoring it...
 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
@@ -21,4 +31,9 @@ warning: [Uniooon::X] cannot be resolved, ignoring it...
 14 | | //!
 15 | | //! and [Uniooon::X].
    | |_____________________^
+   |
+   = note: the link appears in this line:
+           
+            and [Uniooon::X].
+                 ^^^^^^^^^^