Skip to content

Commit 35a559f

Browse files
committed
Auto merge of #4839 - flip1995:rollup-new-lints, r=flip1995
Rollup of 4 Pull requests with new lints Rollup of pull requests - #4816 (New lint: zst_offset) - #4814 (New lint: Implement ifs_same_cond_fn) - #4807 (Add `large_stack_arrays` lint) - #4806 (Issue/4623) changelog: add [`zst_offset`] lint changelog: New lint: [`ifs_same_cond_fn`] cahngelog: Add new lint [large_stack_arrays] changelog: added lint [`tabs_in_doc_comments`]
2 parents 60e8413 + 7cc8fa2 commit 35a559f

19 files changed

+786
-4
lines changed

CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -1059,6 +1059,7 @@ Released 2018-09-13
10591059
[`just_underscores_and_digits`]: https://rust-lang.github.io/rust-clippy/master/index.html#just_underscores_and_digits
10601060
[`large_digit_groups`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_digit_groups
10611061
[`large_enum_variant`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_enum_variant
1062+
[`large_stack_arrays`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_stack_arrays
10621063
[`len_without_is_empty`]: https://rust-lang.github.io/rust-clippy/master/index.html#len_without_is_empty
10631064
[`len_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#len_zero
10641065
[`let_and_return`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_and_return
@@ -1176,6 +1177,7 @@ Released 2018-09-13
11761177
[`result_map_unwrap_or_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_map_unwrap_or_else
11771178
[`result_unwrap_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_unwrap_used
11781179
[`reverse_range_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#reverse_range_loop
1180+
[`same_functions_in_if_condition`]: https://rust-lang.github.io/rust-clippy/master/index.html#same_functions_in_if_condition
11791181
[`search_is_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#search_is_some
11801182
[`serde_api_misuse`]: https://rust-lang.github.io/rust-clippy/master/index.html#serde_api_misuse
11811183
[`shadow_reuse`]: https://rust-lang.github.io/rust-clippy/master/index.html#shadow_reuse
@@ -1201,6 +1203,7 @@ Released 2018-09-13
12011203
[`suspicious_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_map
12021204
[`suspicious_op_assign_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_op_assign_impl
12031205
[`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
12041207
[`temporary_assignment`]: https://rust-lang.github.io/rust-clippy/master/index.html#temporary_assignment
12051208
[`temporary_cstring_as_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#temporary_cstring_as_ptr
12061209
[`to_digit_is_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#to_digit_is_some
@@ -1273,4 +1276,5 @@ Released 2018-09-13
12731276
[`zero_prefixed_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_prefixed_literal
12741277
[`zero_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_ptr
12751278
[`zero_width_space`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_width_space
1279+
[`zst_offset`]: https://rust-lang.github.io/rust-clippy/master/index.html#zst_offset
12761280
<!-- end autogenerated links to lint list -->

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code.
88

9-
[There are 333 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
9+
[There are 337 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
1010

1111
We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you:
1212

clippy_lints/src/copies.rs

+77-1
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,53 @@ declare_clippy_lint! {
4040
"consecutive `ifs` with the same condition"
4141
}
4242

43+
declare_clippy_lint! {
44+
/// **What it does:** Checks for consecutive `if`s with the same function call.
45+
///
46+
/// **Why is this bad?** This is probably a copy & paste error.
47+
/// Despite the fact that function can have side effects and `if` works as
48+
/// intended, such an approach is implicit and can be considered a "code smell".
49+
///
50+
/// **Known problems:** Hopefully none.
51+
///
52+
/// **Example:**
53+
/// ```ignore
54+
/// if foo() == bar {
55+
/// …
56+
/// } else if foo() == bar {
57+
/// …
58+
/// }
59+
/// ```
60+
///
61+
/// This probably should be:
62+
/// ```ignore
63+
/// if foo() == bar {
64+
/// …
65+
/// } else if foo() == baz {
66+
/// …
67+
/// }
68+
/// ```
69+
///
70+
/// or if the original code was not a typo and called function mutates a state,
71+
/// consider move the mutation out of the `if` condition to avoid similarity to
72+
/// a copy & paste error:
73+
///
74+
/// ```ignore
75+
/// let first = foo();
76+
/// if first == bar {
77+
/// …
78+
/// } else {
79+
/// let second = foo();
80+
/// if second == bar {
81+
/// …
82+
/// }
83+
/// }
84+
/// ```
85+
pub SAME_FUNCTIONS_IN_IF_CONDITION,
86+
pedantic,
87+
"consecutive `ifs` with the same function call"
88+
}
89+
4390
declare_clippy_lint! {
4491
/// **What it does:** Checks for `if/else` with the same body as the *then* part
4592
/// and the *else* part.
@@ -102,7 +149,7 @@ declare_clippy_lint! {
102149
"`match` with identical arm bodies"
103150
}
104151

105-
declare_lint_pass!(CopyAndPaste => [IFS_SAME_COND, IF_SAME_THEN_ELSE, MATCH_SAME_ARMS]);
152+
declare_lint_pass!(CopyAndPaste => [IFS_SAME_COND, SAME_FUNCTIONS_IN_IF_CONDITION, IF_SAME_THEN_ELSE, MATCH_SAME_ARMS]);
106153

107154
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for CopyAndPaste {
108155
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
@@ -119,6 +166,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for CopyAndPaste {
119166
let (conds, blocks) = if_sequence(expr);
120167
lint_same_then_else(cx, &blocks);
121168
lint_same_cond(cx, &conds);
169+
lint_same_fns_in_if_cond(cx, &conds);
122170
lint_match_arms(cx, expr);
123171
}
124172
}
@@ -163,6 +211,34 @@ fn lint_same_cond(cx: &LateContext<'_, '_>, conds: &[&Expr]) {
163211
}
164212
}
165213

214+
/// Implementation of `SAME_FUNCTIONS_IN_IF_CONDITION`.
215+
fn lint_same_fns_in_if_cond(cx: &LateContext<'_, '_>, conds: &[&Expr]) {
216+
let hash: &dyn Fn(&&Expr) -> u64 = &|expr| -> u64 {
217+
let mut h = SpanlessHash::new(cx, cx.tables);
218+
h.hash_expr(expr);
219+
h.finish()
220+
};
221+
222+
let eq: &dyn Fn(&&Expr, &&Expr) -> bool = &|&lhs, &rhs| -> bool {
223+
// Do not spawn warning if `IFS_SAME_COND` already produced it.
224+
if SpanlessEq::new(cx).ignore_fn().eq_expr(lhs, rhs) {
225+
return false;
226+
}
227+
SpanlessEq::new(cx).eq_expr(lhs, rhs)
228+
};
229+
230+
for (i, j) in search_same(conds, hash, eq) {
231+
span_note_and_lint(
232+
cx,
233+
SAME_FUNCTIONS_IN_IF_CONDITION,
234+
j.span,
235+
"this `if` has the same function call as a previous if",
236+
i.span,
237+
"same as this",
238+
);
239+
}
240+
}
241+
166242
/// Implementation of `MATCH_SAME_ARMS`.
167243
fn lint_match_arms<'tcx>(cx: &LateContext<'_, 'tcx>, expr: &Expr) {
168244
fn same_bindings<'tcx>(
+68
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
use rustc::hir::*;
2+
use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
3+
use rustc::mir::interpret::ConstValue;
4+
use rustc::ty::{self, ConstKind};
5+
use rustc::{declare_tool_lint, impl_lint_pass};
6+
7+
use if_chain::if_chain;
8+
9+
use crate::rustc_target::abi::LayoutOf;
10+
use crate::utils::{snippet, span_help_and_lint};
11+
12+
declare_clippy_lint! {
13+
/// **What it does:** Checks for local arrays that may be too large.
14+
///
15+
/// **Why is this bad?** Large local arrays may cause stack overflow.
16+
///
17+
/// **Known problems:** None.
18+
///
19+
/// **Example:**
20+
/// ```rust,ignore
21+
/// let a = [0u32; 1_000_000];
22+
/// ```
23+
pub LARGE_STACK_ARRAYS,
24+
pedantic,
25+
"allocating large arrays on stack may cause stack overflow"
26+
}
27+
28+
pub struct LargeStackArrays {
29+
maximum_allowed_size: u64,
30+
}
31+
32+
impl LargeStackArrays {
33+
#[must_use]
34+
pub fn new(maximum_allowed_size: u64) -> Self {
35+
Self { maximum_allowed_size }
36+
}
37+
}
38+
39+
impl_lint_pass!(LargeStackArrays => [LARGE_STACK_ARRAYS]);
40+
41+
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LargeStackArrays {
42+
fn check_expr(&mut self, cx: &LateContext<'_, '_>, expr: &Expr) {
43+
if_chain! {
44+
if let ExprKind::Repeat(_, _) = expr.kind;
45+
if let ty::Array(element_type, cst) = cx.tables.expr_ty(expr).kind;
46+
if let ConstKind::Value(val) = cst.val;
47+
if let ConstValue::Scalar(element_count) = val;
48+
if let Ok(element_count) = element_count.to_machine_usize(&cx.tcx);
49+
if let Ok(element_size) = cx.layout_of(element_type).map(|l| l.size.bytes());
50+
if self.maximum_allowed_size < element_count * element_size;
51+
then {
52+
span_help_and_lint(
53+
cx,
54+
LARGE_STACK_ARRAYS,
55+
expr.span,
56+
&format!(
57+
"allocating a local array larger than {} bytes",
58+
self.maximum_allowed_size
59+
),
60+
&format!(
61+
"consider allocating on the heap with vec!{}.into_boxed_slice()",
62+
snippet(cx, expr.span, "[...]")
63+
),
64+
);
65+
}
66+
}
67+
}
68+
}

clippy_lints/src/lib.rs

+15
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,7 @@ pub mod int_plus_one;
212212
pub mod integer_division;
213213
pub mod items_after_statements;
214214
pub mod large_enum_variant;
215+
pub mod large_stack_arrays;
215216
pub mod len_zero;
216217
pub mod let_if_seq;
217218
pub mod lifetimes;
@@ -274,6 +275,7 @@ pub mod slow_vector_initialization;
274275
pub mod strings;
275276
pub mod suspicious_trait_impl;
276277
pub mod swap;
278+
pub mod tabs_in_doc_comments;
277279
pub mod temporary_assignment;
278280
pub mod to_digit_is_some;
279281
pub mod trait_bounds;
@@ -472,6 +474,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf
472474
&copies::IFS_SAME_COND,
473475
&copies::IF_SAME_THEN_ELSE,
474476
&copies::MATCH_SAME_ARMS,
477+
&copies::SAME_FUNCTIONS_IN_IF_CONDITION,
475478
&copy_iterator::COPY_ITERATOR,
476479
&dbg_macro::DBG_MACRO,
477480
&default_trait_access::DEFAULT_TRAIT_ACCESS,
@@ -538,6 +541,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf
538541
&integer_division::INTEGER_DIVISION,
539542
&items_after_statements::ITEMS_AFTER_STATEMENTS,
540543
&large_enum_variant::LARGE_ENUM_VARIANT,
544+
&large_stack_arrays::LARGE_STACK_ARRAYS,
541545
&len_zero::LEN_WITHOUT_IS_EMPTY,
542546
&len_zero::LEN_ZERO,
543547
&let_if_seq::USELESS_LET_IF_SEQ,
@@ -624,6 +628,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf
624628
&methods::USELESS_ASREF,
625629
&methods::WRONG_PUB_SELF_CONVENTION,
626630
&methods::WRONG_SELF_CONVENTION,
631+
&methods::ZST_OFFSET,
627632
&minmax::MIN_MAX,
628633
&misc::CMP_NAN,
629634
&misc::CMP_OWNED,
@@ -716,6 +721,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf
716721
&suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL,
717722
&swap::ALMOST_SWAPPED,
718723
&swap::MANUAL_SWAP,
724+
&tabs_in_doc_comments::TABS_IN_DOC_COMMENTS,
719725
&temporary_assignment::TEMPORARY_ASSIGNMENT,
720726
&to_digit_is_some::TO_DIGIT_IS_SOME,
721727
&trait_bounds::TYPE_REPETITION_IN_BOUNDS,
@@ -946,10 +952,13 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf
946952
store.register_early_pass(|| box utils::internal_lints::ClippyLintsInternal);
947953
let enum_variant_name_threshold = conf.enum_variant_name_threshold;
948954
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);
949956
store.register_late_pass(|| box unused_self::UnusedSelf);
950957
store.register_late_pass(|| box mutable_debug_assertion::DebugAssertWithMutCall);
951958
store.register_late_pass(|| box exit::Exit);
952959
store.register_late_pass(|| box to_digit_is_some::ToDigitIsSome);
960+
let array_size_threshold = conf.array_size_threshold;
961+
store.register_late_pass(move || box large_stack_arrays::LargeStackArrays::new(array_size_threshold));
953962

954963
store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![
955964
LintId::of(&arithmetic::FLOAT_ARITHMETIC),
@@ -989,6 +998,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf
989998
LintId::of(&attrs::INLINE_ALWAYS),
990999
LintId::of(&checked_conversions::CHECKED_CONVERSIONS),
9911000
LintId::of(&copies::MATCH_SAME_ARMS),
1001+
LintId::of(&copies::SAME_FUNCTIONS_IN_IF_CONDITION),
9921002
LintId::of(&copy_iterator::COPY_ITERATOR),
9931003
LintId::of(&default_trait_access::DEFAULT_TRAIT_ACCESS),
9941004
LintId::of(&derive::EXPL_IMPL_CLONE_ON_COPY),
@@ -1003,6 +1013,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf
10031013
LintId::of(&if_not_else::IF_NOT_ELSE),
10041014
LintId::of(&infinite_iter::MAYBE_INFINITE_ITER),
10051015
LintId::of(&items_after_statements::ITEMS_AFTER_STATEMENTS),
1016+
LintId::of(&large_stack_arrays::LARGE_STACK_ARRAYS),
10061017
LintId::of(&literal_representation::LARGE_DIGIT_GROUPS),
10071018
LintId::of(&loops::EXPLICIT_INTO_ITER_LOOP),
10081019
LintId::of(&loops::EXPLICIT_ITER_LOOP),
@@ -1176,6 +1187,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf
11761187
LintId::of(&methods::UNNECESSARY_FOLD),
11771188
LintId::of(&methods::USELESS_ASREF),
11781189
LintId::of(&methods::WRONG_SELF_CONVENTION),
1190+
LintId::of(&methods::ZST_OFFSET),
11791191
LintId::of(&minmax::MIN_MAX),
11801192
LintId::of(&misc::CMP_NAN),
11811193
LintId::of(&misc::CMP_OWNED),
@@ -1243,6 +1255,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf
12431255
LintId::of(&suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL),
12441256
LintId::of(&swap::ALMOST_SWAPPED),
12451257
LintId::of(&swap::MANUAL_SWAP),
1258+
LintId::of(&tabs_in_doc_comments::TABS_IN_DOC_COMMENTS),
12461259
LintId::of(&temporary_assignment::TEMPORARY_ASSIGNMENT),
12471260
LintId::of(&to_digit_is_some::TO_DIGIT_IS_SOME),
12481261
LintId::of(&transmute::CROSSPOINTER_TRANSMUTE),
@@ -1370,6 +1383,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf
13701383
LintId::of(&returns::NEEDLESS_RETURN),
13711384
LintId::of(&returns::UNUSED_UNIT),
13721385
LintId::of(&strings::STRING_LIT_AS_BYTES),
1386+
LintId::of(&tabs_in_doc_comments::TABS_IN_DOC_COMMENTS),
13731387
LintId::of(&to_digit_is_some::TO_DIGIT_IS_SOME),
13741388
LintId::of(&try_err::TRY_ERR),
13751389
LintId::of(&types::FN_TO_NUMERIC_CAST),
@@ -1497,6 +1511,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf
14971511
LintId::of(&methods::CLONE_DOUBLE_REF),
14981512
LintId::of(&methods::TEMPORARY_CSTRING_AS_PTR),
14991513
LintId::of(&methods::UNINIT_ASSUMED_INIT),
1514+
LintId::of(&methods::ZST_OFFSET),
15001515
LintId::of(&minmax::MIN_MAX),
15011516
LintId::of(&misc::CMP_NAN),
15021517
LintId::of(&misc::FLOAT_CMP),

clippy_lints/src/methods/mod.rs

+33
Original file line numberDiff line numberDiff line change
@@ -1065,6 +1065,23 @@ declare_clippy_lint! {
10651065
"`.chcked_add/sub(x).unwrap_or(MAX/MIN)`"
10661066
}
10671067

1068+
declare_clippy_lint! {
1069+
/// **What it does:** Checks for `offset(_)`, `wrapping_`{`add`, `sub`}, etc. on raw pointers to
1070+
/// zero-sized types
1071+
///
1072+
/// **Why is this bad?** This is a no-op, and likely unintended
1073+
///
1074+
/// **Known problems:** None
1075+
///
1076+
/// **Example:**
1077+
/// ```ignore
1078+
/// unsafe { (&() as *const ()).offest(1) };
1079+
/// ```
1080+
pub ZST_OFFSET,
1081+
correctness,
1082+
"Check for offset calculations on raw pointers to zero-sized types"
1083+
}
1084+
10681085
declare_lint_pass!(Methods => [
10691086
OPTION_UNWRAP_USED,
10701087
RESULT_UNWRAP_USED,
@@ -1109,6 +1126,7 @@ declare_lint_pass!(Methods => [
11091126
SUSPICIOUS_MAP,
11101127
UNINIT_ASSUMED_INIT,
11111128
MANUAL_SATURATING_ARITHMETIC,
1129+
ZST_OFFSET,
11121130
]);
11131131

11141132
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Methods {
@@ -1167,6 +1185,9 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Methods {
11671185
| ["unwrap_or", arith @ "checked_mul"] => {
11681186
manual_saturating_arithmetic::lint(cx, expr, &arg_lists, &arith["checked_".len()..])
11691187
},
1188+
["add"] | ["offset"] | ["sub"] | ["wrapping_offset"] | ["wrapping_add"] | ["wrapping_sub"] => {
1189+
check_pointer_offset(cx, expr, arg_lists[0])
1190+
},
11701191
_ => {},
11711192
}
11721193

@@ -3063,3 +3084,15 @@ fn contains_return(expr: &hir::Expr) -> bool {
30633084
visitor.visit_expr(expr);
30643085
visitor.found
30653086
}
3087+
3088+
fn check_pointer_offset(cx: &LateContext<'_, '_>, expr: &hir::Expr, args: &[hir::Expr]) {
3089+
if_chain! {
3090+
if args.len() == 2;
3091+
if let ty::RawPtr(ty::TypeAndMut { ref ty, .. }) = cx.tables.expr_ty(&args[0]).kind;
3092+
if let Ok(layout) = cx.tcx.layout_of(cx.param_env.and(ty));
3093+
if layout.is_zst();
3094+
then {
3095+
span_lint(cx, ZST_OFFSET, expr.span, "offset calculation on zero-sized value");
3096+
}
3097+
}
3098+
}

0 commit comments

Comments
 (0)