@@ -68,7 +68,7 @@ impl<'a> From<ResolutionFailure<'a>> for ErrorKind<'a> {
6868}
6969
7070#[ derive( Copy , Clone , Debug , Hash ) ]
71- enum Res {
71+ crate enum Res {
7272 Def ( DefKind , DefId ) ,
7373 Primitive ( PrimitiveType ) ,
7474}
@@ -134,7 +134,7 @@ impl TryFrom<ResolveRes> for Res {
134134
135135/// A link failed to resolve.
136136#[ derive( Debug ) ]
137- enum ResolutionFailure < ' a > {
137+ crate enum ResolutionFailure < ' a > {
138138 /// This resolved, but with the wrong namespace.
139139 WrongNamespace {
140140 /// What the link resolved to.
@@ -172,7 +172,7 @@ enum ResolutionFailure<'a> {
172172}
173173
174174#[ derive( Debug ) ]
175- enum MalformedGenerics {
175+ crate enum MalformedGenerics {
176176 /// This link has unbalanced angle brackets.
177177 ///
178178 /// For example, `Vec<T` should trigger this, as should `Vec<T>>`.
@@ -224,7 +224,7 @@ impl ResolutionFailure<'a> {
224224 }
225225}
226226
227- enum AnchorFailure {
227+ crate enum AnchorFailure {
228228 /// User error: `[std#x#y]` is not valid
229229 MultipleAnchors ,
230230 /// The anchor provided by the user conflicts with Rustdoc's generated anchor.
@@ -892,6 +892,117 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
892892 }
893893}
894894
895+ crate enum PreprocessingError < ' a > {
896+ Anchor ( AnchorFailure ) ,
897+ Disambiguator ( Range < usize > , String ) ,
898+ Resolution ( ResolutionFailure < ' a > , String , Option < Disambiguator > ) ,
899+ }
900+
901+ impl From < AnchorFailure > for PreprocessingError < ' _ > {
902+ fn from ( err : AnchorFailure ) -> Self {
903+ Self :: Anchor ( err)
904+ }
905+ }
906+
907+ crate struct PreprocessingInfo {
908+ crate path_str : String ,
909+ disambiguator : Option < Disambiguator > ,
910+ extra_fragment : Option < String > ,
911+ link_text : String ,
912+ }
913+
914+ /// Returns:
915+ /// - `None` if the link should be ignored.
916+ /// - `Some(Err)` if the link should emit an error
917+ /// - `Some(Ok)` if the link is valid
918+ ///
919+ /// `link_buffer` is needed for lifetime reasons; it will always be overwritten and the contents ignored.
920+ crate fn preprocess_link < ' a > (
921+ ori_link : & ' a MarkdownLink ,
922+ ) -> Option < Result < PreprocessingInfo , PreprocessingError < ' a > > > {
923+ // [] is mostly likely not supposed to be a link
924+ if ori_link. link . is_empty ( ) {
925+ return None ;
926+ }
927+
928+ // Bail early for real links.
929+ if ori_link. link . contains ( '/' ) {
930+ return None ;
931+ }
932+
933+ let stripped = ori_link. link . replace ( "`" , "" ) ;
934+ let mut parts = stripped. split ( '#' ) ;
935+
936+ let link = parts. next ( ) . unwrap ( ) ;
937+ if link. trim ( ) . is_empty ( ) {
938+ // This is an anchor to an element of the current page, nothing to do in here!
939+ return None ;
940+ }
941+ let extra_fragment = parts. next ( ) ;
942+ if parts. next ( ) . is_some ( ) {
943+ // A valid link can't have multiple #'s
944+ return Some ( Err ( AnchorFailure :: MultipleAnchors . into ( ) ) ) ;
945+ }
946+
947+ // Parse and strip the disambiguator from the link, if present.
948+ let ( path_str, disambiguator) = match Disambiguator :: from_str ( & link) {
949+ Ok ( Some ( ( d, path) ) ) => ( path. trim ( ) , Some ( d) ) ,
950+ Ok ( None ) => ( link. trim ( ) , None ) ,
951+ Err ( ( err_msg, relative_range) ) => {
952+ // Only report error if we would not have ignored this link. See issue #83859.
953+ if !should_ignore_link_with_disambiguators ( link) {
954+ let no_backticks_range = range_between_backticks ( & ori_link) ;
955+ let disambiguator_range = ( no_backticks_range. start + relative_range. start )
956+ ..( no_backticks_range. start + relative_range. end ) ;
957+ return Some ( Err ( PreprocessingError :: Disambiguator ( disambiguator_range, err_msg) ) ) ;
958+ } else {
959+ return None ;
960+ }
961+ }
962+ } ;
963+
964+ if should_ignore_link ( path_str) {
965+ return None ;
966+ }
967+
968+ // We stripped `()` and `!` when parsing the disambiguator.
969+ // Add them back to be displayed, but not prefix disambiguators.
970+ let link_text =
971+ disambiguator. map ( |d| d. display_for ( path_str) ) . unwrap_or_else ( || path_str. to_owned ( ) ) ;
972+
973+ // Strip generics from the path.
974+ let path_str = if path_str. contains ( [ '<' , '>' ] . as_slice ( ) ) {
975+ match strip_generics_from_path ( & path_str) {
976+ Ok ( path) => path,
977+ Err ( err_kind) => {
978+ debug ! ( "link has malformed generics: {}" , path_str) ;
979+ return Some ( Err ( PreprocessingError :: Resolution (
980+ err_kind,
981+ path_str. to_owned ( ) ,
982+ disambiguator,
983+ ) ) ) ;
984+ }
985+ }
986+ } else {
987+ path_str. to_owned ( )
988+ } ;
989+
990+ // Sanity check to make sure we don't have any angle brackets after stripping generics.
991+ assert ! ( !path_str. contains( [ '<' , '>' ] . as_slice( ) ) ) ;
992+
993+ // The link is not an intra-doc link if it still contains spaces after stripping generics.
994+ if path_str. contains ( ' ' ) {
995+ return None ;
996+ }
997+
998+ Some ( Ok ( PreprocessingInfo {
999+ path_str,
1000+ disambiguator,
1001+ extra_fragment : extra_fragment. map ( String :: from) ,
1002+ link_text,
1003+ } ) )
1004+ }
1005+
8951006impl LinkCollector < ' _ , ' _ > {
8961007 /// This is the entry point for resolving an intra-doc link.
8971008 ///
@@ -907,64 +1018,36 @@ impl LinkCollector<'_, '_> {
9071018 ) -> Option < ItemLink > {
9081019 trace ! ( "considering link '{}'" , ori_link. link) ;
9091020
910- // Bail early for real links.
911- if ori_link. link . contains ( '/' ) {
912- return None ;
913- }
914-
915- // [] is mostly likely not supposed to be a link
916- if ori_link. link . is_empty ( ) {
917- return None ;
918- }
919-
9201021 let diag_info = DiagnosticInfo {
9211022 item,
9221023 dox,
9231024 ori_link : & ori_link. link ,
9241025 link_range : ori_link. range . clone ( ) ,
9251026 } ;
9261027
927- let link = ori_link. link . replace ( "`" , "" ) ;
928- let no_backticks_range = range_between_backticks ( & ori_link) ;
929- let parts = link. split ( '#' ) . collect :: < Vec < _ > > ( ) ;
930- let ( link, extra_fragment) = if parts. len ( ) > 2 {
931- // A valid link can't have multiple #'s
932- anchor_failure ( self . cx , diag_info, AnchorFailure :: MultipleAnchors ) ;
933- return None ;
934- } else if parts. len ( ) == 2 {
935- if parts[ 0 ] . trim ( ) . is_empty ( ) {
936- // This is an anchor to an element of the current page, nothing to do in here!
937- return None ;
938- }
939- ( parts[ 0 ] , Some ( parts[ 1 ] . to_owned ( ) ) )
940- } else {
941- ( parts[ 0 ] , None )
942- } ;
943-
944- // Parse and strip the disambiguator from the link, if present.
945- let ( mut path_str, disambiguator) = match Disambiguator :: from_str ( & link) {
946- Ok ( Some ( ( d, path) ) ) => ( path. trim ( ) , Some ( d) ) ,
947- Ok ( None ) => ( link. trim ( ) , None ) ,
948- Err ( ( err_msg, relative_range) ) => {
949- if !should_ignore_link_with_disambiguators ( link) {
950- // Only report error if we would not have ignored this link.
951- // See issue #83859.
952- let disambiguator_range = ( no_backticks_range. start + relative_range. start )
953- ..( no_backticks_range. start + relative_range. end ) ;
954- disambiguator_error ( self . cx , diag_info, disambiguator_range, & err_msg) ;
1028+ let PreprocessingInfo { path_str, disambiguator, extra_fragment, link_text } =
1029+ match preprocess_link ( & ori_link) ? {
1030+ Ok ( x) => x,
1031+ Err ( err) => {
1032+ match err {
1033+ PreprocessingError :: Anchor ( err) => anchor_failure ( self . cx , diag_info, err) ,
1034+ PreprocessingError :: Disambiguator ( range, msg) => {
1035+ disambiguator_error ( self . cx , diag_info, range, & msg)
1036+ }
1037+ PreprocessingError :: Resolution ( err, path_str, disambiguator) => {
1038+ resolution_failure (
1039+ self ,
1040+ diag_info,
1041+ & path_str,
1042+ disambiguator,
1043+ smallvec ! [ err] ,
1044+ ) ;
1045+ }
1046+ }
1047+ return None ;
9551048 }
956- return None ;
957- }
958- } ;
959-
960- if should_ignore_link ( path_str) {
961- return None ;
962- }
963-
964- // We stripped `()` and `!` when parsing the disambiguator.
965- // Add them back to be displayed, but not prefix disambiguators.
966- let link_text =
967- disambiguator. map ( |d| d. display_for ( path_str) ) . unwrap_or_else ( || path_str. to_owned ( ) ) ;
1049+ } ;
1050+ let mut path_str = & * path_str;
9681051
9691052 // In order to correctly resolve intra-doc links we need to
9701053 // pick a base AST node to work from. If the documentation for
@@ -1029,39 +1112,12 @@ impl LinkCollector<'_, '_> {
10291112 module_id = DefId { krate, index : CRATE_DEF_INDEX } ;
10301113 }
10311114
1032- // Strip generics from the path.
1033- let stripped_path_string;
1034- if path_str. contains ( [ '<' , '>' ] . as_slice ( ) ) {
1035- stripped_path_string = match strip_generics_from_path ( path_str) {
1036- Ok ( path) => path,
1037- Err ( err_kind) => {
1038- debug ! ( "link has malformed generics: {}" , path_str) ;
1039- resolution_failure (
1040- self ,
1041- diag_info,
1042- path_str,
1043- disambiguator,
1044- smallvec ! [ err_kind] ,
1045- ) ;
1046- return None ;
1047- }
1048- } ;
1049- path_str = & stripped_path_string;
1050- }
1051- // Sanity check to make sure we don't have any angle brackets after stripping generics.
1052- assert ! ( !path_str. contains( [ '<' , '>' ] . as_slice( ) ) ) ;
1053-
1054- // The link is not an intra-doc link if it still contains spaces after stripping generics.
1055- if path_str. contains ( ' ' ) {
1056- return None ;
1057- }
1058-
10591115 let ( mut res, mut fragment) = self . resolve_with_disambiguator_cached (
10601116 ResolutionInfo {
10611117 module_id,
10621118 dis : disambiguator,
10631119 path_str : path_str. to_owned ( ) ,
1064- extra_fragment,
1120+ extra_fragment : extra_fragment . map ( String :: from ) ,
10651121 } ,
10661122 diag_info. clone ( ) , // this struct should really be Copy, but Range is not :(
10671123 matches ! ( ori_link. kind, LinkType :: Reference | LinkType :: Shortcut ) ,
0 commit comments