@@ -19,7 +19,7 @@ use rustc_resolve::ParentScope;
1919use rustc_session:: lint:: Lint ;
2020use rustc_span:: hygiene:: { MacroKind , SyntaxContext } ;
2121use rustc_span:: symbol:: { sym, Ident , Symbol } ;
22- use rustc_span:: DUMMY_SP ;
22+ use rustc_span:: { BytePos , DUMMY_SP } ;
2323use smallvec:: { smallvec, SmallVec } ;
2424
2525use pulldown_cmark:: LinkType ;
@@ -1193,16 +1193,20 @@ impl LinkCollector<'_, '_> {
11931193 let report_mismatch = |specified : Disambiguator , resolved : Disambiguator | {
11941194 // The resolved item did not match the disambiguator; give a better error than 'not found'
11951195 let msg = format ! ( "incompatible link kind for `{}`" , path_str) ;
1196- let callback = |diag : & mut DiagnosticBuilder < ' _ > , sp| {
1196+ let callback = |diag : & mut DiagnosticBuilder < ' _ > , sp : Option < rustc_span :: Span > | {
11971197 let note = format ! (
11981198 "this link resolved to {} {}, which is not {} {}" ,
11991199 resolved. article( ) ,
12001200 resolved. descr( ) ,
12011201 specified. article( ) ,
12021202 specified. descr( )
12031203 ) ;
1204- diag. note ( & note) ;
1205- suggest_disambiguator ( resolved, diag, path_str, dox, sp, & ori_link. range ) ;
1204+ if let Some ( sp) = sp {
1205+ diag. span_label ( sp, & note) ;
1206+ } else {
1207+ diag. note ( & note) ;
1208+ }
1209+ suggest_disambiguator ( resolved, diag, path_str, & ori_link. link , sp) ;
12061210 } ;
12071211 report_diagnostic ( self . cx . tcx , BROKEN_INTRA_DOC_LINKS , & msg, & diag_info, callback) ;
12081212 } ;
@@ -1699,6 +1703,51 @@ impl Suggestion {
16991703 Self :: RemoveDisambiguator => path_str. into ( ) ,
17001704 }
17011705 }
1706+
1707+ fn as_help_span (
1708+ & self ,
1709+ path_str : & str ,
1710+ ori_link : & str ,
1711+ sp : rustc_span:: Span ,
1712+ ) -> Vec < ( rustc_span:: Span , String ) > {
1713+ let inner_sp = match ori_link. find ( '(' ) {
1714+ Some ( index) => sp. with_hi ( sp. lo ( ) + BytePos ( index as _ ) ) ,
1715+ None => sp,
1716+ } ;
1717+ let inner_sp = match ori_link. find ( '!' ) {
1718+ Some ( index) => inner_sp. with_hi ( inner_sp. lo ( ) + BytePos ( index as _ ) ) ,
1719+ None => inner_sp,
1720+ } ;
1721+ let inner_sp = match ori_link. find ( '@' ) {
1722+ Some ( index) => inner_sp. with_lo ( inner_sp. lo ( ) + BytePos ( index as u32 + 1 ) ) ,
1723+ None => inner_sp,
1724+ } ;
1725+ match self {
1726+ Self :: Prefix ( prefix) => {
1727+ // FIXME: if this is an implied shortcut link, it's bad style to suggest `@`
1728+ let mut sugg = vec ! [ ( sp. with_hi( inner_sp. lo( ) ) , format!( "{}@" , prefix) ) ] ;
1729+ if sp. hi ( ) != inner_sp. hi ( ) {
1730+ sugg. push ( ( inner_sp. shrink_to_hi ( ) . with_hi ( sp. hi ( ) ) , String :: new ( ) ) ) ;
1731+ }
1732+ sugg
1733+ }
1734+ Self :: Function => {
1735+ let mut sugg = vec ! [ ( inner_sp. shrink_to_hi( ) . with_hi( sp. hi( ) ) , "()" . to_string( ) ) ] ;
1736+ if sp. lo ( ) != inner_sp. lo ( ) {
1737+ sugg. push ( ( inner_sp. shrink_to_lo ( ) . with_lo ( sp. lo ( ) ) , String :: new ( ) ) ) ;
1738+ }
1739+ sugg
1740+ }
1741+ Self :: Macro => {
1742+ let mut sugg = vec ! [ ( inner_sp. shrink_to_hi( ) , "!" . to_string( ) ) ] ;
1743+ if sp. lo ( ) != inner_sp. lo ( ) {
1744+ sugg. push ( ( inner_sp. shrink_to_lo ( ) . with_lo ( sp. lo ( ) ) , String :: new ( ) ) ) ;
1745+ }
1746+ sugg
1747+ }
1748+ Self :: RemoveDisambiguator => return vec ! [ ( sp, path_str. into( ) ) ] ,
1749+ }
1750+ }
17021751}
17031752
17041753/// Reports a diagnostic for an intra-doc link.
@@ -1732,7 +1781,16 @@ fn report_diagnostic(
17321781 tcx. struct_span_lint_hir ( lint, hir_id, sp, |lint| {
17331782 let mut diag = lint. build ( msg) ;
17341783
1735- let span = super :: source_span_for_markdown_range ( tcx, dox, link_range, & item. attrs ) ;
1784+ let span =
1785+ super :: source_span_for_markdown_range ( tcx, dox, link_range, & item. attrs ) . map ( |sp| {
1786+ if dox. bytes ( ) . nth ( link_range. start ) == Some ( b'`' )
1787+ && dox. bytes ( ) . nth ( link_range. end - 1 ) == Some ( b'`' )
1788+ {
1789+ sp. with_lo ( sp. lo ( ) + BytePos ( 1 ) ) . with_hi ( sp. hi ( ) - BytePos ( 1 ) )
1790+ } else {
1791+ sp
1792+ }
1793+ } ) ;
17361794
17371795 if let Some ( sp) = span {
17381796 diag. set_span ( sp) ;
@@ -1938,9 +1996,8 @@ fn resolution_failure(
19381996 disambiguator,
19391997 diag,
19401998 path_str,
1941- diag_info. dox ,
1999+ diag_info. ori_link ,
19422000 sp,
1943- & diag_info. link_range ,
19442001 )
19452002 }
19462003
@@ -2007,7 +2064,7 @@ fn anchor_failure(cx: &DocContext<'_>, diag_info: DiagnosticInfo<'_>, failure: A
20072064 if let Some ( ( fragment_offset, _) ) =
20082065 diag_info. ori_link . char_indices ( ) . filter ( |( _, x) | * x == '#' ) . nth ( anchor_idx)
20092066 {
2010- sp = sp. with_lo ( sp. lo ( ) + rustc_span :: BytePos ( fragment_offset as _ ) ) ;
2067+ sp = sp. with_lo ( sp. lo ( ) + BytePos ( fragment_offset as _ ) ) ;
20112068 }
20122069 diag. span_label ( sp, "invalid anchor" ) ;
20132070 }
@@ -2075,14 +2132,7 @@ fn ambiguity_error(
20752132
20762133 for res in candidates {
20772134 let disambiguator = Disambiguator :: from_res ( res) ;
2078- suggest_disambiguator (
2079- disambiguator,
2080- diag,
2081- path_str,
2082- diag_info. dox ,
2083- sp,
2084- & diag_info. link_range ,
2085- ) ;
2135+ suggest_disambiguator ( disambiguator, diag, path_str, diag_info. ori_link , sp) ;
20862136 }
20872137 } ) ;
20882138}
@@ -2093,21 +2143,20 @@ fn suggest_disambiguator(
20932143 disambiguator : Disambiguator ,
20942144 diag : & mut DiagnosticBuilder < ' _ > ,
20952145 path_str : & str ,
2096- dox : & str ,
2146+ ori_link : & str ,
20972147 sp : Option < rustc_span:: Span > ,
2098- link_range : & Range < usize > ,
20992148) {
21002149 let suggestion = disambiguator. suggestion ( ) ;
21012150 let help = format ! ( "to link to the {}, {}" , disambiguator. descr( ) , suggestion. descr( ) ) ;
21022151
21032152 if let Some ( sp) = sp {
2104- let msg = if dox. bytes ( ) . nth ( link_range. start ) == Some ( b'`' ) {
2105- format ! ( "`{}`" , suggestion. as_help( path_str) )
2153+ let mut spans = suggestion. as_help_span ( path_str, ori_link, sp) ;
2154+ if spans. len ( ) > 1 {
2155+ diag. multipart_suggestion ( & help, spans, Applicability :: MaybeIncorrect ) ;
21062156 } else {
2107- suggestion. as_help ( path_str)
2108- } ;
2109-
2110- diag. span_suggestion ( sp, & help, msg, Applicability :: MaybeIncorrect ) ;
2157+ let ( sp, suggestion_text) = spans. pop ( ) . unwrap ( ) ;
2158+ diag. span_suggestion_verbose ( sp, & help, suggestion_text, Applicability :: MaybeIncorrect ) ;
2159+ }
21112160 } else {
21122161 diag. help ( & format ! ( "{}: {}" , help, suggestion. as_help( path_str) ) ) ;
21132162 }
0 commit comments