1
1
use clippy_utils:: diagnostics:: span_lint_and_then;
2
+ use rustc_ast:: token:: CommentKind ;
2
3
use rustc_errors:: Applicability ;
4
+ use rustc_hir:: { AttrStyle , Attribute } ;
3
5
use rustc_lint:: { LateContext , LintContext } ;
4
6
5
7
use std:: ops:: Range ;
6
8
7
9
use super :: { DOC_SUSPICIOUS_FOOTNOTES , Fragments } ;
8
10
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 ] ) {
10
12
for i in doc[ range. clone ( ) ]
11
13
. bytes ( )
12
14
. enumerate ( )
@@ -29,6 +31,10 @@ pub fn check(cx: &LateContext<'_>, doc: &str, range: Range<usize>, fragments: &F
29
31
found
30
32
} )
31
33
. 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 ( ) ?) ) )
32
38
{
33
39
let span = fragments. span ( cx, start..end) . unwrap_or ( this_fragment. span ) ;
34
40
span_lint_and_then (
@@ -37,56 +43,48 @@ pub fn check(cx: &LateContext<'_>, doc: &str, range: Range<usize>, fragments: &F
37
43
span,
38
44
"looks like a footnote ref, but has no matching footnote" ,
39
45
|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 /*! " , " */" ) ,
83
52
} ;
84
53
diag. span_suggestion_verbose (
85
- span,
54
+ last_doc_attr . span ( ) . shrink_to_hi ( ) ,
86
55
"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 ,
89
58
) ;
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
+ }
90
88
}
91
89
} ,
92
90
) ;
0 commit comments