Skip to content

Commit 98426f5

Browse files
committed
Use a simpler way to generate these doc comments
1 parent 99b16ae commit 98426f5

6 files changed

+152
-86
lines changed

clippy_lints/src/doc/doc_suspicious_footnotes.rs

Lines changed: 45 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
use clippy_utils::diagnostics::span_lint_and_then;
2+
use rustc_ast::token::CommentKind;
23
use rustc_errors::Applicability;
4+
use rustc_hir::{AttrStyle, Attribute};
35
use rustc_lint::{LateContext, LintContext};
46

57
use std::ops::Range;
68

79
use 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
);

clippy_lints/src/doc/mod.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -862,6 +862,7 @@ fn check_attrs(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, attrs: &[
862862
doc: &doc,
863863
fragments: &fragments,
864864
},
865+
attrs,
865866
))
866867
}
867868

@@ -942,6 +943,7 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
942943
events: Events,
943944
doc: &str,
944945
fragments: Fragments<'_>,
946+
attrs: &[Attribute],
945947
) -> DocHeaders {
946948
// true if a safety header was found
947949
let mut headers = DocHeaders::default();
@@ -1187,7 +1189,7 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
11871189
continue;
11881190
}
11891191
text_to_check.push((text, range.clone(), code_level));
1190-
doc_suspicious_footnotes::check(cx, doc, range, &fragments);
1192+
doc_suspicious_footnotes::check(cx, doc, range, &fragments, attrs);
11911193
}
11921194
}
11931195
FootnoteReference(_) => {}

tests/ui/doc_suspicious_footnotes.fixed

Lines changed: 40 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
#![warn(clippy::doc_suspicious_footnotes)]
22
#![allow(clippy::needless_raw_string_hashes)]
33
//! This is not a footnote[^1].
4-
//!
5-
//! [^1]: <!-- description -->
6-
//!
74
//~^ doc_suspicious_footnotes
85
//!
96
//! This is not a footnote[^either], but it doesn't warn.
@@ -17,11 +14,10 @@
1714
//! This is a footnote[^2].
1815
//!
1916
//! [^2]: hello world
17+
//!
18+
//! [^1]: <!-- description -->
2019

2120
/// This is not a footnote[^1].
22-
///
23-
/// [^1]: <!-- description -->
24-
///
2521
//~^ doc_suspicious_footnotes
2622
///
2723
/// This is not a footnote[^either], but it doesn't warn.
@@ -35,16 +31,17 @@
3531
/// This is a footnote[^2].
3632
///
3733
/// [^2]: hello world
34+
///
35+
/// [^1]: <!-- description -->
3836
pub fn footnotes() {
3937
// test code goes here
4038
}
4139

4240
pub struct Foo;
4341
impl Foo {
44-
#[doc = r###"This is not a footnote[^1].
42+
#[doc = r#"[^2]: hello world
4543

46-
[^1]: <!-- description -->
47-
"###]
44+
[^1]: <!-- description -->"#]
4845
//~^ doc_suspicious_footnotes
4946
#[doc = r#""#]
5047
#[doc = r#"This is not a footnote[^either], but it doesn't warn."#]
@@ -61,7 +58,7 @@ impl Foo {
6158
pub fn footnotes() {
6259
// test code goes here
6360
}
64-
#[doc = r###"This is not a footnote[^1].
61+
#[doc = r#"This is not a footnote[^1].
6562

6663
This is not a footnote[^either], but it doesn't warn.
6764

@@ -76,31 +73,28 @@ impl Foo {
7673
[^2]: hello world
7774

7875

79-
[^1]: <!-- description -->
80-
"###]
76+
[^1]: <!-- description -->"#]
8177
//~^^^^^^^^^^^^^^ doc_suspicious_footnotes
8278
pub fn footnotes2() {
8379
// test code goes here
8480
}
8581
#[cfg_attr(
8682
not(FALSE),
87-
doc = r###"This is not a footnote[^1].
83+
doc = r#"This is not a footnote[^1].
8884

8985
This is not a footnote[^either], but it doesn't warn.
9086

91-
[^1]: <!-- description -->
92-
"###
87+
[^1]: <!-- description -->"#
9388
//~^ doc_suspicious_footnotes
9489
)]
9590
pub fn footnotes3() {
9691
// test code goes here
9792
}
9893
}
9994

100-
#[doc = r###"This is not a footnote[^1].
95+
#[doc = r#"[^2]: hello world
10196

102-
[^1]: <!-- description -->
103-
"###]
97+
[^1]: <!-- description -->"#]
10498
//~^ doc_suspicious_footnotes
10599
#[doc = r""]
106100
#[doc = r"This is not a footnote[^either], but it doesn't warn."]
@@ -117,3 +111,31 @@ This is not a footnote[^either], but it doesn't warn.
117111
pub fn footnotes_attrs() {
118112
// test code goes here
119113
}
114+
115+
pub mod multiline {
116+
/*!
117+
* This is not a footnote[^1]. //~ doc_suspicious_footnotes
118+
*
119+
* This is not a footnote\[^1], but it doesn't warn.
120+
*
121+
* This is a footnote[^2].
122+
*
123+
* These give weird results, but correct ones, so it works.
124+
*
125+
* [^2]: hello world
126+
*/
127+
/*! [^1]: <!-- description --> */
128+
/**
129+
* This is not a footnote[^1]. //~ doc_suspicious_footnotes
130+
*
131+
* This is not a footnote\[^1], but it doesn't warn.
132+
*
133+
* This is a footnote[^2].
134+
*
135+
* These give weird results, but correct ones, so it works.
136+
*
137+
* [^2]: hello world
138+
*/
139+
/** [^1]: <!-- description --> */
140+
pub fn foo() {}
141+
}

tests/ui/doc_suspicious_footnotes.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,3 +97,29 @@ impl Foo {
9797
pub fn footnotes_attrs() {
9898
// test code goes here
9999
}
100+
101+
pub mod multiline {
102+
/*!
103+
* This is not a footnote[^1]. //~ doc_suspicious_footnotes
104+
*
105+
* This is not a footnote\[^1], but it doesn't warn.
106+
*
107+
* This is a footnote[^2].
108+
*
109+
* These give weird results, but correct ones, so it works.
110+
*
111+
* [^2]: hello world
112+
*/
113+
/**
114+
* This is not a footnote[^1]. //~ doc_suspicious_footnotes
115+
*
116+
* This is not a footnote\[^1], but it doesn't warn.
117+
*
118+
* This is a footnote[^2].
119+
*
120+
* These give weird results, but correct ones, so it works.
121+
*
122+
* [^2]: hello world
123+
*/
124+
pub fn foo() {}
125+
}

0 commit comments

Comments
 (0)