@@ -57,6 +57,7 @@ use std::rc::Rc;
57
57
use std:: cell:: RefCell ;
58
58
use std:: sync:: Arc ;
59
59
use std:: u32;
60
+ use std:: ops:: Range ;
60
61
61
62
use core:: { self , DocContext } ;
62
63
use doctree;
@@ -954,12 +955,20 @@ fn type_ns_kind(def: Def, path_str: &str) -> (&'static str, &'static str, String
954
955
( kind, article, format ! ( "{}@{}" , kind, path_str) )
955
956
}
956
957
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
+
957
967
fn ambiguity_error ( cx : & DocContext , attrs : & Attributes ,
958
968
path_str : & str ,
959
969
article1 : & str , kind1 : & str , disambig1 : & str ,
960
970
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) ;
963
972
cx. sess ( )
964
973
. struct_span_warn ( sp,
965
974
& format ! ( "`{}` is both {} {} and {} {}" ,
@@ -1174,8 +1183,39 @@ enum PathKind {
1174
1183
Type ,
1175
1184
}
1176
1185
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 ( ) ;
1179
1219
}
1180
1220
1181
1221
impl Clean < Attributes > for [ ast:: Attribute ] {
@@ -1184,7 +1224,7 @@ impl Clean<Attributes> for [ast::Attribute] {
1184
1224
1185
1225
if UnstableFeatures :: from_environment ( ) . is_nightly_build ( ) {
1186
1226
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) {
1188
1228
// bail early for real links
1189
1229
if ori_link. contains ( '/' ) {
1190
1230
continue ;
@@ -1228,7 +1268,7 @@ impl Clean<Attributes> for [ast::Attribute] {
1228
1268
if let Ok ( def) = resolve ( cx, path_str, true ) {
1229
1269
def
1230
1270
} else {
1231
- resolution_failure ( cx, path_str) ;
1271
+ resolution_failure ( cx, & attrs , path_str, & dox , link_range ) ;
1232
1272
// this could just be a normal link or a broken link
1233
1273
// we could potentially check if something is
1234
1274
// "intra-doc-link-like" and warn in that case
@@ -1239,7 +1279,7 @@ impl Clean<Attributes> for [ast::Attribute] {
1239
1279
if let Ok ( def) = resolve ( cx, path_str, false ) {
1240
1280
def
1241
1281
} else {
1242
- resolution_failure ( cx, path_str) ;
1282
+ resolution_failure ( cx, & attrs , path_str, & dox , link_range ) ;
1243
1283
// this could just be a normal link
1244
1284
continue ;
1245
1285
}
@@ -1284,7 +1324,7 @@ impl Clean<Attributes> for [ast::Attribute] {
1284
1324
} else if let Ok ( value_def) = resolve ( cx, path_str, true ) {
1285
1325
value_def
1286
1326
} else {
1287
- resolution_failure ( cx, path_str) ;
1327
+ resolution_failure ( cx, & attrs , path_str, & dox , link_range ) ;
1288
1328
// this could just be a normal link
1289
1329
continue ;
1290
1330
}
@@ -1293,7 +1333,7 @@ impl Clean<Attributes> for [ast::Attribute] {
1293
1333
if let Some ( def) = macro_resolve ( cx, path_str) {
1294
1334
( def, None )
1295
1335
} else {
1296
- resolution_failure ( cx, path_str) ;
1336
+ resolution_failure ( cx, & attrs , path_str, & dox , link_range ) ;
1297
1337
continue
1298
1338
}
1299
1339
}
0 commit comments