@@ -174,7 +174,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
174
174
fn resolve (
175
175
& self ,
176
176
path_str : & str ,
177
- disambiguator : Option < & str > ,
177
+ disambiguator : Option < Disambiguator > ,
178
178
ns : Namespace ,
179
179
current_item : & Option < String > ,
180
180
parent_id : Option < DefId > ,
@@ -214,7 +214,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
214
214
Res :: Def ( DefKind :: Mod , _) => {
215
215
// This resolved to a module, but if we were passed `type@`,
216
216
// we want primitive types to take precedence instead.
217
- if disambiguator == Some ( "type" ) {
217
+ if disambiguator == Some ( Disambiguator :: Namespace ( Namespace :: TypeNS ) ) {
218
218
if let Some ( prim) = is_primitive ( path_str, ns) {
219
219
if extra_fragment. is_some ( ) {
220
220
return Err ( ErrorKind :: AnchorFailure ( AnchorFailure :: Primitive ) ) ;
@@ -575,47 +575,14 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
575
575
} ;
576
576
let resolved_self;
577
577
let mut path_str;
578
- let mut disambiguator = None ;
578
+ let disambiguator;
579
579
let ( res, fragment) = {
580
- let mut kind = None ;
581
- path_str = if let Some ( prefix) =
582
- [ "struct@" , "enum@" , "type@" , "trait@" , "union@" , "module@" , "mod@" ]
583
- . iter ( )
584
- . find ( |p| link. starts_with ( * * p) )
585
- {
586
- kind = Some ( TypeNS ) ;
587
- disambiguator = Some ( & prefix[ ..prefix. len ( ) - 1 ] ) ;
588
- link. trim_start_matches ( prefix)
589
- } else if let Some ( prefix) =
590
- [ "const@" , "static@" , "value@" , "function@" , "fn@" , "method@" ]
591
- . iter ( )
592
- . find ( |p| link. starts_with ( * * p) )
593
- {
594
- kind = Some ( ValueNS ) ;
595
- disambiguator = Some ( & prefix[ ..prefix. len ( ) - 1 ] ) ;
596
- link. trim_start_matches ( prefix)
597
- } else if link. ends_with ( "!()" ) {
598
- kind = Some ( MacroNS ) ;
599
- disambiguator = Some ( "bang" ) ;
600
- link. trim_end_matches ( "!()" )
601
- } else if link. ends_with ( "()" ) {
602
- kind = Some ( ValueNS ) ;
603
- disambiguator = Some ( "fn" ) ;
604
- link. trim_end_matches ( "()" )
605
- } else if link. starts_with ( "macro@" ) {
606
- kind = Some ( MacroNS ) ;
607
- disambiguator = Some ( "macro" ) ;
608
- link. trim_start_matches ( "macro@" )
609
- } else if link. starts_with ( "derive@" ) {
610
- kind = Some ( MacroNS ) ;
611
- disambiguator = Some ( "derive" ) ;
612
- link. trim_start_matches ( "derive@" )
613
- } else if link. ends_with ( '!' ) {
614
- kind = Some ( MacroNS ) ;
615
- disambiguator = Some ( "bang" ) ;
616
- link. trim_end_matches ( '!' )
580
+ path_str = if let Ok ( ( d, path) ) = Disambiguator :: from_str ( & link) {
581
+ disambiguator = Some ( d) ;
582
+ path
617
583
} else {
618
- & link[ ..]
584
+ disambiguator = None ;
585
+ & link
619
586
}
620
587
. trim ( ) ;
621
588
@@ -648,7 +615,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
648
615
}
649
616
}
650
617
651
- match kind {
618
+ match disambiguator . map ( Disambiguator :: ns ) {
652
619
Some ( ns @ ValueNS ) => {
653
620
match self . resolve (
654
621
path_str,
@@ -796,34 +763,31 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
796
763
debug ! ( "saw kind {:?} with disambiguator {:?}" , kind, disambiguator) ;
797
764
// NOTE: this relies on the fact that `''` is never parsed as a disambiguator
798
765
// NOTE: this needs to be kept in sync with the disambiguator parsing
799
- match ( kind, disambiguator. unwrap_or_default ( ) . trim_end_matches ( "@" ) ) {
800
- | ( DefKind :: Struct , "struct" )
801
- | ( DefKind :: Enum , "enum" )
802
- | ( DefKind :: Trait , "trait" )
803
- | ( DefKind :: Union , "union" )
804
- | ( DefKind :: Mod , "mod" | "module" )
805
- | ( DefKind :: Const | DefKind :: ConstParam | DefKind :: AssocConst | DefKind :: AnonConst , "const" )
806
- | ( DefKind :: Static , "static" )
766
+ match ( kind, disambiguator) {
767
+ | ( DefKind :: Const | DefKind :: ConstParam | DefKind :: AssocConst | DefKind :: AnonConst , Some ( Disambiguator :: Kind ( DefKind :: Const ) ) )
807
768
// NOTE: this allows 'method' to mean both normal functions and associated functions
808
769
// This can't cause ambiguity because both are in the same namespace.
809
- | ( DefKind :: Fn | DefKind :: AssocFn , "fn" | "function" | "method" )
810
- | ( DefKind :: Macro ( MacroKind :: Bang ) , "bang" )
811
- | ( DefKind :: Macro ( MacroKind :: Derive ) , "derive" )
770
+ | ( DefKind :: Fn | DefKind :: AssocFn , Some ( Disambiguator :: Kind ( DefKind :: Fn ) ) )
812
771
// These are namespaces; allow anything in the namespace to match
813
- | ( _, "type" | "macro" | "value" )
772
+ | ( _, Some ( Disambiguator :: Namespace ( _ ) ) )
814
773
// If no disambiguator given, allow anything
815
- | ( _, "" )
774
+ | ( _, None )
816
775
// All of these are valid, so do nothing
817
776
=> { }
818
- ( _, disambiguator) => {
777
+ ( _, Some ( Disambiguator :: Kind ( expected) ) ) if kind == expected => { }
778
+ ( _, Some ( expected) ) => {
819
779
// The resolved item did not match the disambiguator; give a better error than 'not found'
820
780
let msg = format ! ( "unresolved link to `{}`" , path_str) ;
821
781
report_diagnostic ( cx, & msg, & item, & dox, link_range, |diag, sp| {
822
- let msg = format ! ( "this link resolved to {} {}, which did not match the disambiguator '{}'" , kind. article( ) , kind. descr( id) , disambiguator) ;
782
+ // HACK(jynelson): by looking at the source I saw the DefId we pass
783
+ // for `expected.descr()` doesn't matter, since it's not a crate
784
+ let note = format ! ( "this link resolved to {} {}, which is not {} {}" , kind. article( ) , kind. descr( id) , expected. article( ) , expected. descr( id) ) ;
785
+ let suggestion = Disambiguator :: display_for ( kind, path_str) ;
786
+ let help_msg = format ! ( "to link to the {}, use its disambiguator" , kind. descr( id) ) ;
787
+ diag. note ( & note) ;
823
788
if let Some ( sp) = sp {
824
- diag. span_note ( sp, & msg) ;
825
- } else {
826
- diag. note ( & msg) ;
789
+ diag. span_suggestion ( sp, & help_msg, suggestion, Applicability :: MaybeIncorrect ) ;
790
+ diag. set_sort_span ( sp) ;
827
791
}
828
792
} ) ;
829
793
continue ;
@@ -879,6 +843,109 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
879
843
}
880
844
}
881
845
846
+ #[ derive( Copy , Clone , Debug , PartialEq , Eq ) ]
847
+ enum Disambiguator {
848
+ Kind ( DefKind ) ,
849
+ Namespace ( Namespace ) ,
850
+ }
851
+
852
+ impl Disambiguator {
853
+ /// (disambiguator, path_str)
854
+ fn from_str ( link : & str ) -> Result < ( Self , & str ) , ( ) > {
855
+ use Disambiguator :: { Kind , Namespace as NS } ;
856
+
857
+ let find_suffix = || {
858
+ let suffixes = [
859
+ ( "!()" , DefKind :: Macro ( MacroKind :: Bang ) ) ,
860
+ ( "()" , DefKind :: Fn ) ,
861
+ ( "!" , DefKind :: Macro ( MacroKind :: Bang ) ) ,
862
+ ] ;
863
+ for & ( suffix, kind) in & suffixes {
864
+ if link. ends_with ( suffix) {
865
+ return Ok ( ( Kind ( kind) , link. trim_end_matches ( suffix) ) ) ;
866
+ }
867
+ }
868
+ Err ( ( ) )
869
+ } ;
870
+
871
+ if let Some ( idx) = link. find ( '@' ) {
872
+ let ( prefix, rest) = link. split_at ( idx) ;
873
+ let d = match prefix {
874
+ "struct" => Kind ( DefKind :: Struct ) ,
875
+ "enum" => Kind ( DefKind :: Enum ) ,
876
+ "trait" => Kind ( DefKind :: Trait ) ,
877
+ "union" => Kind ( DefKind :: Union ) ,
878
+ "module" | "mod" => Kind ( DefKind :: Mod ) ,
879
+ "const" | "constant" => Kind ( DefKind :: Const ) ,
880
+ "static" => Kind ( DefKind :: Static ) ,
881
+ "function" | "fn" | "method" => Kind ( DefKind :: Fn ) ,
882
+ "derive" => Kind ( DefKind :: Macro ( MacroKind :: Derive ) ) ,
883
+ "type" => NS ( Namespace :: TypeNS ) ,
884
+ "value" => NS ( Namespace :: ValueNS ) ,
885
+ "macro" => NS ( Namespace :: MacroNS ) ,
886
+ _ => return find_suffix ( ) ,
887
+ } ;
888
+ Ok ( ( d, & rest[ 1 ..] ) )
889
+ } else {
890
+ find_suffix ( )
891
+ }
892
+ }
893
+
894
+ fn display_for ( kind : DefKind , path_str : & str ) -> String {
895
+ if kind == DefKind :: Macro ( MacroKind :: Bang ) {
896
+ return format ! ( "{}!" , path_str) ;
897
+ }
898
+ let prefix = match kind {
899
+ DefKind :: Struct => "struct" ,
900
+ DefKind :: Enum => "enum" ,
901
+ DefKind :: Trait => "trait" ,
902
+ DefKind :: Union => "union" ,
903
+ DefKind :: Mod => "mod" ,
904
+ DefKind :: Const | DefKind :: ConstParam | DefKind :: AssocConst | DefKind :: AnonConst => {
905
+ "const"
906
+ }
907
+ DefKind :: Static => "static" ,
908
+ DefKind :: Fn | DefKind :: AssocFn => "fn" ,
909
+ DefKind :: Macro ( MacroKind :: Derive ) => "derive" ,
910
+ // Now handle things that don't have a specific disambiguator
911
+ _ => match kind
912
+ . ns ( )
913
+ . expect ( "tried to calculate a disambiguator for a def without a namespace?" )
914
+ {
915
+ Namespace :: TypeNS => "type" ,
916
+ Namespace :: ValueNS => "value" ,
917
+ Namespace :: MacroNS => "macro" ,
918
+ } ,
919
+ } ;
920
+ format ! ( "{}@{}" , prefix, path_str)
921
+ }
922
+
923
+ fn ns ( self ) -> Namespace {
924
+ match self {
925
+ Self :: Namespace ( n) => n,
926
+ Self :: Kind ( k) => {
927
+ k. ns ( ) . expect ( "only DefKinds with a valid namespace can be disambiguators" )
928
+ }
929
+ }
930
+ }
931
+
932
+ fn article ( & self ) -> & ' static str {
933
+ match self {
934
+ Self :: Namespace ( _) => "a" ,
935
+ Self :: Kind ( kind) => kind. article ( ) ,
936
+ }
937
+ }
938
+
939
+ fn descr ( & self , def_id : DefId ) -> & ' static str {
940
+ match self {
941
+ Self :: Namespace ( Namespace :: TypeNS ) => "type" ,
942
+ Self :: Namespace ( Namespace :: ValueNS ) => "value" ,
943
+ Self :: Namespace ( Namespace :: MacroNS ) => "macro" ,
944
+ Self :: Kind ( kind) => kind. descr ( def_id) ,
945
+ }
946
+ }
947
+ }
948
+
882
949
/// Reports a diagnostic for an intra-doc link.
883
950
///
884
951
/// If no link range is provided, or the source span of the link cannot be determined, the span of
0 commit comments