@@ -34,8 +34,17 @@ use crate::clean::{self, Crate, Item, ItemId, ItemLink, PrimitiveType};
34
34
use crate :: core:: DocContext ;
35
35
use crate :: html:: markdown:: { MarkdownLink , MarkdownLinkRange , markdown_links} ;
36
36
use crate :: lint:: { BROKEN_INTRA_DOC_LINKS , PRIVATE_INTRA_DOC_LINKS } ;
37
+ use crate :: passes:: Pass ;
37
38
use crate :: visit:: DocVisitor ;
38
39
40
+ /// We create an empty pass for `collect_intra_doc_link` so it still listed when displaying
41
+ /// passes list.
42
+ pub ( crate ) const COLLECT_INTRA_DOC_LINKS : Pass = Pass {
43
+ name : "collect-intra-doc-links" ,
44
+ run : |krate : Crate , _: & mut DocContext < ' _ > | krate,
45
+ description : "resolves intra-doc links" ,
46
+ } ;
47
+
39
48
pub ( crate ) fn collect_intra_doc_links < ' a , ' tcx > (
40
49
krate : Crate ,
41
50
cx : & ' a mut DocContext < ' tcx > ,
@@ -247,6 +256,7 @@ pub(crate) struct ResolutionInfo {
247
256
dis : Option < Disambiguator > ,
248
257
path_str : Box < str > ,
249
258
extra_fragment : Option < String > ,
259
+ link_range : MarkdownLinkRange ,
250
260
}
251
261
252
262
#[ derive( Clone , Debug ) ]
@@ -290,7 +300,7 @@ pub(crate) struct LinkCollector<'a, 'tcx> {
290
300
pub ( crate ) cx : & ' a mut DocContext < ' tcx > ,
291
301
/// Cache the resolved links so we can avoid resolving (and emitting errors for) the same link.
292
302
/// The link will be `None` if it could not be resolved (i.e. the error was cached).
293
- pub ( crate ) visited_links : FxHashMap < ResolutionInfo , Option < ( Res , Option < UrlFragment > ) > > ,
303
+ pub ( crate ) visited_links : FxHashMap < ResolutionInfo , Option < Vec < ( Res , Option < UrlFragment > ) > > > ,
294
304
/// These links are ambiguous. We need for the cache to have its paths filled. Unfortunately,
295
305
/// if we run the `LinkCollector` pass after `Cache::populate`, a lot of items that we need
296
306
/// to go through will be removed, making a lot of intra-doc links to not be inferred.
@@ -299,7 +309,7 @@ pub(crate) struct LinkCollector<'a, 'tcx> {
299
309
/// inferring them (if possible).
300
310
///
301
311
/// Key is `(item ID, path str)`.
302
- pub ( crate ) ambiguous_links : FxHashMap < ( ItemId , String ) , AmbiguousLinks > ,
312
+ pub ( crate ) ambiguous_links : FxHashMap < ( ItemId , String ) , Vec < AmbiguousLinks > > ,
303
313
}
304
314
305
315
impl < ' a , ' tcx > LinkCollector < ' a , ' tcx > {
@@ -1079,6 +1089,7 @@ impl LinkCollector<'_, '_> {
1079
1089
dis : disambiguator,
1080
1090
path_str : path_str. clone ( ) ,
1081
1091
extra_fragment : extra_fragment. clone ( ) ,
1092
+ link_range : ori_link. range . clone ( ) ,
1082
1093
} ,
1083
1094
diag_info. clone ( ) , // this struct should really be Copy, but Range is not :(
1084
1095
// For reference-style links we want to report only one error so unsuccessful
@@ -1095,7 +1106,11 @@ impl LinkCollector<'_, '_> {
1095
1106
diag_info : diag_info. into ( ) ,
1096
1107
resolved,
1097
1108
} ;
1098
- self . ambiguous_links . insert ( ( item. item_id , path_str. to_string ( ) ) , links) ;
1109
+
1110
+ self . ambiguous_links
1111
+ . entry ( ( item. item_id , path_str. to_string ( ) ) )
1112
+ . or_default ( )
1113
+ . push ( links) ;
1099
1114
None
1100
1115
} else if let Some ( ( res, fragment) ) = resolved. pop ( ) {
1101
1116
self . compute_link ( res, fragment, path_str, disambiguator, diag_info, link_text)
@@ -1152,51 +1167,60 @@ impl LinkCollector<'_, '_> {
1152
1167
pub ( crate ) fn resolve_ambiguities ( & mut self ) {
1153
1168
let mut ambiguous_links = mem:: take ( & mut self . ambiguous_links ) ;
1154
1169
1155
- for ( ( item_id, path_str) , info) in ambiguous_links. iter_mut ( ) {
1156
- info. resolved . retain ( |( res, _) | match res {
1157
- Res :: Def ( _, def_id) => self . validate_link ( * def_id) ,
1158
- // Primitive types are always valid.
1159
- Res :: Primitive ( _) => true ,
1160
- } ) ;
1161
- let diag_info = info. diag_info . into_info ( ) ;
1162
- match info. resolved . len ( ) {
1163
- 1 => {
1164
- let ( res, fragment) = info. resolved . pop ( ) . unwrap ( ) ;
1165
- if let Some ( link) = self . compute_link (
1166
- res,
1167
- fragment,
1168
- path_str,
1169
- info. disambiguator ,
1170
- diag_info,
1171
- & info. link_text ,
1172
- ) {
1173
- self . save_link ( * item_id, link) ;
1170
+ for ( ( item_id, path_str) , info_items) in ambiguous_links. iter_mut ( ) {
1171
+ for info in info_items {
1172
+ info. resolved . retain ( |( res, _) | match res {
1173
+ Res :: Def ( _, def_id) => self . validate_link ( * def_id) ,
1174
+ // Primitive types are always valid.
1175
+ Res :: Primitive ( _) => true ,
1176
+ } ) ;
1177
+ let diag_info = info. diag_info . into_info ( ) ;
1178
+ match info. resolved . len ( ) {
1179
+ 1 => {
1180
+ let ( res, fragment) = info. resolved . pop ( ) . unwrap ( ) ;
1181
+ if let Some ( link) = self . compute_link (
1182
+ res,
1183
+ fragment,
1184
+ path_str,
1185
+ info. disambiguator ,
1186
+ diag_info,
1187
+ & info. link_text ,
1188
+ ) {
1189
+ self . save_link ( * item_id, link) ;
1190
+ }
1191
+ }
1192
+ 0 => {
1193
+ report_diagnostic (
1194
+ self . cx . tcx ,
1195
+ BROKEN_INTRA_DOC_LINKS ,
1196
+ format ! (
1197
+ "all items matching `{path_str}` are either private or doc(hidden)"
1198
+ ) ,
1199
+ & diag_info,
1200
+ |diag, sp, _| {
1201
+ if let Some ( sp) = sp {
1202
+ diag. span_label ( sp, "unresolved link" ) ;
1203
+ } else {
1204
+ diag. note ( "unresolved link" ) ;
1205
+ }
1206
+ } ,
1207
+ ) ;
1208
+ }
1209
+ _ => {
1210
+ let candidates = info
1211
+ . resolved
1212
+ . iter ( )
1213
+ . map ( |( res, fragment) | {
1214
+ let def_id = if let Some ( UrlFragment :: Item ( def_id) ) = fragment {
1215
+ Some ( * def_id)
1216
+ } else {
1217
+ None
1218
+ } ;
1219
+ ( * res, def_id)
1220
+ } )
1221
+ . collect :: < Vec < _ > > ( ) ;
1222
+ ambiguity_error ( self . cx , & diag_info, path_str, & candidates, true ) ;
1174
1223
}
1175
- }
1176
- 0 => {
1177
- report_diagnostic (
1178
- self . cx . tcx ,
1179
- BROKEN_INTRA_DOC_LINKS ,
1180
- format ! (
1181
- "all items matching `{path_str}` are either private or doc(hidden)"
1182
- ) ,
1183
- & diag_info,
1184
- |diag, sp, _| {
1185
- if let Some ( sp) = sp {
1186
- diag. span_label ( sp, "unresolved link" ) ;
1187
- } else {
1188
- diag. note ( "unresolved link" ) ;
1189
- }
1190
- } ,
1191
- ) ;
1192
- }
1193
- _ => {
1194
- let candidates = info
1195
- . resolved
1196
- . iter ( )
1197
- . map ( |( res, _) | ( * res, res. def_id ( self . cx . tcx ) ) )
1198
- . collect :: < Vec < _ > > ( ) ;
1199
- ambiguity_error ( self . cx , & diag_info, path_str, & candidates, true ) ;
1200
1224
}
1201
1225
}
1202
1226
}
@@ -1387,15 +1411,13 @@ impl LinkCollector<'_, '_> {
1387
1411
diag : DiagnosticInfo < ' _ > ,
1388
1412
// If errors are cached then they are only reported on first occurrence
1389
1413
// which we want in some cases but not in others.
1390
- cache_errors : bool ,
1414
+ _cache_errors : bool ,
1391
1415
// If this call is intended to be recoverable, then pass true to silence.
1392
1416
// This is only recoverable when path is failed to resolved.
1393
1417
recoverable : bool ,
1394
1418
) -> Option < Vec < ( Res , Option < UrlFragment > ) > > {
1395
1419
if let Some ( res) = self . visited_links . get ( & key) {
1396
- if res. is_some ( ) || cache_errors {
1397
- return res. clone ( ) . map ( |r| vec ! [ r] ) ;
1398
- }
1420
+ return res. clone ( ) ;
1399
1421
}
1400
1422
1401
1423
let mut candidates = self . resolve_with_disambiguator ( & key, diag. clone ( ) , recoverable) ;
@@ -1426,25 +1448,24 @@ impl LinkCollector<'_, '_> {
1426
1448
}
1427
1449
1428
1450
let mut resolved = Vec :: with_capacity ( candidates. len ( ) ) ;
1429
- for ( res, def_id) in candidates. as_slice ( ) {
1451
+ for ( res, def_id) in candidates {
1430
1452
let fragment = match ( & key. extra_fragment , def_id) {
1431
1453
( Some ( _) , Some ( def_id) ) => {
1432
- report_anchor_conflict ( self . cx , diag, * def_id) ;
1454
+ report_anchor_conflict ( self . cx , diag, def_id) ;
1433
1455
return None ;
1434
1456
}
1435
1457
( Some ( u_frag) , None ) => Some ( UrlFragment :: UserWritten ( u_frag. clone ( ) ) ) ,
1436
- ( None , Some ( def_id) ) => Some ( UrlFragment :: Item ( * def_id) ) ,
1458
+ ( None , Some ( def_id) ) => Some ( UrlFragment :: Item ( def_id) ) ,
1437
1459
( None , None ) => None ,
1438
1460
} ;
1439
- let r = ( res. clone ( ) , fragment. clone ( ) ) ;
1440
- self . visited_links . insert ( key. clone ( ) , Some ( r. clone ( ) ) ) ;
1441
- resolved. push ( r) ;
1461
+ resolved. push ( ( res, fragment) ) ;
1442
1462
}
1443
1463
1444
- if resolved. is_empty ( ) && cache_errors {
1464
+ if resolved. is_empty ( ) {
1445
1465
self . visited_links . insert ( key, None ) ;
1446
1466
None
1447
1467
} else {
1468
+ self . visited_links . insert ( key. clone ( ) , Some ( resolved. clone ( ) ) ) ;
1448
1469
Some ( resolved)
1449
1470
}
1450
1471
}
0 commit comments