1
1
use errors:: Applicability ;
2
- use rustc:: hir:: def:: Def ;
2
+ use rustc:: hir:: def:: { Def , Namespace :: { self , * } , PerNS } ;
3
3
use rustc:: hir:: def_id:: DefId ;
4
4
use rustc:: hir;
5
5
use rustc:: lint as lint;
@@ -36,46 +36,24 @@ pub fn collect_intra_doc_links(krate: Crate, cx: &DocContext<'_>) -> Crate {
36
36
}
37
37
}
38
38
39
- #[ derive( Debug ) ]
40
- enum PathKind {
41
- /// Either a value or type, but not a macro
42
- Unknown ,
43
- /// Macro
44
- Macro ,
45
- /// Values, functions, consts, statics (everything in the value namespace)
46
- Value ,
47
- /// Types, traits (everything in the type namespace)
48
- Type ,
49
- }
50
-
51
39
struct LinkCollector < ' a , ' tcx > {
52
40
cx : & ' a DocContext < ' tcx > ,
53
41
mod_ids : Vec < ast:: NodeId > ,
54
- is_nightly_build : bool ,
55
- }
56
-
57
- #[ derive( Debug , Copy , Clone ) ]
58
- enum Namespace {
59
- Type ,
60
- Value ,
61
- Macro ,
62
42
}
63
43
64
44
impl < ' a , ' tcx > LinkCollector < ' a , ' tcx > {
65
45
fn new ( cx : & ' a DocContext < ' tcx > ) -> Self {
66
46
LinkCollector {
67
47
cx,
68
48
mod_ids : Vec :: new ( ) ,
69
- is_nightly_build : UnstableFeatures :: from_environment ( ) . is_nightly_build ( ) ,
70
49
}
71
50
}
72
51
73
- /// Resolves a given string as a path, along with whether or not it is
74
- /// in the value namespace. Also returns an optional URL fragment in the case
75
- /// of variants and methods.
52
+ /// Resolves a string as a path within a particular namespace. Also returns an optional
53
+ /// URL fragment in the case of variants and methods.
76
54
fn resolve ( & self ,
77
55
path_str : & str ,
78
- is_val : bool ,
56
+ ns : Namespace ,
79
57
current_item : & Option < String > ,
80
58
parent_id : Option < ast:: NodeId > )
81
59
-> Result < ( Def , Option < String > ) , ( ) >
@@ -86,11 +64,11 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
86
64
// path.
87
65
if let Some ( id) = parent_id. or ( self . mod_ids . last ( ) . cloned ( ) ) {
88
66
// FIXME: `with_scope` requires the `NodeId` of a module.
89
- let result = cx. enter_resolver ( |resolver| resolver . with_scope ( id ,
90
- |resolver| {
91
- resolver. resolve_str_path_error ( DUMMY_SP ,
92
- & path_str , is_val )
93
- } ) ) ;
67
+ let result = cx. enter_resolver ( |resolver| {
68
+ resolver . with_scope ( id , |resolver| {
69
+ resolver. resolve_str_path_error ( DUMMY_SP , & path_str , ns == ValueNS )
70
+ } )
71
+ } ) ;
94
72
95
73
if let Ok ( result) = result {
96
74
// In case this is a trait item, skip the
@@ -103,16 +81,16 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
103
81
_ => return Ok ( ( result. def , None ) )
104
82
} ;
105
83
106
- if value != is_val {
84
+ if value != ( ns == ValueNS ) {
107
85
return Err ( ( ) )
108
86
}
109
- } else if let Some ( prim) = is_primitive ( path_str, is_val ) {
87
+ } else if let Some ( prim) = is_primitive ( path_str, ns ) {
110
88
return Ok ( ( prim, Some ( path_str. to_owned ( ) ) ) )
111
89
} else {
112
90
// If resolution failed, it may still be a method
113
91
// because methods are not handled by the resolver
114
92
// If so, bail when we're not looking for a value.
115
- if !is_val {
93
+ if ns != ValueNS {
116
94
return Err ( ( ) )
117
95
}
118
96
}
@@ -136,7 +114,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
136
114
path = name. clone ( ) ;
137
115
}
138
116
}
139
- if let Some ( prim) = is_primitive ( & path, false ) {
117
+ if let Some ( prim) = is_primitive ( & path, TypeNS ) {
140
118
let did = primitive_impl ( cx, & path) . ok_or ( ( ) ) ?;
141
119
return cx. tcx . associated_items ( did)
142
120
. find ( |item| item. ident . name == item_name)
@@ -160,8 +138,8 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
160
138
. find ( |item| item. ident . name == item_name) ;
161
139
if let Some ( item) = item {
162
140
let out = match item. kind {
163
- ty:: AssociatedKind :: Method if is_val => "method" ,
164
- ty:: AssociatedKind :: Const if is_val => "associatedconstant" ,
141
+ ty:: AssociatedKind :: Method if ns == ValueNS => "method" ,
142
+ ty:: AssociatedKind :: Const if ns == ValueNS => "associatedconstant" ,
165
143
_ => return Err ( ( ) )
166
144
} ;
167
145
Ok ( ( ty. def , Some ( format ! ( "{}.{}" , out, item_name) ) ) )
@@ -198,9 +176,9 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
198
176
. find ( |item| item. ident . name == item_name) ;
199
177
if let Some ( item) = item {
200
178
let kind = match item. kind {
201
- ty:: AssociatedKind :: Const if is_val => "associatedconstant" ,
202
- ty:: AssociatedKind :: Type if !is_val => "associatedtype" ,
203
- ty:: AssociatedKind :: Method if is_val => {
179
+ ty:: AssociatedKind :: Const if ns == ValueNS => "associatedconstant" ,
180
+ ty:: AssociatedKind :: Type if ns == TypeNS => "associatedtype" ,
181
+ ty:: AssociatedKind :: Method if ns == ValueNS => {
204
182
if item. defaultness . has_value ( ) {
205
183
"method"
206
184
} else {
@@ -287,39 +265,35 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
287
265
288
266
look_for_tests ( & cx, & dox, & item, true ) ;
289
267
290
- if !self . is_nightly_build {
291
- return None ;
292
- }
293
-
294
268
for ( ori_link, link_range) in markdown_links ( & dox) {
295
269
// Bail early for real links.
296
270
if ori_link. contains ( '/' ) {
297
271
continue ;
298
272
}
299
273
let link = ori_link. replace ( "`" , "" ) ;
300
274
let ( def, fragment) = {
301
- let mut kind = PathKind :: Unknown ;
275
+ let mut kind = None ;
302
276
let path_str = if let Some ( prefix) =
303
277
[ "struct@" , "enum@" , "type@" ,
304
278
"trait@" , "union@" ] . iter ( )
305
279
. find ( |p| link. starts_with ( * * p) ) {
306
- kind = PathKind :: Type ;
280
+ kind = Some ( TypeNS ) ;
307
281
link. trim_start_matches ( prefix)
308
282
} else if let Some ( prefix) =
309
283
[ "const@" , "static@" ,
310
284
"value@" , "function@" , "mod@" ,
311
285
"fn@" , "module@" , "method@" ]
312
286
. iter ( ) . find ( |p| link. starts_with ( * * p) ) {
313
- kind = PathKind :: Value ;
287
+ kind = Some ( ValueNS ) ;
314
288
link. trim_start_matches ( prefix)
315
289
} else if link. ends_with ( "()" ) {
316
- kind = PathKind :: Value ;
290
+ kind = Some ( ValueNS ) ;
317
291
link. trim_end_matches ( "()" )
318
292
} else if link. starts_with ( "macro@" ) {
319
- kind = PathKind :: Macro ;
293
+ kind = Some ( MacroNS ) ;
320
294
link. trim_start_matches ( "macro@" )
321
295
} else if link. ends_with ( '!' ) {
322
- kind = PathKind :: Macro ;
296
+ kind = Some ( MacroNS ) ;
323
297
link. trim_end_matches ( '!' )
324
298
} else {
325
299
& link[ ..]
@@ -331,8 +305,8 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
331
305
}
332
306
333
307
match kind {
334
- PathKind :: Value => {
335
- if let Ok ( def) = self . resolve ( path_str, true , & current_item, parent_node) {
308
+ Some ( ns @ ValueNS ) => {
309
+ if let Ok ( def) = self . resolve ( path_str, ns , & current_item, parent_node) {
336
310
def
337
311
} else {
338
312
resolution_failure ( cx, & item. attrs , path_str, & dox, link_range) ;
@@ -342,66 +316,58 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
342
316
continue ;
343
317
}
344
318
}
345
- PathKind :: Type => {
346
- if let Ok ( def) = self . resolve ( path_str, false , & current_item, parent_node) {
319
+ Some ( ns @ TypeNS ) => {
320
+ if let Ok ( def) = self . resolve ( path_str, ns , & current_item, parent_node) {
347
321
def
348
322
} else {
349
323
resolution_failure ( cx, & item. attrs , path_str, & dox, link_range) ;
350
324
// This could just be a normal link.
351
325
continue ;
352
326
}
353
327
}
354
- PathKind :: Unknown => {
328
+ None => {
355
329
// Try everything!
356
- let mut candidates = vec ! [ ] ;
357
-
358
- if let Some ( macro_def) = macro_resolve ( cx, path_str) {
359
- candidates. push ( ( ( macro_def, None ) , Namespace :: Macro ) ) ;
360
- }
361
-
362
- if let Ok ( type_def) =
363
- self . resolve ( path_str, false , & current_item, parent_node)
364
- {
365
- candidates. push ( ( type_def, Namespace :: Type ) ) ;
366
- }
367
-
368
- if let Ok ( value_def) =
369
- self . resolve ( path_str, true , & current_item, parent_node)
370
- {
371
- // Structs, variants, and mods exist in both namespaces, skip them.
372
- match value_def. 0 {
373
- Def :: StructCtor ( ..)
374
- | Def :: Mod ( ..)
375
- | Def :: Variant ( ..)
376
- | Def :: VariantCtor ( ..)
377
- | Def :: SelfCtor ( ..) => ( ) ,
378
- _ => candidates. push ( ( value_def, Namespace :: Value ) ) ,
379
- }
380
- }
330
+ let candidates = PerNS {
331
+ macro_ns : macro_resolve ( cx, path_str) . map ( |def| ( def, None ) ) ,
332
+ type_ns : self
333
+ . resolve ( path_str, TypeNS , & current_item, parent_node)
334
+ . ok ( ) ,
335
+ value_ns : self
336
+ . resolve ( path_str, ValueNS , & current_item, parent_node)
337
+ . ok ( )
338
+ . and_then ( |( def, fragment) | {
339
+ // Constructors are picked up in the type namespace.
340
+ match def {
341
+ Def :: StructCtor ( ..)
342
+ | Def :: VariantCtor ( ..)
343
+ | Def :: SelfCtor ( ..) => None ,
344
+ _ => Some ( ( def, fragment) )
345
+ }
346
+ } ) ,
347
+ } ;
381
348
382
- if candidates. len ( ) == 1 {
383
- candidates. remove ( 0 ) . 0
384
- } else if candidates. is_empty ( ) {
349
+ if candidates. is_empty ( ) {
385
350
resolution_failure ( cx, & item. attrs , path_str, & dox, link_range) ;
386
351
// this could just be a normal link
387
352
continue ;
388
- } else {
389
- let candidates = candidates. into_iter ( ) . map ( |( ( def, _) , ns) | {
390
- ( def, ns)
391
- } ) . collect :: < Vec < _ > > ( ) ;
353
+ }
392
354
355
+ let is_unambiguous = candidates. clone ( ) . present_items ( ) . count ( ) == 1 ;
356
+ if is_unambiguous {
357
+ candidates. present_items ( ) . next ( ) . unwrap ( )
358
+ } else {
393
359
ambiguity_error (
394
360
cx,
395
361
& item. attrs ,
396
362
path_str,
397
363
& dox,
398
364
link_range,
399
- & candidates,
365
+ candidates. map ( |candidate| candidate . map ( | ( def , _ ) | def ) ) ,
400
366
) ;
401
367
continue ;
402
368
}
403
369
}
404
- PathKind :: Macro => {
370
+ Some ( MacroNS ) => {
405
371
if let Some ( def) = macro_resolve ( cx, path_str) {
406
372
( def, None )
407
373
} else {
@@ -514,13 +480,16 @@ fn ambiguity_error(
514
480
path_str : & str ,
515
481
dox : & str ,
516
482
link_range : Option < Range < usize > > ,
517
- candidates : & [ ( Def , Namespace ) ] ,
483
+ candidates : PerNS < Option < Def > > ,
518
484
) {
519
485
let sp = span_of_attrs ( attrs) ;
520
486
521
487
let mut msg = format ! ( "`{}` is " , path_str) ;
522
488
523
- match candidates {
489
+ let candidates = [ TypeNS , ValueNS , MacroNS ] . iter ( ) . filter_map ( |& ns| {
490
+ candidates[ ns] . map ( |def| ( def, ns) )
491
+ } ) . collect :: < Vec < _ > > ( ) ;
492
+ match candidates. as_slice ( ) {
524
493
[ ( first_def, _) , ( second_def, _) ] => {
525
494
msg += & format ! (
526
495
"both {} {} and {} {}" ,
@@ -568,9 +537,9 @@ fn ambiguity_error(
568
537
( Def :: Union ( ..) , _) => "union" ,
569
538
( Def :: Trait ( ..) , _) => "trait" ,
570
539
( Def :: Mod ( ..) , _) => "module" ,
571
- ( _, Namespace :: Type ) => "type" ,
572
- ( _, Namespace :: Value ) => "value" ,
573
- ( _, Namespace :: Macro ) => "macro" ,
540
+ ( _, TypeNS ) => "type" ,
541
+ ( _, ValueNS ) => "value" ,
542
+ ( _, MacroNS ) => "macro" ,
574
543
} ;
575
544
576
545
// FIXME: if this is an implied shortcut link, it's bad style to suggest `@`
@@ -646,11 +615,11 @@ const PRIMITIVES: &[(&str, Def)] = &[
646
615
( "char" , Def :: PrimTy ( hir:: PrimTy :: Char ) ) ,
647
616
] ;
648
617
649
- fn is_primitive ( path_str : & str , is_val : bool ) -> Option < Def > {
650
- if is_val {
651
- None
652
- } else {
618
+ fn is_primitive ( path_str : & str , ns : Namespace ) -> Option < Def > {
619
+ if ns == TypeNS {
653
620
PRIMITIVES . iter ( ) . find ( |x| x. 0 == path_str) . map ( |x| x. 1 )
621
+ } else {
622
+ None
654
623
}
655
624
}
656
625
0 commit comments