]> git.lizzy.rs Git - rust.git/commitdiff
Show which line the link is coming from.
authorkennytm <kennytm@gmail.com>
Sun, 3 Jun 2018 10:22:24 +0000 (18:22 +0800)
committerkennytm <kennytm@gmail.com>
Sun, 3 Jun 2018 10:25:04 +0000 (18:25 +0800)
src/librustdoc/clean/mod.rs
src/librustdoc/html/markdown.rs
src/librustdoc/lib.rs
src/test/rustdoc-ui/intra-links-warning.stderr

index 7c3df329bb7027a0c0200bda8cc62026097e5d66..1c1ba208678ed0e418faac4eba8cbd3025321142 100644 (file)
@@ -57,6 +57,7 @@
 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 @@ fn clean(&self, cx: &DocContext) -> Attributes {
 
         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 @@ fn clean(&self, cx: &DocContext) -> Attributes {
                             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 @@ fn clean(&self, cx: &DocContext) -> Attributes {
                             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 @@ fn clean(&self, cx: &DocContext) -> Attributes {
                             } 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 @@ fn clean(&self, cx: &DocContext) -> Attributes {
                             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
                             }
                         }
index c09bd4cc84ae5222714bf7bb514a38d10c4998ec..7088104cd7a31d8b6ee5a6f6baa1ca2b3a5c9cea 100644 (file)
@@ -32,6 +32,8 @@
 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 @@ fn next(&mut self) -> Option<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),
+                });
             }
         }
     }
index 1b713a446a0ec7af0492dae4583d965e95a0b469..97c84d8348f7c0ce6f142dcf29a9a6493beac68a 100644 (file)
@@ -23,6 +23,7 @@
 #![feature(test)]
 #![feature(vec_remove_item)]
 #![feature(entry_and_modify)]
+#![feature(ptr_offset_from)]
 
 #![recursion_limit="256"]
 
index 539ae94c3a9f8bf4df8261991722edb03b51d0a2..1e8e9f04c26ace303e17597274859488e1cee8f9 100644 (file)
@@ -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].
+                 ^^^^^^^^^^