use std::cell::RefCell;
use std::sync::Arc;
use std::u32;
+use std::ops::Range;
use core::{self, DocContext};
use doctree;
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] {
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;
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
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;
}
} 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;
}
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
}
}
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;
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![];
}
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,
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),
+ });
}
}
}
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
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
14 | | //!
15 | | //! and [Uniooon::X].
| |_____________________^
+ |
+ = note: the link appears in this line:
+
+ and [Uniooon::X].
+ ^^^^^^^^^^