Skip to content

Commit eea151d

Browse files
committed
Clean up fragment and attr search code
1 parent a5f4d5d commit eea151d

File tree

4 files changed

+153
-30
lines changed

4 files changed

+153
-30
lines changed

clippy_lints/src/doc/doc_suspicious_footnotes.rs

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use rustc_ast::token::CommentKind;
33
use rustc_errors::Applicability;
44
use rustc_hir::{AttrStyle, Attribute};
55
use rustc_lint::{LateContext, LintContext};
6+
use rustc_resolve::rustdoc::DocFragmentKind;
67

78
use std::ops::Range;
89

@@ -15,26 +16,24 @@ pub fn check(cx: &LateContext<'_>, doc: &str, range: Range<usize>, fragments: &F
1516
.filter_map(|(i, c)| if c == b'[' { Some(i) } else { None })
1617
{
1718
let start = i + range.start;
18-
let mut this_fragment_start = start;
1919
if doc.as_bytes().get(start + 1) == Some(&b'^')
2020
&& let Some(end) = all_numbers_upto_brace(doc, start + 2)
2121
&& doc.as_bytes().get(end) != Some(&b':')
2222
&& doc.as_bytes().get(start - 1) != Some(&b'\\')
23-
&& let Some(this_fragment) = fragments
24-
.fragments
25-
.iter()
26-
.find(|frag| {
27-
let found = this_fragment_start < frag.doc.as_str().len();
28-
if !found {
29-
this_fragment_start -= frag.doc.as_str().len();
23+
&& let Some(this_fragment) = {
24+
// the `doc` string contains all fragments concatenated together
25+
// figure out which one this suspicious footnote comes from
26+
let mut starting_position = 0;
27+
let mut found_fragment = fragments.fragments.last();
28+
for fragment in fragments.fragments {
29+
if start >= starting_position && start < starting_position + fragment.doc.as_str().len() {
30+
found_fragment = Some(fragment);
31+
break;
3032
}
31-
found
32-
})
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()?)))
33+
starting_position += fragment.doc.as_str().len();
34+
}
35+
found_fragment
36+
}
3837
{
3938
let span = fragments.span(cx, start..end).unwrap_or(this_fragment.span);
4039
span_lint_and_then(
@@ -43,15 +42,21 @@ pub fn check(cx: &LateContext<'_>, doc: &str, range: Range<usize>, fragments: &F
4342
span,
4443
"looks like a footnote ref, but has no matching footnote",
4544
|diag| {
46-
if last_doc_attr.is_doc_comment() {
47-
let (to_add, terminator) = match (last_doc_attr_comment_kind, last_doc_attr.style()) {
45+
if this_fragment.kind == DocFragmentKind::SugaredDoc {
46+
let (doc_attr, (_, doc_attr_comment_kind)) = attrs
47+
.iter()
48+
.filter(|attr| attr.span().overlaps(this_fragment.span))
49+
.rev()
50+
.find_map(|attr| Some((attr, attr.doc_str_and_comment_kind()?)))
51+
.unwrap();
52+
let (to_add, terminator) = match (doc_attr_comment_kind, doc_attr.style()) {
4853
(CommentKind::Line, AttrStyle::Outer) => ("\n///\n/// ", ""),
4954
(CommentKind::Line, AttrStyle::Inner) => ("\n//!\n//! ", ""),
5055
(CommentKind::Block, AttrStyle::Outer) => ("\n/** ", " */"),
5156
(CommentKind::Block, AttrStyle::Inner) => ("\n/*! ", " */"),
5257
};
5358
diag.span_suggestion_verbose(
54-
last_doc_attr.span().shrink_to_hi(),
59+
doc_attr.span().shrink_to_hi(),
5560
"add footnote definition",
5661
format!(
5762
"{to_add}{label}: <!-- description -->{terminator}",
@@ -82,7 +87,7 @@ pub fn check(cx: &LateContext<'_>, doc: &str, range: Range<usize>, fragments: &F
8287
"add footnote definition",
8388
format!(
8489
"r#\"{doc}\n\n{label}: <!-- description -->\"#",
85-
doc = last_doc_attr_str,
90+
doc = this_fragment.doc,
8691
label = &doc[start..end],
8792
),
8893
Applicability::HasPlaceholders,

tests/ui/doc_suspicious_footnotes.fixed

Lines changed: 43 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
#![warn(clippy::doc_suspicious_footnotes)]
22
#![allow(clippy::needless_raw_string_hashes)]
33
//! This is not a footnote[^1].
4+
//!
5+
//! [^1]: <!-- description -->
46
//~^ doc_suspicious_footnotes
57
//!
68
//! This is not a footnote[^either], but it doesn't warn.
@@ -14,10 +16,10 @@
1416
//! This is a footnote[^2].
1517
//!
1618
//! [^2]: hello world
17-
//!
18-
//! [^1]: <!-- description -->
1919

2020
/// This is not a footnote[^1].
21+
///
22+
/// [^1]: <!-- description -->
2123
//~^ doc_suspicious_footnotes
2224
///
2325
/// This is not a footnote[^either], but it doesn't warn.
@@ -31,16 +33,14 @@
3133
/// This is a footnote[^2].
3234
///
3335
/// [^2]: hello world
34-
///
35-
/// [^1]: <!-- description -->
3636
pub fn footnotes() {
3737
// test code goes here
3838
}
3939

4040
pub struct Foo;
4141
#[rustfmt::skip]
4242
impl Foo {
43-
#[doc = r#"[^2]: hello world
43+
#[doc = r#"This is not a footnote[^1].
4444

4545
[^1]: <!-- description -->"#]
4646
//~^ doc_suspicious_footnotes
@@ -100,7 +100,7 @@ This is not a footnote[^either], but it doesn't warn.
100100
}
101101
}
102102

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

105105
[^1]: <!-- description -->"#]
106106
//~^ doc_suspicious_footnotes
@@ -147,3 +147,40 @@ pub mod multiline {
147147
/** [^1]: <!-- description --> */
148148
pub fn foo() {}
149149
}
150+
151+
/// This is not a footnote [^1]
152+
///
153+
/// [^1]: <!-- description -->
154+
//~^ doc_suspicious_footnotes
155+
///
156+
/// This one is [^2]
157+
///
158+
/// [^2]: contents
159+
#[doc = r#"This is not a footnote [^3]
160+
161+
[^3]: <!-- description -->"#]
162+
//~^ doc_suspicious_footnotes
163+
#[doc = ""]
164+
#[doc = "This one is [^4]"]
165+
#[doc = ""]
166+
#[doc = "[^4]: contents"]
167+
pub struct MultiFragmentFootnote;
168+
169+
#[doc(inline)]
170+
/// This is not a footnote [^5]
171+
///
172+
/// [^5]: <!-- description -->
173+
//~^ doc_suspicious_footnotes
174+
///
175+
/// This one is [^6]
176+
///
177+
/// [^6]: contents
178+
#[doc = r#"This is not a footnote [^7]
179+
180+
[^7]: <!-- description -->"#]
181+
//~^ doc_suspicious_footnotes
182+
#[doc = ""]
183+
#[doc = "This one is [^8]"]
184+
#[doc = ""]
185+
#[doc = "[^8]: contents"]
186+
pub use MultiFragmentFootnote as OtherInlinedFootnote;

tests/ui/doc_suspicious_footnotes.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,3 +131,32 @@ pub mod multiline {
131131
*/
132132
pub fn foo() {}
133133
}
134+
135+
/// This is not a footnote [^1]
136+
//~^ doc_suspicious_footnotes
137+
///
138+
/// This one is [^2]
139+
///
140+
/// [^2]: contents
141+
#[doc = "This is not a footnote [^3]"]
142+
//~^ doc_suspicious_footnotes
143+
#[doc = ""]
144+
#[doc = "This one is [^4]"]
145+
#[doc = ""]
146+
#[doc = "[^4]: contents"]
147+
pub struct MultiFragmentFootnote;
148+
149+
#[doc(inline)]
150+
/// This is not a footnote [^5]
151+
//~^ doc_suspicious_footnotes
152+
///
153+
/// This one is [^6]
154+
///
155+
/// [^6]: contents
156+
#[doc = "This is not a footnote [^7]"]
157+
//~^ doc_suspicious_footnotes
158+
#[doc = ""]
159+
#[doc = "This one is [^8]"]
160+
#[doc = ""]
161+
#[doc = "[^8]: contents"]
162+
pub use MultiFragmentFootnote as OtherInlinedFootnote;

tests/ui/doc_suspicious_footnotes.stderr

Lines changed: 57 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ LL | //! This is not a footnote[^1].
88
= help: to override `-D warnings` add `#[allow(clippy::doc_suspicious_footnotes)]`
99
help: add footnote definition
1010
|
11-
LL ~ //! [^2]: hello world
11+
LL ~ //! This is not a footnote[^1].
1212
LL + //!
1313
LL + //! [^1]: <!-- description -->
1414
|
@@ -21,7 +21,7 @@ LL | /// This is not a footnote[^1].
2121
|
2222
help: add footnote definition
2323
|
24-
LL ~ /// [^2]: hello world
24+
LL ~ /// This is not a footnote[^1].
2525
LL + ///
2626
LL + /// [^1]: <!-- description -->
2727
|
@@ -34,7 +34,7 @@ LL | #[doc = r#"This is not a footnote[^1]."#]
3434
|
3535
help: add footnote definition
3636
|
37-
LL ~ #[doc = r#"[^2]: hello world
37+
LL ~ #[doc = r#"This is not a footnote[^1].
3838
LL +
3939
LL ~ [^1]: <!-- description -->"#]
4040
|
@@ -94,7 +94,7 @@ LL | #[doc = r"This is not a footnote[^1]."]
9494
|
9595
help: add footnote definition
9696
|
97-
LL ~ #[doc = r#"[^2]: hello world
97+
LL ~ #[doc = r#"This is not a footnote[^1].
9898
LL +
9999
LL ~ [^1]: <!-- description -->"#]
100100
|
@@ -123,5 +123,57 @@ LL ~ */
123123
LL + /** [^1]: <!-- description --> */
124124
|
125125

126-
error: aborting due to 8 previous errors
126+
error: looks like a footnote ref, but has no matching footnote
127+
--> tests/ui/doc_suspicious_footnotes.rs:135:1
128+
|
129+
LL | /// This is not a footnote [^1]
130+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
131+
|
132+
help: add footnote definition
133+
|
134+
LL ~ /// This is not a footnote [^1]
135+
LL + ///
136+
LL + /// [^1]: <!-- description -->
137+
|
138+
139+
error: looks like a footnote ref, but has no matching footnote
140+
--> tests/ui/doc_suspicious_footnotes.rs:141:9
141+
|
142+
LL | #[doc = "This is not a footnote [^3]"]
143+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
144+
|
145+
help: add footnote definition
146+
|
147+
LL ~ #[doc = r#"This is not a footnote [^3]
148+
LL +
149+
LL ~ [^3]: <!-- description -->"#]
150+
|
151+
152+
error: looks like a footnote ref, but has no matching footnote
153+
--> tests/ui/doc_suspicious_footnotes.rs:150:1
154+
|
155+
LL | /// This is not a footnote [^5]
156+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
157+
|
158+
help: add footnote definition
159+
|
160+
LL ~ /// This is not a footnote [^5]
161+
LL + ///
162+
LL + /// [^5]: <!-- description -->
163+
|
164+
165+
error: looks like a footnote ref, but has no matching footnote
166+
--> tests/ui/doc_suspicious_footnotes.rs:156:9
167+
|
168+
LL | #[doc = "This is not a footnote [^7]"]
169+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
170+
|
171+
help: add footnote definition
172+
|
173+
LL ~ #[doc = r#"This is not a footnote [^7]
174+
LL +
175+
LL ~ [^7]: <!-- description -->"#]
176+
|
177+
178+
error: aborting due to 12 previous errors
127179

0 commit comments

Comments
 (0)