Skip to content

Commit 7db973d

Browse files
committed
Merge remote-tracking branch 'FlorianRohm/issue/4623' into rollup-new-lints
2 parents 353668e + 73806b7 commit 7db973d

File tree

7 files changed

+328
-0
lines changed

7 files changed

+328
-0
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -1203,6 +1203,7 @@ Released 2018-09-13
12031203
[`suspicious_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_map
12041204
[`suspicious_op_assign_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_op_assign_impl
12051205
[`suspicious_unary_op_formatting`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_unary_op_formatting
1206+
[`tabs_in_doc_comments`]: https://rust-lang.github.io/rust-clippy/master/index.html#tabs_in_doc_comments
12061207
[`temporary_assignment`]: https://rust-lang.github.io/rust-clippy/master/index.html#temporary_assignment
12071208
[`temporary_cstring_as_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#temporary_cstring_as_ptr
12081209
[`to_digit_is_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#to_digit_is_some

clippy_lints/src/lib.rs

+5
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,7 @@ pub mod slow_vector_initialization;
275275
pub mod strings;
276276
pub mod suspicious_trait_impl;
277277
pub mod swap;
278+
pub mod tabs_in_doc_comments;
278279
pub mod temporary_assignment;
279280
pub mod to_digit_is_some;
280281
pub mod trait_bounds;
@@ -720,6 +721,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf
720721
&suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL,
721722
&swap::ALMOST_SWAPPED,
722723
&swap::MANUAL_SWAP,
724+
&tabs_in_doc_comments::TABS_IN_DOC_COMMENTS,
723725
&temporary_assignment::TEMPORARY_ASSIGNMENT,
724726
&to_digit_is_some::TO_DIGIT_IS_SOME,
725727
&trait_bounds::TYPE_REPETITION_IN_BOUNDS,
@@ -950,6 +952,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf
950952
store.register_early_pass(|| box utils::internal_lints::ClippyLintsInternal);
951953
let enum_variant_name_threshold = conf.enum_variant_name_threshold;
952954
store.register_early_pass(move || box enum_variants::EnumVariantNames::new(enum_variant_name_threshold));
955+
store.register_early_pass(|| box tabs_in_doc_comments::TabsInDocComments);
953956
store.register_late_pass(|| box unused_self::UnusedSelf);
954957
store.register_late_pass(|| box mutable_debug_assertion::DebugAssertWithMutCall);
955958
store.register_late_pass(|| box exit::Exit);
@@ -1252,6 +1255,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf
12521255
LintId::of(&suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL),
12531256
LintId::of(&swap::ALMOST_SWAPPED),
12541257
LintId::of(&swap::MANUAL_SWAP),
1258+
LintId::of(&tabs_in_doc_comments::TABS_IN_DOC_COMMENTS),
12551259
LintId::of(&temporary_assignment::TEMPORARY_ASSIGNMENT),
12561260
LintId::of(&to_digit_is_some::TO_DIGIT_IS_SOME),
12571261
LintId::of(&transmute::CROSSPOINTER_TRANSMUTE),
@@ -1379,6 +1383,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf
13791383
LintId::of(&returns::NEEDLESS_RETURN),
13801384
LintId::of(&returns::UNUSED_UNIT),
13811385
LintId::of(&strings::STRING_LIT_AS_BYTES),
1386+
LintId::of(&tabs_in_doc_comments::TABS_IN_DOC_COMMENTS),
13821387
LintId::of(&to_digit_is_some::TO_DIGIT_IS_SOME),
13831388
LintId::of(&try_err::TRY_ERR),
13841389
LintId::of(&types::FN_TO_NUMERIC_CAST),
+219
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
use crate::utils::span_lint_and_sugg;
2+
use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass};
3+
use rustc::{declare_lint_pass, declare_tool_lint};
4+
use rustc_errors::Applicability;
5+
use std::convert::TryFrom;
6+
use syntax::ast;
7+
use syntax::source_map::{BytePos, Span};
8+
9+
declare_clippy_lint! {
10+
/// **What it does:** Checks doc comments for usage of tab characters.
11+
///
12+
/// **Why is this bad?** The rust style-guide promotes spaces instead of tabs for indentation.
13+
/// To keep a consistent view on the source, also doc comments should not have tabs.
14+
/// Also, explaining ascii-diagrams containing tabs can get displayed incorrectly when the
15+
/// display settings of the author and reader differ.
16+
///
17+
/// **Known problems:** None.
18+
///
19+
/// **Example:**
20+
/// ```rust
21+
/// ///
22+
/// /// Struct to hold two strings:
23+
/// /// - first one
24+
/// /// - second one
25+
/// pub struct DoubleString {
26+
/// ///
27+
/// /// - First String:
28+
/// /// - needs to be inside here
29+
/// first_string: String,
30+
/// ///
31+
/// /// - Second String:
32+
/// /// - needs to be inside here
33+
/// second_string: String,
34+
///}
35+
/// ```
36+
///
37+
/// Will be converted to:
38+
/// ```rust
39+
/// ///
40+
/// /// Struct to hold two strings:
41+
/// /// - first one
42+
/// /// - second one
43+
/// pub struct DoubleString {
44+
/// ///
45+
/// /// - First String:
46+
/// /// - needs to be inside here
47+
/// first_string: String,
48+
/// ///
49+
/// /// - Second String:
50+
/// /// - needs to be inside here
51+
/// second_string: String,
52+
///}
53+
/// ```
54+
pub TABS_IN_DOC_COMMENTS,
55+
style,
56+
"using tabs in doc comments is not recommended"
57+
}
58+
59+
declare_lint_pass!(TabsInDocComments => [TABS_IN_DOC_COMMENTS]);
60+
61+
impl TabsInDocComments {
62+
fn warn_if_tabs_in_doc(cx: &EarlyContext<'_>, attr: &ast::Attribute) {
63+
if let ast::AttrKind::DocComment(comment) = attr.kind {
64+
let comment = comment.as_str();
65+
66+
for (lo, hi) in get_chunks_of_tabs(&comment) {
67+
let new_span = Span::new(
68+
attr.span.lo() + BytePos(lo),
69+
attr.span.lo() + BytePos(hi),
70+
attr.span.ctxt(),
71+
);
72+
span_lint_and_sugg(
73+
cx,
74+
TABS_IN_DOC_COMMENTS,
75+
new_span,
76+
"using tabs in doc comments is not recommended",
77+
"consider using four spaces per tab",
78+
" ".repeat((hi - lo) as usize),
79+
Applicability::MaybeIncorrect,
80+
);
81+
}
82+
}
83+
}
84+
}
85+
86+
impl EarlyLintPass for TabsInDocComments {
87+
fn check_attribute(&mut self, cx: &EarlyContext<'_>, attribute: &ast::Attribute) {
88+
Self::warn_if_tabs_in_doc(cx, &attribute);
89+
}
90+
}
91+
92+
///
93+
/// scans the string for groups of tabs and returns the start(inclusive) and end positions
94+
/// (exclusive) of all groups
95+
/// e.g. "sd\tasd\t\taa" will be converted to [(2, 3), (6, 8)] as
96+
/// 012 3456 7 89
97+
/// ^-^ ^---^
98+
fn get_chunks_of_tabs(the_str: &str) -> Vec<(u32, u32)> {
99+
let line_length_way_to_long = "doc comment longer than 2^32 chars";
100+
let mut spans: Vec<(u32, u32)> = vec![];
101+
let mut current_start: u32 = 0;
102+
103+
// tracker to decide if the last group of tabs is not closed by a non-tab character
104+
let mut is_active = false;
105+
106+
let chars_array: Vec<_> = the_str.chars().collect();
107+
108+
if chars_array == vec!['\t'] {
109+
return vec![(0, 1)];
110+
}
111+
112+
for (index, arr) in chars_array.windows(2).enumerate() {
113+
let index = u32::try_from(index).expect(line_length_way_to_long);
114+
match arr {
115+
['\t', '\t'] => {
116+
// either string starts with double tab, then we have to set it active,
117+
// otherwise is_active is true anyway
118+
is_active = true;
119+
},
120+
[_, '\t'] => {
121+
// as ['\t', '\t'] is excluded, this has to be a start of a tab group,
122+
// set indices accordingly
123+
is_active = true;
124+
current_start = index + 1;
125+
},
126+
['\t', _] => {
127+
// this now has to be an end of the group, hence we have to push a new tuple
128+
is_active = false;
129+
spans.push((current_start, index + 1));
130+
},
131+
_ => {},
132+
}
133+
}
134+
135+
// only possible when tabs are at the end, insert last group
136+
if is_active {
137+
spans.push((
138+
current_start,
139+
u32::try_from(the_str.chars().count()).expect(line_length_way_to_long),
140+
));
141+
}
142+
143+
spans
144+
}
145+
146+
#[cfg(test)]
147+
mod tests_for_get_chunks_of_tabs {
148+
use super::get_chunks_of_tabs;
149+
150+
#[test]
151+
fn test_empty_string() {
152+
let res = get_chunks_of_tabs("");
153+
154+
assert_eq!(res, vec![]);
155+
}
156+
157+
#[test]
158+
fn test_simple() {
159+
let res = get_chunks_of_tabs("sd\t\t\taa");
160+
161+
assert_eq!(res, vec![(2, 5)]);
162+
}
163+
164+
#[test]
165+
fn test_only_t() {
166+
let res = get_chunks_of_tabs("\t\t");
167+
168+
assert_eq!(res, vec![(0, 2)]);
169+
}
170+
171+
#[test]
172+
fn test_only_one_t() {
173+
let res = get_chunks_of_tabs("\t");
174+
175+
assert_eq!(res, vec![(0, 1)]);
176+
}
177+
178+
#[test]
179+
fn test_double() {
180+
let res = get_chunks_of_tabs("sd\tasd\t\taa");
181+
182+
assert_eq!(res, vec![(2, 3), (6, 8)]);
183+
}
184+
185+
#[test]
186+
fn test_start() {
187+
let res = get_chunks_of_tabs("\t\taa");
188+
189+
assert_eq!(res, vec![(0, 2)]);
190+
}
191+
192+
#[test]
193+
fn test_end() {
194+
let res = get_chunks_of_tabs("aa\t\t");
195+
196+
assert_eq!(res, vec![(2, 4)]);
197+
}
198+
199+
#[test]
200+
fn test_start_single() {
201+
let res = get_chunks_of_tabs("\taa");
202+
203+
assert_eq!(res, vec![(0, 1)]);
204+
}
205+
206+
#[test]
207+
fn test_end_single() {
208+
let res = get_chunks_of_tabs("aa\t");
209+
210+
assert_eq!(res, vec![(2, 3)]);
211+
}
212+
213+
#[test]
214+
fn test_no_tabs() {
215+
let res = get_chunks_of_tabs("dsfs");
216+
217+
assert_eq!(res, vec![]);
218+
}
219+
}

src/lintlist/mod.rs

+7
Original file line numberDiff line numberDiff line change
@@ -1876,6 +1876,13 @@ pub const ALL_LINTS: [Lint; 334] = [
18761876
deprecation: None,
18771877
module: "formatting",
18781878
},
1879+
Lint {
1880+
name: "tabs_in_doc_comments",
1881+
group: "style",
1882+
desc: "using tabs in doc comments is not recommended",
1883+
deprecation: None,
1884+
module: "tabs_in_doc_comments",
1885+
},
18791886
Lint {
18801887
name: "temporary_assignment",
18811888
group: "complexity",

tests/ui/tabs_in_doc_comments.fixed

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// run-rustfix
2+
3+
#![warn(clippy::tabs_in_doc_comments)]
4+
#[allow(dead_code)]
5+
6+
///
7+
/// Struct to hold two strings:
8+
/// - first one
9+
/// - second one
10+
pub struct DoubleString {
11+
///
12+
/// - First String:
13+
/// - needs to be inside here
14+
first_string: String,
15+
///
16+
/// - Second String:
17+
/// - needs to be inside here
18+
second_string: String,
19+
}
20+
21+
/// This is main
22+
fn main() {}

tests/ui/tabs_in_doc_comments.rs

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// run-rustfix
2+
3+
#![warn(clippy::tabs_in_doc_comments)]
4+
#[allow(dead_code)]
5+
6+
///
7+
/// Struct to hold two strings:
8+
/// - first one
9+
/// - second one
10+
pub struct DoubleString {
11+
///
12+
/// - First String:
13+
/// - needs to be inside here
14+
first_string: String,
15+
///
16+
/// - Second String:
17+
/// - needs to be inside here
18+
second_string: String,
19+
}
20+
21+
/// This is main
22+
fn main() {}

tests/ui/tabs_in_doc_comments.stderr

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
error: using tabs in doc comments is not recommended
2+
--> $DIR/tabs_in_doc_comments.rs:12:9
3+
|
4+
LL | /// - First String:
5+
| ^^^^ help: consider using four spaces per tab
6+
|
7+
= note: `-D clippy::tabs-in-doc-comments` implied by `-D warnings`
8+
9+
error: using tabs in doc comments is not recommended
10+
--> $DIR/tabs_in_doc_comments.rs:13:9
11+
|
12+
LL | /// - needs to be inside here
13+
| ^^^^^^^^ help: consider using four spaces per tab
14+
15+
error: using tabs in doc comments is not recommended
16+
--> $DIR/tabs_in_doc_comments.rs:16:9
17+
|
18+
LL | /// - Second String:
19+
| ^^^^ help: consider using four spaces per tab
20+
21+
error: using tabs in doc comments is not recommended
22+
--> $DIR/tabs_in_doc_comments.rs:17:9
23+
|
24+
LL | /// - needs to be inside here
25+
| ^^^^^^^^ help: consider using four spaces per tab
26+
27+
error: using tabs in doc comments is not recommended
28+
--> $DIR/tabs_in_doc_comments.rs:8:5
29+
|
30+
LL | /// - first one
31+
| ^^^^ help: consider using four spaces per tab
32+
33+
error: using tabs in doc comments is not recommended
34+
--> $DIR/tabs_in_doc_comments.rs:8:13
35+
|
36+
LL | /// - first one
37+
| ^^^^^^^^ help: consider using four spaces per tab
38+
39+
error: using tabs in doc comments is not recommended
40+
--> $DIR/tabs_in_doc_comments.rs:9:5
41+
|
42+
LL | /// - second one
43+
| ^^^^ help: consider using four spaces per tab
44+
45+
error: using tabs in doc comments is not recommended
46+
--> $DIR/tabs_in_doc_comments.rs:9:14
47+
|
48+
LL | /// - second one
49+
| ^^^^ help: consider using four spaces per tab
50+
51+
error: aborting due to 8 previous errors
52+

0 commit comments

Comments
 (0)