Skip to content

Commit 5823e94

Browse files
committed
New is_integer_const to check more const ints
This mostly affects loop checks and the modulo_one lint. Tests were also updated where applicable.
1 parent 144d940 commit 5823e94

File tree

11 files changed

+98
-20
lines changed

11 files changed

+98
-20
lines changed

clippy_lints/src/loops.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ use syntax_pos::{BytePos, Symbol};
2727

2828
use crate::utils::paths;
2929
use crate::utils::{
30-
get_enclosing_block, get_parent_expr, has_iter_method, higher, is_integer_literal, is_refutable, last_path_segment,
30+
get_enclosing_block, get_parent_expr, has_iter_method, higher, is_integer_const, is_refutable, last_path_segment,
3131
match_trait_method, match_type, match_var, multispan_sugg, snippet, snippet_opt, snippet_with_applicability,
3232
span_help_and_lint, span_lint, span_lint_and_sugg, span_lint_and_then, SpanlessEq,
3333
};
@@ -1096,7 +1096,7 @@ fn check_for_loop_range<'a, 'tcx>(
10961096
return;
10971097
}
10981098

1099-
let starts_at_zero = is_integer_literal(start, 0);
1099+
let starts_at_zero = is_integer_const(cx, start, 0);
11001100

11011101
let skip = if starts_at_zero {
11021102
String::new()
@@ -2042,7 +2042,7 @@ impl<'a, 'tcx> Visitor<'tcx> for IncrementVisitor<'a, 'tcx> {
20422042
match parent.node {
20432043
ExprKind::AssignOp(op, ref lhs, ref rhs) => {
20442044
if lhs.hir_id == expr.hir_id {
2045-
if op.node == BinOpKind::Add && is_integer_literal(rhs, 1) {
2045+
if op.node == BinOpKind::Add && is_integer_const(self.cx, rhs, 1) {
20462046
*state = match *state {
20472047
VarState::Initial if self.depth == 0 => VarState::IncrOnce,
20482048
_ => VarState::DontWarn,
@@ -2094,7 +2094,7 @@ impl<'a, 'tcx> Visitor<'tcx> for InitializeVisitor<'a, 'tcx> {
20942094
self.name = Some(ident.name);
20952095

20962096
self.state = if let Some(ref init) = local.init {
2097-
if is_integer_literal(init, 0) {
2097+
if is_integer_const(&self.cx, init, 0) {
20982098
VarState::Warn
20992099
} else {
21002100
VarState::Declared
@@ -2130,7 +2130,7 @@ impl<'a, 'tcx> Visitor<'tcx> for InitializeVisitor<'a, 'tcx> {
21302130
self.state = VarState::DontWarn;
21312131
},
21322132
ExprKind::Assign(ref lhs, ref rhs) if lhs.hir_id == expr.hir_id => {
2133-
self.state = if is_integer_literal(rhs, 0) && self.depth == 0 {
2133+
self.state = if is_integer_const(&self.cx, rhs, 0) && self.depth == 0 {
21342134
VarState::Warn
21352135
} else {
21362136
VarState::DontWarn

clippy_lints/src/misc.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use syntax::source_map::{ExpnKind, Span};
1212
use crate::consts::{constant, Constant};
1313
use crate::utils::sugg::Sugg;
1414
use crate::utils::{
15-
get_item_name, get_parent_expr, implements_trait, in_constant, is_integer_literal, iter_input_pats,
15+
get_item_name, get_parent_expr, implements_trait, in_constant, is_integer_const, iter_input_pats,
1616
last_path_segment, match_qpath, match_trait_method, paths, snippet, span_lint, span_lint_and_then,
1717
span_lint_hir_and_then, walk_ptrs_ty, SpanlessEq,
1818
};
@@ -388,7 +388,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MiscLints {
388388
);
389389
db.span_note(expr.span, "std::f32::EPSILON and std::f64::EPSILON are available.");
390390
});
391-
} else if op == BinOpKind::Rem && is_integer_literal(right, 1) {
391+
} else if op == BinOpKind::Rem && is_integer_const(cx, right, 1) {
392392
span_lint(cx, MODULO_ONE, expr.span, "any number modulo 1 will be 0");
393393
}
394394
},

clippy_lints/src/ranges.rs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use syntax::source_map::Spanned;
88

99
use crate::utils::sugg::Sugg;
1010
use crate::utils::{get_trait_def_id, higher, implements_trait, SpanlessEq};
11-
use crate::utils::{is_integer_literal, paths, snippet, snippet_opt, span_lint, span_lint_and_then};
11+
use crate::utils::{is_integer_const, paths, snippet, snippet_opt, span_lint, span_lint_and_then};
1212

1313
declare_clippy_lint! {
1414
/// **What it does:** Checks for calling `.step_by(0)` on iterators,
@@ -132,7 +132,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Ranges {
132132
if iter_path.ident.name == sym!(iter);
133133
// range expression in `.zip()` call: `0..x.len()`
134134
if let Some(higher::Range { start: Some(start), end: Some(end), .. }) = higher::range(cx, zip_arg);
135-
if is_integer_literal(start, 0);
135+
if is_integer_const(cx, start, 0);
136136
// `.len()` call
137137
if let ExprKind::MethodCall(ref len_path, _, ref len_args) = end.node;
138138
if len_path.ident.name == sym!(len) && len_args.len() == 1;
@@ -164,7 +164,7 @@ fn check_exclusive_range_plus_one(cx: &LateContext<'_, '_>, expr: &Expr) {
164164
end: Some(end),
165165
limits: RangeLimits::HalfOpen
166166
}) = higher::range(cx, expr);
167-
if let Some(y) = y_plus_one(end);
167+
if let Some(y) = y_plus_one(cx, end);
168168
then {
169169
let span = if expr.span.from_expansion() {
170170
expr.span
@@ -209,7 +209,7 @@ fn check_exclusive_range_plus_one(cx: &LateContext<'_, '_>, expr: &Expr) {
209209
fn check_inclusive_range_minus_one(cx: &LateContext<'_, '_>, expr: &Expr) {
210210
if_chain! {
211211
if let Some(higher::Range { start, end: Some(end), limits: RangeLimits::Closed }) = higher::range(cx, expr);
212-
if let Some(y) = y_minus_one(end);
212+
if let Some(y) = y_minus_one(cx, end);
213213
then {
214214
span_lint_and_then(
215215
cx,
@@ -239,7 +239,7 @@ fn has_step_by(cx: &LateContext<'_, '_>, expr: &Expr) -> bool {
239239
get_trait_def_id(cx, &paths::ITERATOR).map_or(false, |iterator_trait| implements_trait(cx, ty, iterator_trait, &[]))
240240
}
241241

242-
fn y_plus_one(expr: &Expr) -> Option<&Expr> {
242+
fn y_plus_one<'t>(cx: &LateContext<'_, '_>, expr: &'t Expr) -> Option<&'t Expr> {
243243
match expr.node {
244244
ExprKind::Binary(
245245
Spanned {
@@ -248,9 +248,9 @@ fn y_plus_one(expr: &Expr) -> Option<&Expr> {
248248
ref lhs,
249249
ref rhs,
250250
) => {
251-
if is_integer_literal(lhs, 1) {
251+
if is_integer_const(cx, lhs, 1) {
252252
Some(rhs)
253-
} else if is_integer_literal(rhs, 1) {
253+
} else if is_integer_const(cx, rhs, 1) {
254254
Some(lhs)
255255
} else {
256256
None
@@ -260,15 +260,15 @@ fn y_plus_one(expr: &Expr) -> Option<&Expr> {
260260
}
261261
}
262262

263-
fn y_minus_one(expr: &Expr) -> Option<&Expr> {
263+
fn y_minus_one<'t>(cx: &LateContext<'_, '_>, expr: &'t Expr) -> Option<&'t Expr> {
264264
match expr.node {
265265
ExprKind::Binary(
266266
Spanned {
267267
node: BinOpKind::Sub, ..
268268
},
269269
ref lhs,
270270
ref rhs,
271-
) if is_integer_literal(rhs, 1) => Some(lhs),
271+
) if is_integer_const(cx, rhs, 1) => Some(lhs),
272272
_ => None,
273273
}
274274
}

clippy_lints/src/utils/mod.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ use syntax::source_map::{Span, DUMMY_SP};
4848
use syntax::symbol::{kw, Symbol};
4949

5050
use crate::reexport::*;
51+
use crate::consts::{constant, Constant};
5152

5253
/// Returns `true` if the two spans come from differing expansions (i.e., one is
5354
/// from a macro and one isn't).
@@ -669,6 +670,22 @@ pub fn walk_ptrs_ty_depth(ty: Ty<'_>) -> (Ty<'_>, usize) {
669670
inner(ty, 0)
670671
}
671672

673+
/// Checks whether the given expression is a constant integer of the given value.
674+
/// unlike `is_integer_literal`, this version does const folding
675+
pub fn is_integer_const(cx: &LateContext<'_, '_>, e: &Expr, value: u128) -> bool {
676+
if is_integer_literal(e, value) {
677+
return true;
678+
}
679+
let map = cx.tcx.hir();
680+
let parent_item = map.get_parent_item(e.hir_id);
681+
if let Some((Constant::Int(v), _)) = map.maybe_body_owned_by(parent_item)
682+
.and_then(|body_id| constant(cx, cx.tcx.body_tables(body_id), e)) {
683+
value == v
684+
} else {
685+
false
686+
}
687+
}
688+
672689
/// Checks whether the given expression is a constant literal of the given value.
673690
pub fn is_integer_literal(expr: &Expr, value: u128) -> bool {
674691
// FIXME: use constant folding

tests/ui/for_loop.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,14 @@ fn main() {
275275
for mid in 1..vec.len() {
276276
let (_, _) = vec.split_at(mid);
277277
}
278+
279+
const ZERO: usize = 0;
280+
281+
for i in ZERO..vec.len() {
282+
if f(&vec[i], &vec[i]) {
283+
panic!("at the disco");
284+
}
285+
}
278286
}
279287

280288
#[allow(dead_code)]

tests/ui/for_loop.stderr

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,5 +152,17 @@ LL | for _v in vec.iter().next() {}
152152
|
153153
= note: `-D clippy::iter-next-loop` implied by `-D warnings`
154154

155-
error: aborting due to 21 previous errors
155+
error: the loop variable `i` is only used to index `vec`.
156+
--> $DIR/for_loop.rs:281:14
157+
|
158+
LL | for i in ZERO..vec.len() {
159+
| ^^^^^^^^^^^^^^^
160+
|
161+
= note: `-D clippy::needless-range-loop` implied by `-D warnings`
162+
help: consider using an iterator
163+
|
164+
LL | for <item> in &vec {
165+
| ^^^^^^ ^^^^
166+
167+
error: aborting due to 22 previous errors
156168

tests/ui/modulo_one.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
11
#![warn(clippy::modulo_one)]
22
#![allow(clippy::no_effect, clippy::unnecessary_operation)]
33

4+
static STATIC_ONE: usize = 2 - 1;
5+
46
fn main() {
57
10 % 1;
68
10 % 2;
9+
10+
const ONE: u32 = 1 * 1;
11+
12+
2 % ONE;
13+
5 % STATIC_ONE;
714
}

tests/ui/modulo_one.stderr

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,30 @@
11
error: any number modulo 1 will be 0
2-
--> $DIR/modulo_one.rs:5:5
2+
--> $DIR/modulo_one.rs:7:5
33
|
44
LL | 10 % 1;
55
| ^^^^^^
66
|
77
= note: `-D clippy::modulo-one` implied by `-D warnings`
88

9-
error: aborting due to previous error
9+
error: the operation is ineffective. Consider reducing it to `1`
10+
--> $DIR/modulo_one.rs:10:22
11+
|
12+
LL | const ONE: u32 = 1 * 1;
13+
| ^^^^^
14+
|
15+
= note: `-D clippy::identity-op` implied by `-D warnings`
16+
17+
error: the operation is ineffective. Consider reducing it to `1`
18+
--> $DIR/modulo_one.rs:10:22
19+
|
20+
LL | const ONE: u32 = 1 * 1;
21+
| ^^^^^
22+
23+
error: any number modulo 1 will be 0
24+
--> $DIR/modulo_one.rs:12:5
25+
|
26+
LL | 2 % ONE;
27+
| ^^^^^^^
28+
29+
error: aborting due to 4 previous errors
1030

tests/ui/range_plus_minus_one.fixed

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ fn main() {
3232
let _ = (1..=11);
3333
let _ = ((f() + 1)..=f());
3434

35+
const ONE: usize = 1;
36+
// integer consts are linted, too
37+
for _ in 1..=ONE {}
38+
3539
let mut vec: Vec<()> = std::vec::Vec::new();
3640
vec.drain(..);
3741
}

tests/ui/range_plus_minus_one.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ fn main() {
3232
let _ = (1..11 + 1);
3333
let _ = (f() + 1)..(f() + 1);
3434

35+
const ONE: usize = 1;
36+
// integer consts are linted, too
37+
for _ in 1..ONE + ONE {}
38+
3539
let mut vec: Vec<()> = std::vec::Vec::new();
3640
vec.drain(..);
3741
}

tests/ui/range_plus_minus_one.stderr

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,5 +50,11 @@ error: an inclusive range would be more readable
5050
LL | let _ = (f() + 1)..(f() + 1);
5151
| ^^^^^^^^^^^^^^^^^^^^ help: use: `((f() + 1)..=f())`
5252

53-
error: aborting due to 8 previous errors
53+
error: an inclusive range would be more readable
54+
--> $DIR/range_plus_minus_one.rs:37:14
55+
|
56+
LL | for _ in 1..ONE + ONE {}
57+
| ^^^^^^^^^^^^ help: use: `1..=ONE`
58+
59+
error: aborting due to 9 previous errors
5460

0 commit comments

Comments
 (0)