11use clippy_utils:: diagnostics:: span_lint_and_then;
2+ use rustc_ast:: token:: CommentKind ;
23use rustc_errors:: Applicability ;
4+ use rustc_hir:: { AttrStyle , Attribute } ;
35use rustc_lint:: { LateContext , LintContext } ;
46
57use std:: ops:: Range ;
68
79use super :: { DOC_SUSPICIOUS_FOOTNOTES , Fragments } ;
810
9- pub fn check ( cx : & LateContext < ' _ > , doc : & str , range : Range < usize > , fragments : & Fragments < ' _ > ) {
11+ pub fn check ( cx : & LateContext < ' _ > , doc : & str , range : Range < usize > , fragments : & Fragments < ' _ > , attrs : & [ Attribute ] ) {
1012 for i in doc[ range. clone ( ) ]
1113 . bytes ( )
1214 . enumerate ( )
@@ -29,6 +31,10 @@ pub fn check(cx: &LateContext<'_>, doc: &str, range: Range<usize>, fragments: &F
2931 found
3032 } )
3133 . or ( fragments. fragments . last ( ) )
34+ && let Some ( ( last_doc_attr, ( last_doc_attr_str, last_doc_attr_comment_kind) ) ) = attrs
35+ . iter ( )
36+ . rev ( )
37+ . find_map ( |attr| Some ( ( attr, attr. doc_str_and_comment_kind ( ) ?) ) )
3238 {
3339 let span = fragments. span ( cx, start..end) . unwrap_or ( this_fragment. span ) ;
3440 span_lint_and_then (
@@ -37,56 +43,48 @@ pub fn check(cx: &LateContext<'_>, doc: &str, range: Range<usize>, fragments: &F
3743 span,
3844 "looks like a footnote ref, but has no matching footnote" ,
3945 |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- }
81- } else {
82- span_whole_line. shrink_to_hi ( )
46+ if last_doc_attr. is_doc_comment ( ) {
47+ let ( pfx, sfx) = match ( last_doc_attr_comment_kind, last_doc_attr. style ( ) ) {
48+ ( CommentKind :: Line , AttrStyle :: Outer ) => ( "\n ///\n /// " , "" ) ,
49+ ( CommentKind :: Line , AttrStyle :: Inner ) => ( "\n //!\n //! " , "" ) ,
50+ ( CommentKind :: Block , AttrStyle :: Outer ) => ( "\n /** " , " */" ) ,
51+ ( CommentKind :: Block , AttrStyle :: Inner ) => ( "\n /*! " , " */" ) ,
8352 } ;
8453 diag. span_suggestion_verbose (
85- span,
54+ last_doc_attr . span ( ) . shrink_to_hi ( ) ,
8655 "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 ,
56+ format ! ( "{pfx}{label}: <!-- description -->{sfx}" , label = & doc[ start..end] ) ,
57+ Applicability :: HasPlaceholders ,
8958 ) ;
59+ } else {
60+ let is_file_include = cx
61+ . sess ( )
62+ . source_map ( )
63+ . span_to_snippet ( this_fragment. span )
64+ . as_ref ( )
65+ . map ( |vdoc| vdoc. trim ( ) )
66+ == Ok ( doc) ;
67+ if is_file_include {
68+ // if this is a file include, then there's no quote marks
69+ diag. span_suggestion_verbose (
70+ this_fragment. span . shrink_to_hi ( ) ,
71+ "add footnote definition" ,
72+ format ! ( "\n \n {label}: <!-- description -->" , label = & doc[ start..end] , ) ,
73+ Applicability :: HasPlaceholders ,
74+ ) ;
75+ } else {
76+ // otherwise, we wrap in a string
77+ diag. span_suggestion_verbose (
78+ this_fragment. span ,
79+ "add footnote definition" ,
80+ format ! (
81+ "r#\" {doc}\n \n {label}: <!-- description -->\" #" ,
82+ doc = last_doc_attr_str,
83+ label = & doc[ start..end] ,
84+ ) ,
85+ Applicability :: HasPlaceholders ,
86+ ) ;
87+ }
9088 }
9189 } ,
9290 ) ;
0 commit comments