@@ -659,7 +659,8 @@ pub struct Attributes {
659
659
pub other_attrs : Vec < ast:: Attribute > ,
660
660
pub cfg : Option < Rc < Cfg > > ,
661
661
pub span : Option < syntax_pos:: Span > ,
662
- pub links : Vec < ( String , DefId ) > ,
662
+ /// map from Rust paths to resolved defs and potential URL fragments
663
+ pub links : Vec < ( String , DefId , Option < String > ) > ,
663
664
}
664
665
665
666
impl Attributes {
@@ -820,8 +821,12 @@ impl Attributes {
820
821
/// Cache must be populated before call
821
822
pub fn links ( & self ) -> Vec < ( String , String ) > {
822
823
use html:: format:: href;
823
- self . links . iter ( ) . filter_map ( |& ( ref s, did) | {
824
- if let Some ( ( href, ..) ) = href ( did) {
824
+ self . links . iter ( ) . filter_map ( |& ( ref s, did, ref fragment) | {
825
+ if let Some ( ( mut href, ..) ) = href ( did) {
826
+ if let Some ( ref fragment) = * fragment {
827
+ href. push_str ( "#" ) ;
828
+ href. push_str ( fragment) ;
829
+ }
825
830
Some ( ( s. clone ( ) , href) )
826
831
} else {
827
832
None
@@ -843,10 +848,8 @@ impl AttributesExt for Attributes {
843
848
/// they exist in both namespaces (structs and modules)
844
849
fn value_ns_kind ( def : Def , path_str : & str ) -> Option < ( & ' static str , String ) > {
845
850
match def {
846
- // structs and mods exist in both namespaces. skip them
847
- Def :: StructCtor ( ..) | Def :: Mod ( ..) => None ,
848
- Def :: Variant ( ..) | Def :: VariantCtor ( ..)
849
- => Some ( ( "variant" , format ! ( "{}()" , path_str) ) ) ,
851
+ // structs, variants, and mods exist in both namespaces. skip them
852
+ Def :: StructCtor ( ..) | Def :: Mod ( ..) | Def :: Variant ( ..) | Def :: VariantCtor ( ..) => None ,
850
853
Def :: Fn ( ..)
851
854
=> Some ( ( "function" , format ! ( "{}()" , path_str) ) ) ,
852
855
Def :: Method ( ..)
@@ -880,10 +883,10 @@ fn ambiguity_error(cx: &DocContext, attrs: &Attributes,
880
883
let sp = attrs. doc_strings . first ( )
881
884
. map_or ( DUMMY_SP , |a| a. span ( ) ) ;
882
885
cx. sess ( )
883
- . struct_span_err ( sp,
884
- & format ! ( "`{}` is both {} {} and {} {}" ,
885
- path_str, article1, kind1,
886
- article2, kind2) )
886
+ . struct_span_warn ( sp,
887
+ & format ! ( "`{}` is both {} {} and {} {}" ,
888
+ path_str, article1, kind1,
889
+ article2, kind2) )
887
890
. help ( & format ! ( "try `{}` if you want to select the {}, \
888
891
or `{}` if you want to \
889
892
select the {}",
@@ -892,21 +895,114 @@ fn ambiguity_error(cx: &DocContext, attrs: &Attributes,
892
895
. emit ( ) ;
893
896
}
894
897
898
+ /// Given an enum variant's def, return the def of its enum and the associated fragment
899
+ fn handle_variant ( cx : & DocContext , def : Def ) -> Result < ( Def , Option < String > ) , ( ) > {
900
+ use rustc:: ty:: DefIdTree ;
901
+
902
+ let parent = if let Some ( parent) = cx. tcx . parent ( def. def_id ( ) ) {
903
+ parent
904
+ } else {
905
+ return Err ( ( ) )
906
+ } ;
907
+ let parent_def = Def :: Enum ( parent) ;
908
+ let variant = cx. tcx . expect_variant_def ( def) ;
909
+ Ok ( ( parent_def, Some ( format ! ( "{}.v" , variant. name) ) ) )
910
+ }
911
+
895
912
/// Resolve a given string as a path, along with whether or not it is
896
- /// in the value namespace
897
- fn resolve ( cx : & DocContext , path_str : & str , is_val : bool ) -> Result < hir:: Path , ( ) > {
913
+ /// in the value namespace. Also returns an optional URL fragment in the case
914
+ /// of variants and methods
915
+ fn resolve ( cx : & DocContext , path_str : & str , is_val : bool ) -> Result < ( Def , Option < String > ) , ( ) > {
898
916
// In case we're in a module, try to resolve the relative
899
917
// path
900
918
if let Some ( id) = cx. mod_ids . borrow ( ) . last ( ) {
901
- cx. resolver . borrow_mut ( )
902
- . with_scope ( * id, |resolver| {
903
- resolver. resolve_str_path_error ( DUMMY_SP ,
904
- & path_str, is_val)
905
- } )
919
+ let result = cx. resolver . borrow_mut ( )
920
+ . with_scope ( * id,
921
+ |resolver| {
922
+ resolver. resolve_str_path_error ( DUMMY_SP ,
923
+ & path_str, is_val)
924
+ } ) ;
925
+
926
+ if let Ok ( result) = result {
927
+ // In case this is a trait item, skip the
928
+ // early return and try looking for the trait
929
+ let value = match result. def {
930
+ Def :: Method ( _) | Def :: AssociatedConst ( _) => true ,
931
+ Def :: AssociatedTy ( _) => false ,
932
+ Def :: Variant ( _) => return handle_variant ( cx, result. def ) ,
933
+ // not a trait item, just return what we found
934
+ _ => return Ok ( ( result. def , None ) )
935
+ } ;
936
+
937
+ if value != is_val {
938
+ return Err ( ( ) )
939
+ }
940
+ } else {
941
+ // If resolution failed, it may still be a method
942
+ // because methods are not handled by the resolver
943
+ // If so, bail when we're not looking for a value
944
+ if !is_val {
945
+ return Err ( ( ) )
946
+ }
947
+ }
948
+
949
+ // Try looking for methods and associated items
950
+ let mut split = path_str. rsplitn ( 2 , "::" ) ;
951
+ let mut item_name = if let Some ( first) = split. next ( ) {
952
+ first
953
+ } else {
954
+ return Err ( ( ) )
955
+ } ;
956
+
957
+ let mut path = if let Some ( second) = split. next ( ) {
958
+ second
959
+ } else {
960
+ return Err ( ( ) )
961
+ } ;
962
+
963
+ let ty = cx. resolver . borrow_mut ( )
964
+ . with_scope ( * id,
965
+ |resolver| {
966
+ resolver. resolve_str_path_error ( DUMMY_SP ,
967
+ & path, false )
968
+ } ) ?;
969
+ match ty. def {
970
+ Def :: Struct ( did) | Def :: Union ( did) | Def :: Enum ( did) | Def :: TyAlias ( did) => {
971
+ let item = cx. tcx . inherent_impls ( did) . iter ( )
972
+ . flat_map ( |imp| cx. tcx . associated_items ( * imp) )
973
+ . find ( |item| item. name == item_name) ;
974
+ if let Some ( item) = item {
975
+ if item. kind == ty:: AssociatedKind :: Method && is_val {
976
+ Ok ( ( ty. def , Some ( format ! ( "method.{}" , item_name) ) ) )
977
+ } else {
978
+ Err ( ( ) )
979
+ }
980
+ } else {
981
+ Err ( ( ) )
982
+ }
983
+ }
984
+ Def :: Trait ( did) => {
985
+ let item = cx. tcx . associated_item_def_ids ( did) . iter ( )
986
+ . map ( |item| cx. tcx . associated_item ( * item) )
987
+ . find ( |item| item. name == item_name) ;
988
+ if let Some ( item) = item {
989
+ let kind = match item. kind {
990
+ ty:: AssociatedKind :: Const if is_val => "associatedconstant" ,
991
+ ty:: AssociatedKind :: Type if !is_val => "associatedtype" ,
992
+ ty:: AssociatedKind :: Method if is_val => "tymethod" ,
993
+ _ => return Err ( ( ) )
994
+ } ;
995
+
996
+ Ok ( ( ty. def , Some ( format ! ( "{}.{}" , kind, item_name) ) ) )
997
+ } else {
998
+ Err ( ( ) )
999
+ }
1000
+ }
1001
+ _ => Err ( ( ) )
1002
+ }
1003
+
906
1004
} else {
907
- // FIXME(Manishearth) this branch doesn't seem to ever be hit, really
908
- cx. resolver . borrow_mut ( )
909
- . resolve_str_path_error ( DUMMY_SP , & path_str, is_val)
1005
+ Err ( ( ) )
910
1006
}
911
1007
}
912
1008
@@ -955,7 +1051,7 @@ impl Clean<Attributes> for [ast::Attribute] {
955
1051
if UnstableFeatures :: from_environment ( ) . is_nightly_build ( ) {
956
1052
let dox = attrs. collapsed_doc_value ( ) . unwrap_or_else ( String :: new) ;
957
1053
for link in markdown_links ( & dox, cx. render_type ) {
958
- let def = {
1054
+ let ( def, fragment ) = {
959
1055
let mut kind = PathKind :: Unknown ;
960
1056
let path_str = if let Some ( prefix) =
961
1057
[ "struct@" , "enum@" , "type@" ,
@@ -965,7 +1061,8 @@ impl Clean<Attributes> for [ast::Attribute] {
965
1061
link. trim_left_matches ( prefix)
966
1062
} else if let Some ( prefix) =
967
1063
[ "const@" , "static@" ,
968
- "value@" , "function@" , "mod@" , "fn@" , "module@" ]
1064
+ "value@" , "function@" , "mod@" ,
1065
+ "fn@" , "module@" , "method@" ]
969
1066
. iter ( ) . find ( |p| link. starts_with ( * * p) ) {
970
1067
kind = PathKind :: Value ;
971
1068
link. trim_left_matches ( prefix)
@@ -993,8 +1090,8 @@ impl Clean<Attributes> for [ast::Attribute] {
993
1090
994
1091
match kind {
995
1092
PathKind :: Value => {
996
- if let Ok ( path ) = resolve ( cx, path_str, true ) {
997
- path . def
1093
+ if let Ok ( def ) = resolve ( cx, path_str, true ) {
1094
+ def
998
1095
} else {
999
1096
// this could just be a normal link or a broken link
1000
1097
// we could potentially check if something is
@@ -1003,8 +1100,8 @@ impl Clean<Attributes> for [ast::Attribute] {
1003
1100
}
1004
1101
}
1005
1102
PathKind :: Type => {
1006
- if let Ok ( path ) = resolve ( cx, path_str, false ) {
1007
- path . def
1103
+ if let Ok ( def ) = resolve ( cx, path_str, false ) {
1104
+ def
1008
1105
} else {
1009
1106
// this could just be a normal link
1010
1107
continue ;
@@ -1013,50 +1110,50 @@ impl Clean<Attributes> for [ast::Attribute] {
1013
1110
PathKind :: Unknown => {
1014
1111
// try everything!
1015
1112
if let Some ( macro_def) = macro_resolve ( cx, path_str) {
1016
- if let Ok ( type_path ) = resolve ( cx, path_str, false ) {
1113
+ if let Ok ( type_def ) = resolve ( cx, path_str, false ) {
1017
1114
let ( type_kind, article, type_disambig)
1018
- = type_ns_kind ( type_path . def , path_str) ;
1115
+ = type_ns_kind ( type_def . 0 , path_str) ;
1019
1116
ambiguity_error ( cx, & attrs, path_str,
1020
1117
article, type_kind, & type_disambig,
1021
1118
"a" , "macro" , & format ! ( "macro@{}" , path_str) ) ;
1022
1119
continue ;
1023
- } else if let Ok ( value_path ) = resolve ( cx, path_str, true ) {
1120
+ } else if let Ok ( value_def ) = resolve ( cx, path_str, true ) {
1024
1121
let ( value_kind, value_disambig)
1025
- = value_ns_kind ( value_path . def , path_str)
1122
+ = value_ns_kind ( value_def . 0 , path_str)
1026
1123
. expect ( "struct and mod cases should have been \
1027
1124
caught in previous branch") ;
1028
1125
ambiguity_error ( cx, & attrs, path_str,
1029
1126
"a" , value_kind, & value_disambig,
1030
1127
"a" , "macro" , & format ! ( "macro@{}" , path_str) ) ;
1031
1128
}
1032
- macro_def
1033
- } else if let Ok ( type_path ) = resolve ( cx, path_str, false ) {
1129
+ ( macro_def, None )
1130
+ } else if let Ok ( type_def ) = resolve ( cx, path_str, false ) {
1034
1131
// It is imperative we search for not-a-value first
1035
1132
// Otherwise we will find struct ctors for when we are looking
1036
1133
// for structs, and the link won't work.
1037
1134
// if there is something in both namespaces
1038
- if let Ok ( value_path ) = resolve ( cx, path_str, true ) {
1039
- let kind = value_ns_kind ( value_path . def , path_str) ;
1135
+ if let Ok ( value_def ) = resolve ( cx, path_str, true ) {
1136
+ let kind = value_ns_kind ( value_def . 0 , path_str) ;
1040
1137
if let Some ( ( value_kind, value_disambig) ) = kind {
1041
1138
let ( type_kind, article, type_disambig)
1042
- = type_ns_kind ( type_path . def , path_str) ;
1139
+ = type_ns_kind ( type_def . 0 , path_str) ;
1043
1140
ambiguity_error ( cx, & attrs, path_str,
1044
1141
article, type_kind, & type_disambig,
1045
1142
"a" , value_kind, & value_disambig) ;
1046
1143
continue ;
1047
1144
}
1048
1145
}
1049
- type_path . def
1050
- } else if let Ok ( value_path ) = resolve ( cx, path_str, true ) {
1051
- value_path . def
1146
+ type_def
1147
+ } else if let Ok ( value_def ) = resolve ( cx, path_str, true ) {
1148
+ value_def
1052
1149
} else {
1053
1150
// this could just be a normal link
1054
1151
continue ;
1055
1152
}
1056
1153
}
1057
1154
PathKind :: Macro => {
1058
1155
if let Some ( def) = macro_resolve ( cx, path_str) {
1059
- def
1156
+ ( def, None )
1060
1157
} else {
1061
1158
continue
1062
1159
}
@@ -1066,7 +1163,7 @@ impl Clean<Attributes> for [ast::Attribute] {
1066
1163
1067
1164
1068
1165
let id = register_def ( cx, def) ;
1069
- attrs. links . push ( ( link, id) ) ;
1166
+ attrs. links . push ( ( link, id, fragment ) ) ;
1070
1167
}
1071
1168
1072
1169
cx. sess ( ) . abort_if_errors ( ) ;
0 commit comments