11use clippy_utils:: diagnostics:: span_lint_and_then;
22use rustc_errors:: Applicability ;
3- use rustc_lint:: { LateContext , LintContext } ;
3+ use rustc_hir:: { AttrStyle , Attribute } ;
4+ use rustc_lint:: LateContext ;
45
56use std:: ops:: Range ;
67
78use super :: { DOC_SUSPICIOUS_FOOTNOTES , Fragments } ;
89
9- pub fn check ( cx : & LateContext < ' _ > , doc : & str , range : Range < usize > , fragments : & Fragments < ' _ > ) {
10+ pub fn check ( cx : & LateContext < ' _ > , doc : & str , range : Range < usize > , fragments : & Fragments < ' _ > , attrs : & [ Attribute ] ) {
1011 for i in doc[ range. clone ( ) ]
1112 . bytes ( )
1213 . enumerate ( )
@@ -29,6 +30,8 @@ pub fn check(cx: &LateContext<'_>, doc: &str, range: Range<usize>, fragments: &F
2930 found
3031 } )
3132 . or ( fragments. fragments . last ( ) )
33+ && let Some ( ( last_doc_attr, last_doc_attr_str) ) =
34+ attrs. iter ( ) . rev ( ) . find_map ( |attr| Some ( ( attr, attr. doc_str ( ) ?) ) )
3235 {
3336 let span = fragments. span ( cx, start..end) . unwrap_or ( this_fragment. span ) ;
3437 span_lint_and_then (
@@ -37,55 +40,28 @@ pub fn check(cx: &LateContext<'_>, doc: &str, range: Range<usize>, fragments: &F
3740 span,
3841 "looks like a footnote ref, but has no matching footnote" ,
3942 |diag| {
40- let applicability = Applicability :: HasPlaceholders ;
41- let start_of_md_line = doc. as_bytes ( ) [ ..start]
42- . iter ( )
43- . rposition ( |& c| c == b'\n' || c == b'\r' )
44- . unwrap_or ( 0 ) ;
45- let end_of_md_line = doc. as_bytes ( ) [ start..]
46- . iter ( )
47- . position ( |& c| c == b'\n' || c == b'\r' )
48- . unwrap_or ( doc. len ( ) - start)
49- + start;
50- let span_md_line = fragments
51- . span ( cx, start_of_md_line..end_of_md_line)
52- . unwrap_or ( this_fragment. span ) ;
53- let span_whole_line = cx. sess ( ) . source_map ( ) . span_extend_to_line ( span_md_line) ;
54- if let Ok ( mut pfx) = cx
55- . sess ( )
56- . source_map ( )
57- . span_to_snippet ( span_whole_line. until ( span_md_line) )
58- && let Ok ( mut sfx) = cx
59- . sess ( )
60- . source_map ( )
61- . span_to_snippet ( span_md_line. shrink_to_hi ( ) . until ( span_whole_line. shrink_to_hi ( ) ) )
62- {
63- let mut insert_before = String :: new ( ) ;
64- let mut insert_after = String :: new ( ) ;
65- let span = if this_fragment. kind == rustc_resolve:: rustdoc:: DocFragmentKind :: RawDoc
66- && ( !pfx. is_empty ( ) || !sfx. is_empty ( ) )
67- {
68- if ( pfx. trim ( ) == "#[doc=" || pfx. trim ( ) == "#![doc=" ) && sfx. trim ( ) == "]" {
69- // try to use per-line doc fragments if that's what the author did
70- pfx. push ( '"' ) ;
71- sfx. insert ( 0 , '"' ) ;
72- span_whole_line. shrink_to_hi ( )
73- } else {
74- // otherwise, replace the whole line with the result
75- pfx = String :: new ( ) ;
76- sfx = String :: new ( ) ;
77- insert_before = format ! ( r#"r###"{}"# , this_fragment. doc) ;
78- r####""###"#### . clone_into ( & mut insert_after) ;
79- span_md_line
80- }
43+ if last_doc_attr. is_doc_comment ( ) {
44+ let pfx = if last_doc_attr. style ( ) == AttrStyle :: Outer {
45+ "///"
8146 } else {
82- span_whole_line . shrink_to_hi ( )
47+ "//!"
8348 } ;
8449 diag. span_suggestion_verbose (
85- span,
50+ last_doc_attr . span ( ) . shrink_to_hi ( ) ,
8651 "add footnote definition" ,
87- format ! ( "{insert_before}\n {pfx}{sfx}\n {pfx}{label}: <!-- description -->{sfx}\n {pfx}{sfx}{insert_after}" , label = & doc[ start..end] ) ,
88- applicability,
52+ format ! ( "\n {pfx}\n {pfx}{label}: <!-- description -->" , label = & doc[ start..end] ) ,
53+ Applicability :: HasPlaceholders ,
54+ ) ;
55+ } else if let Some ( vspan) = last_doc_attr. value_span ( ) {
56+ diag. span_suggestion_verbose (
57+ vspan,
58+ "add footnote definition" ,
59+ format ! (
60+ "r#\" {doc}\n \n {label}: <!-- description -->\" #" ,
61+ doc = last_doc_attr_str,
62+ label = & doc[ start..end] ,
63+ ) ,
64+ Applicability :: HasPlaceholders ,
8965 ) ;
9066 }
9167 } ,
0 commit comments