Skip to content

Commit 01a9b30

Browse files
committed
Auto merge of #51111 - kennytm:intralink-resolution-failure-line-numbers, r=GuillaumeGomez
Point to the rustdoc attribute where intralink resolution failed.
2 parents 29f48cc + 2886aca commit 01a9b30

File tree

5 files changed

+108
-13
lines changed

5 files changed

+108
-13
lines changed

src/librustdoc/clean/mod.rs

+49-9
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ use std::rc::Rc;
5757
use std::cell::RefCell;
5858
use std::sync::Arc;
5959
use std::u32;
60+
use std::ops::Range;
6061

6162
use core::{self, DocContext};
6263
use doctree;
@@ -954,12 +955,20 @@ fn type_ns_kind(def: Def, path_str: &str) -> (&'static str, &'static str, String
954955
(kind, article, format!("{}@{}", kind, path_str))
955956
}
956957

958+
fn span_of_attrs(attrs: &Attributes) -> syntax_pos::Span {
959+
if attrs.doc_strings.is_empty() {
960+
return DUMMY_SP;
961+
}
962+
let start = attrs.doc_strings[0].span();
963+
let end = attrs.doc_strings.last().unwrap().span();
964+
start.to(end)
965+
}
966+
957967
fn ambiguity_error(cx: &DocContext, attrs: &Attributes,
958968
path_str: &str,
959969
article1: &str, kind1: &str, disambig1: &str,
960970
article2: &str, kind2: &str, disambig2: &str) {
961-
let sp = attrs.doc_strings.first()
962-
.map_or(DUMMY_SP, |a| a.span());
971+
let sp = span_of_attrs(attrs);
963972
cx.sess()
964973
.struct_span_warn(sp,
965974
&format!("`{}` is both {} {} and {} {}",
@@ -1174,8 +1183,39 @@ enum PathKind {
11741183
Type,
11751184
}
11761185

1177-
fn resolution_failure(cx: &DocContext, path_str: &str) {
1178-
cx.sess().warn(&format!("[{}] cannot be resolved, ignoring it...", path_str));
1186+
fn resolution_failure(
1187+
cx: &DocContext,
1188+
attrs: &Attributes,
1189+
path_str: &str,
1190+
dox: &str,
1191+
link_range: Option<Range<usize>>,
1192+
) {
1193+
let sp = span_of_attrs(attrs);
1194+
let mut diag = cx.sess()
1195+
.struct_span_warn(sp, &format!("[{}] cannot be resolved, ignoring it...", path_str));
1196+
1197+
if let Some(link_range) = link_range {
1198+
// blah blah blah\nblah\nblah [blah] blah blah\nblah blah
1199+
// ^ ~~~~~~
1200+
// | link_range
1201+
// last_new_line_offset
1202+
1203+
let last_new_line_offset = dox[..link_range.start].rfind('\n').map_or(0, |n| n + 1);
1204+
let line = dox[last_new_line_offset..].lines().next().unwrap_or("");
1205+
1206+
// Print the line containing the `link_range` and manually mark it with '^'s
1207+
diag.note(&format!(
1208+
"the link appears in this line:\n\n{line}\n{indicator: <before$}{indicator:^<found$}",
1209+
line=line,
1210+
indicator="",
1211+
before=link_range.start - last_new_line_offset,
1212+
found=link_range.len(),
1213+
));
1214+
} else {
1215+
1216+
}
1217+
1218+
diag.emit();
11791219
}
11801220

11811221
impl Clean<Attributes> for [ast::Attribute] {
@@ -1184,7 +1224,7 @@ impl Clean<Attributes> for [ast::Attribute] {
11841224

11851225
if UnstableFeatures::from_environment().is_nightly_build() {
11861226
let dox = attrs.collapsed_doc_value().unwrap_or_else(String::new);
1187-
for ori_link in markdown_links(&dox) {
1227+
for (ori_link, link_range) in markdown_links(&dox) {
11881228
// bail early for real links
11891229
if ori_link.contains('/') {
11901230
continue;
@@ -1228,7 +1268,7 @@ impl Clean<Attributes> for [ast::Attribute] {
12281268
if let Ok(def) = resolve(cx, path_str, true) {
12291269
def
12301270
} else {
1231-
resolution_failure(cx, path_str);
1271+
resolution_failure(cx, &attrs, path_str, &dox, link_range);
12321272
// this could just be a normal link or a broken link
12331273
// we could potentially check if something is
12341274
// "intra-doc-link-like" and warn in that case
@@ -1239,7 +1279,7 @@ impl Clean<Attributes> for [ast::Attribute] {
12391279
if let Ok(def) = resolve(cx, path_str, false) {
12401280
def
12411281
} else {
1242-
resolution_failure(cx, path_str);
1282+
resolution_failure(cx, &attrs, path_str, &dox, link_range);
12431283
// this could just be a normal link
12441284
continue;
12451285
}
@@ -1284,7 +1324,7 @@ impl Clean<Attributes> for [ast::Attribute] {
12841324
} else if let Ok(value_def) = resolve(cx, path_str, true) {
12851325
value_def
12861326
} else {
1287-
resolution_failure(cx, path_str);
1327+
resolution_failure(cx, &attrs, path_str, &dox, link_range);
12881328
// this could just be a normal link
12891329
continue;
12901330
}
@@ -1293,7 +1333,7 @@ impl Clean<Attributes> for [ast::Attribute] {
12931333
if let Some(def) = macro_resolve(cx, path_str) {
12941334
(def, None)
12951335
} else {
1296-
resolution_failure(cx, path_str);
1336+
resolution_failure(cx, &attrs, path_str, &dox, link_range);
12971337
continue
12981338
}
12991339
}

src/librustdoc/html/markdown.rs

+22-3
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ use std::cell::RefCell;
3232
use std::collections::{HashMap, VecDeque};
3333
use std::default::Default;
3434
use std::fmt::{self, Write};
35+
use std::borrow::Cow;
36+
use std::ops::Range;
3537
use std::str;
3638
use syntax::feature_gate::UnstableFeatures;
3739
use syntax::codemap::Span;
@@ -747,7 +749,7 @@ pub fn plain_summary_line(md: &str) -> String {
747749
s
748750
}
749751

750-
pub fn markdown_links(md: &str) -> Vec<String> {
752+
pub fn markdown_links(md: &str) -> Vec<(String, Option<Range<usize>>)> {
751753
if md.is_empty() {
752754
return vec![];
753755
}
@@ -760,8 +762,22 @@ pub fn markdown_links(md: &str) -> Vec<String> {
760762
let shortcut_links = RefCell::new(vec![]);
761763

762764
{
765+
let locate = |s: &str| unsafe {
766+
let s_start = s.as_ptr();
767+
let s_end = s_start.add(s.len());
768+
let md_start = md.as_ptr();
769+
let md_end = md_start.add(md.len());
770+
if md_start <= s_start && s_end <= md_end {
771+
let start = s_start.offset_from(md_start) as usize;
772+
let end = s_end.offset_from(md_start) as usize;
773+
Some(start..end)
774+
} else {
775+
None
776+
}
777+
};
778+
763779
let push = |_: &str, s: &str| {
764-
shortcut_links.borrow_mut().push(s.to_owned());
780+
shortcut_links.borrow_mut().push((s.to_owned(), locate(s)));
765781
None
766782
};
767783
let p = Parser::new_with_broken_link_callback(md, opts,
@@ -772,7 +788,10 @@ pub fn markdown_links(md: &str) -> Vec<String> {
772788
for ev in iter {
773789
if let Event::Start(Tag::Link(dest, _)) = ev {
774790
debug!("found link: {}", dest);
775-
links.push(dest.into_owned());
791+
links.push(match dest {
792+
Cow::Borrowed(s) => (s.to_owned(), locate(s)),
793+
Cow::Owned(s) => (s, None),
794+
});
776795
}
777796
}
778797
}

src/librustdoc/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#![feature(test)]
2424
#![feature(vec_remove_item)]
2525
#![feature(entry_and_modify)]
26+
#![feature(ptr_offset_from)]
2627

2728
#![recursion_limit="256"]
2829

src/test/rustdoc-ui/intra-links-warning.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@
1010

1111
// compile-pass
1212

13-
//! Test with [Foo::baz], [Bar::foo], [Uniooon::X]
13+
//! Test with [Foo::baz], [Bar::foo], ...
14+
//!
15+
//! and [Uniooon::X].
1416
1517
pub struct Foo {
1618
pub bar: usize,
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,39 @@
11
warning: [Foo::baz] cannot be resolved, ignoring it...
2+
--> $DIR/intra-links-warning.rs:13:1
3+
|
4+
13 | / //! Test with [Foo::baz], [Bar::foo], ...
5+
14 | | //!
6+
15 | | //! and [Uniooon::X].
7+
| |_____________________^
8+
|
9+
= note: the link appears in this line:
10+
11+
Test with [Foo::baz], [Bar::foo], ...
12+
^^^^^^^^
213

314
warning: [Bar::foo] cannot be resolved, ignoring it...
15+
--> $DIR/intra-links-warning.rs:13:1
16+
|
17+
13 | / //! Test with [Foo::baz], [Bar::foo], ...
18+
14 | | //!
19+
15 | | //! and [Uniooon::X].
20+
| |_____________________^
21+
|
22+
= note: the link appears in this line:
23+
24+
Test with [Foo::baz], [Bar::foo], ...
25+
^^^^^^^^
426

527
warning: [Uniooon::X] cannot be resolved, ignoring it...
28+
--> $DIR/intra-links-warning.rs:13:1
29+
|
30+
13 | / //! Test with [Foo::baz], [Bar::foo], ...
31+
14 | | //!
32+
15 | | //! and [Uniooon::X].
33+
| |_____________________^
34+
|
35+
= note: the link appears in this line:
36+
37+
and [Uniooon::X].
38+
^^^^^^^^^^
639

0 commit comments

Comments
 (0)