@@ -19,7 +19,7 @@ use rustc_resolve::ParentScope;
19
19
use rustc_session:: lint:: Lint ;
20
20
use rustc_span:: hygiene:: { MacroKind , SyntaxContext } ;
21
21
use rustc_span:: symbol:: { sym, Ident , Symbol } ;
22
- use rustc_span:: DUMMY_SP ;
22
+ use rustc_span:: { BytePos , DUMMY_SP } ;
23
23
use smallvec:: { smallvec, SmallVec } ;
24
24
25
25
use pulldown_cmark:: LinkType ;
@@ -1193,16 +1193,20 @@ impl LinkCollector<'_, '_> {
1193
1193
let report_mismatch = |specified : Disambiguator , resolved : Disambiguator | {
1194
1194
// The resolved item did not match the disambiguator; give a better error than 'not found'
1195
1195
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 > | {
1197
1197
let note = format ! (
1198
1198
"this link resolved to {} {}, which is not {} {}" ,
1199
1199
resolved. article( ) ,
1200
1200
resolved. descr( ) ,
1201
1201
specified. article( ) ,
1202
1202
specified. descr( )
1203
1203
) ;
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) ;
1206
1210
} ;
1207
1211
report_diagnostic ( self . cx . tcx , BROKEN_INTRA_DOC_LINKS , & msg, & diag_info, callback) ;
1208
1212
} ;
@@ -1699,6 +1703,51 @@ impl Suggestion {
1699
1703
Self :: RemoveDisambiguator => path_str. into ( ) ,
1700
1704
}
1701
1705
}
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
+ }
1702
1751
}
1703
1752
1704
1753
/// Reports a diagnostic for an intra-doc link.
@@ -1732,7 +1781,16 @@ fn report_diagnostic(
1732
1781
tcx. struct_span_lint_hir ( lint, hir_id, sp, |lint| {
1733
1782
let mut diag = lint. build ( msg) ;
1734
1783
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
+ } ) ;
1736
1794
1737
1795
if let Some ( sp) = span {
1738
1796
diag. set_span ( sp) ;
@@ -1938,9 +1996,8 @@ fn resolution_failure(
1938
1996
disambiguator,
1939
1997
diag,
1940
1998
path_str,
1941
- diag_info. dox ,
1999
+ diag_info. ori_link ,
1942
2000
sp,
1943
- & diag_info. link_range ,
1944
2001
)
1945
2002
}
1946
2003
@@ -2007,7 +2064,7 @@ fn anchor_failure(cx: &DocContext<'_>, diag_info: DiagnosticInfo<'_>, failure: A
2007
2064
if let Some ( ( fragment_offset, _) ) =
2008
2065
diag_info. ori_link . char_indices ( ) . filter ( |( _, x) | * x == '#' ) . nth ( anchor_idx)
2009
2066
{
2010
- sp = sp. with_lo ( sp. lo ( ) + rustc_span :: BytePos ( fragment_offset as _ ) ) ;
2067
+ sp = sp. with_lo ( sp. lo ( ) + BytePos ( fragment_offset as _ ) ) ;
2011
2068
}
2012
2069
diag. span_label ( sp, "invalid anchor" ) ;
2013
2070
}
@@ -2075,14 +2132,7 @@ fn ambiguity_error(
2075
2132
2076
2133
for res in candidates {
2077
2134
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) ;
2086
2136
}
2087
2137
} ) ;
2088
2138
}
@@ -2093,21 +2143,20 @@ fn suggest_disambiguator(
2093
2143
disambiguator : Disambiguator ,
2094
2144
diag : & mut DiagnosticBuilder < ' _ > ,
2095
2145
path_str : & str ,
2096
- dox : & str ,
2146
+ ori_link : & str ,
2097
2147
sp : Option < rustc_span:: Span > ,
2098
- link_range : & Range < usize > ,
2099
2148
) {
2100
2149
let suggestion = disambiguator. suggestion ( ) ;
2101
2150
let help = format ! ( "to link to the {}, {}" , disambiguator. descr( ) , suggestion. descr( ) ) ;
2102
2151
2103
2152
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 ) ;
2106
2156
} 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
+ }
2111
2160
} else {
2112
2161
diag. help ( & format ! ( "{}: {}" , help, suggestion. as_help( path_str) ) ) ;
2113
2162
}
0 commit comments