Skip to content

Commit 8ed05ab

Browse files
authored
Fix missing_asserts_for_indexing changes assert_eq to assert (#16040)
Closes #16026 changelog: [`missing_asserts_for_indexing`] fix wrongly changing `assert_eq` to `assert`
2 parents c004be4 + 0ab135f commit 8ed05ab

File tree

4 files changed

+124
-21
lines changed

4 files changed

+124
-21
lines changed

clippy_lints/src/missing_asserts_for_indexing.rs

Lines changed: 41 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,11 @@ use std::ops::ControlFlow;
33

44
use clippy_utils::comparisons::{Rel, normalize_comparison};
55
use clippy_utils::diagnostics::span_lint_and_then;
6-
use clippy_utils::macros::{find_assert_eq_args, first_node_macro_backtrace};
6+
use clippy_utils::higher::{If, Range};
7+
use clippy_utils::macros::{find_assert_eq_args, first_node_macro_backtrace, root_macro_call};
78
use clippy_utils::source::snippet;
89
use clippy_utils::visitors::for_each_expr_without_closures;
9-
use clippy_utils::{eq_expr_value, hash_expr, higher};
10+
use clippy_utils::{eq_expr_value, hash_expr};
1011
use rustc_ast::{BinOpKind, LitKind, RangeLimits};
1112
use rustc_data_structures::packed::Pu128;
1213
use rustc_data_structures::unhash::UnindexMap;
@@ -15,7 +16,7 @@ use rustc_hir::{Block, Body, Expr, ExprKind, UnOp};
1516
use rustc_lint::{LateContext, LateLintPass};
1617
use rustc_session::declare_lint_pass;
1718
use rustc_span::source_map::Spanned;
18-
use rustc_span::{Span, sym};
19+
use rustc_span::{Span, Symbol, sym};
1920

2021
declare_clippy_lint! {
2122
/// ### What it does
@@ -134,15 +135,15 @@ fn len_comparison<'hir>(
134135
fn assert_len_expr<'hir>(
135136
cx: &LateContext<'_>,
136137
expr: &'hir Expr<'hir>,
137-
) -> Option<(LengthComparison, usize, &'hir Expr<'hir>)> {
138-
let (cmp, asserted_len, slice_len) = if let Some(higher::If { cond, then, .. }) = higher::If::hir(expr)
138+
) -> Option<(LengthComparison, usize, &'hir Expr<'hir>, Symbol)> {
139+
let ((cmp, asserted_len, slice_len), macro_call) = if let Some(If { cond, then, .. }) = If::hir(expr)
139140
&& let ExprKind::Unary(UnOp::Not, condition) = &cond.kind
140141
&& let ExprKind::Binary(bin_op, left, right) = &condition.kind
141142
// check if `then` block has a never type expression
142143
&& let ExprKind::Block(Block { expr: Some(then_expr), .. }, _) = then.kind
143144
&& cx.typeck_results().expr_ty(then_expr).is_never()
144145
{
145-
len_comparison(bin_op.node, left, right)?
146+
(len_comparison(bin_op.node, left, right)?, sym::assert_macro)
146147
} else if let Some((macro_call, bin_op)) = first_node_macro_backtrace(cx, expr).find_map(|macro_call| {
147148
match cx.tcx.get_diagnostic_name(macro_call.def_id) {
148149
Some(sym::assert_eq_macro) => Some((macro_call, BinOpKind::Eq)),
@@ -151,7 +152,12 @@ fn assert_len_expr<'hir>(
151152
}
152153
}) && let Some((left, right, _)) = find_assert_eq_args(cx, expr, macro_call.expn)
153154
{
154-
len_comparison(bin_op, left, right)?
155+
(
156+
len_comparison(bin_op, left, right)?,
157+
root_macro_call(expr.span)
158+
.and_then(|macro_call| cx.tcx.get_diagnostic_name(macro_call.def_id))
159+
.unwrap_or(sym::assert_macro),
160+
)
155161
} else {
156162
return None;
157163
};
@@ -160,7 +166,7 @@ fn assert_len_expr<'hir>(
160166
&& cx.typeck_results().expr_ty_adjusted(recv).peel_refs().is_slice()
161167
&& method.ident.name == sym::len
162168
{
163-
Some((cmp, asserted_len, recv))
169+
Some((cmp, asserted_len, recv, macro_call))
164170
} else {
165171
None
166172
}
@@ -174,6 +180,7 @@ enum IndexEntry<'hir> {
174180
comparison: LengthComparison,
175181
assert_span: Span,
176182
slice: &'hir Expr<'hir>,
183+
macro_call: Symbol,
177184
},
178185
/// `assert!` with indexing
179186
///
@@ -187,6 +194,7 @@ enum IndexEntry<'hir> {
187194
slice: &'hir Expr<'hir>,
188195
indexes: Vec<Span>,
189196
comparison: LengthComparison,
197+
macro_call: Symbol,
190198
},
191199
/// Indexing without an `assert!`
192200
IndexWithoutAssert {
@@ -225,9 +233,9 @@ fn upper_index_expr(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<usize> {
225233
&& let LitKind::Int(Pu128(index), _) = lit.node
226234
{
227235
Some(index as usize)
228-
} else if let Some(higher::Range {
236+
} else if let Some(Range {
229237
end: Some(end), limits, ..
230-
}) = higher::Range::hir(cx, expr)
238+
}) = Range::hir(cx, expr)
231239
&& let ExprKind::Lit(lit) = &end.kind
232240
&& let LitKind::Int(Pu128(index @ 1..), _) = lit.node
233241
{
@@ -258,6 +266,7 @@ fn check_index<'hir>(cx: &LateContext<'_>, expr: &'hir Expr<'hir>, map: &mut Uni
258266
comparison,
259267
assert_span,
260268
slice,
269+
macro_call,
261270
} => {
262271
if slice.span.lo() > assert_span.lo() {
263272
*entry = IndexEntry::AssertWithIndex {
@@ -268,6 +277,7 @@ fn check_index<'hir>(cx: &LateContext<'_>, expr: &'hir Expr<'hir>, map: &mut Uni
268277
slice,
269278
indexes: vec![expr.span],
270279
comparison: *comparison,
280+
macro_call: *macro_call,
271281
};
272282
}
273283
},
@@ -303,7 +313,7 @@ fn check_index<'hir>(cx: &LateContext<'_>, expr: &'hir Expr<'hir>, map: &mut Uni
303313

304314
/// Checks if the expression is an `assert!` expression and adds it to `asserts`
305315
fn check_assert<'hir>(cx: &LateContext<'_>, expr: &'hir Expr<'hir>, map: &mut UnindexMap<u64, Vec<IndexEntry<'hir>>>) {
306-
if let Some((comparison, asserted_len, slice)) = assert_len_expr(cx, expr) {
316+
if let Some((comparison, asserted_len, slice, macro_call)) = assert_len_expr(cx, expr) {
307317
let hash = hash_expr(cx, slice);
308318
let indexes = map.entry(hash).or_default();
309319

@@ -326,6 +336,7 @@ fn check_assert<'hir>(cx: &LateContext<'_>, expr: &'hir Expr<'hir>, map: &mut Un
326336
assert_span: expr.span.source_callsite(),
327337
comparison,
328338
asserted_len,
339+
macro_call,
329340
};
330341
}
331342
} else {
@@ -334,6 +345,7 @@ fn check_assert<'hir>(cx: &LateContext<'_>, expr: &'hir Expr<'hir>, map: &mut Un
334345
comparison,
335346
assert_span: expr.span.source_callsite(),
336347
slice,
348+
macro_call,
337349
});
338350
}
339351
}
@@ -362,6 +374,7 @@ fn report_indexes(cx: &LateContext<'_>, map: &UnindexMap<u64, Vec<IndexEntry<'_>
362374
comparison,
363375
assert_span,
364376
slice,
377+
macro_call,
365378
} if indexes.len() > 1 && !is_first_highest => {
366379
// if we have found an `assert!`, let's also check that it's actually right
367380
// and if it covers the highest index and if not, suggest the correct length
@@ -382,11 +395,23 @@ fn report_indexes(cx: &LateContext<'_>, map: &UnindexMap<u64, Vec<IndexEntry<'_>
382395
snippet(cx, slice.span, "..")
383396
)),
384397
// `highest_index` here is rather a length, so we need to add 1 to it
385-
LengthComparison::LengthEqualInt if asserted_len < highest_index + 1 => Some(format!(
386-
"assert!({}.len() == {})",
387-
snippet(cx, slice.span, ".."),
388-
highest_index + 1
389-
)),
398+
LengthComparison::LengthEqualInt if asserted_len < highest_index + 1 => match macro_call {
399+
sym::assert_eq_macro => Some(format!(
400+
"assert_eq!({}.len(), {})",
401+
snippet(cx, slice.span, ".."),
402+
highest_index + 1
403+
)),
404+
sym::debug_assert_eq_macro => Some(format!(
405+
"debug_assert_eq!({}.len(), {})",
406+
snippet(cx, slice.span, ".."),
407+
highest_index + 1
408+
)),
409+
_ => Some(format!(
410+
"assert!({}.len() == {})",
411+
snippet(cx, slice.span, ".."),
412+
highest_index + 1
413+
)),
414+
},
390415
_ => None,
391416
};
392417

tests/ui/missing_asserts_for_indexing.fixed

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -150,9 +150,9 @@ fn highest_index_first(v1: &[u8]) {
150150
}
151151

152152
fn issue14255(v1: &[u8], v2: &[u8], v3: &[u8], v4: &[u8]) {
153-
assert!(v1.len() == 3);
153+
assert_eq!(v1.len(), 3);
154154
assert_eq!(v2.len(), 4);
155-
assert!(v3.len() == 3);
155+
assert_eq!(v3.len(), 3);
156156
assert_eq!(4, v4.len());
157157

158158
let _ = v1[0] + v1[1] + v1[2];
@@ -166,4 +166,18 @@ fn issue14255(v1: &[u8], v2: &[u8], v3: &[u8], v4: &[u8]) {
166166
let _ = v4[0] + v4[1] + v4[2];
167167
}
168168

169+
mod issue15988 {
170+
fn assert_eq_len(v: &[i32]) {
171+
assert_eq!(v.len(), 3);
172+
let _ = v[0] + v[1] + v[2];
173+
//~^ missing_asserts_for_indexing
174+
}
175+
176+
fn debug_assert_eq_len(v: &[i32]) {
177+
debug_assert_eq!(v.len(), 3);
178+
let _ = v[0] + v[1] + v[2];
179+
//~^ missing_asserts_for_indexing
180+
}
181+
}
182+
169183
fn main() {}

tests/ui/missing_asserts_for_indexing.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,4 +166,18 @@ fn issue14255(v1: &[u8], v2: &[u8], v3: &[u8], v4: &[u8]) {
166166
let _ = v4[0] + v4[1] + v4[2];
167167
}
168168

169+
mod issue15988 {
170+
fn assert_eq_len(v: &[i32]) {
171+
assert_eq!(v.len(), 2);
172+
let _ = v[0] + v[1] + v[2];
173+
//~^ missing_asserts_for_indexing
174+
}
175+
176+
fn debug_assert_eq_len(v: &[i32]) {
177+
debug_assert_eq!(v.len(), 2);
178+
let _ = v[0] + v[1] + v[2];
179+
//~^ missing_asserts_for_indexing
180+
}
181+
}
182+
169183
fn main() {}

tests/ui/missing_asserts_for_indexing.stderr

Lines changed: 53 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,7 @@ error: indexing into a slice multiple times with an `assert` that does not cover
305305
--> tests/ui/missing_asserts_for_indexing.rs:158:13
306306
|
307307
LL | assert_eq!(v1.len(), 2);
308-
| ----------------------- help: provide the highest index that is indexed with: `assert!(v1.len() == 3)`
308+
| ----------------------- help: provide the highest index that is indexed with: `assert_eq!(v1.len(), 3)`
309309
...
310310
LL | let _ = v1[0] + v1[1] + v1[2];
311311
| ^^^^^^^^^^^^^^^^^^^^^
@@ -331,7 +331,7 @@ error: indexing into a slice multiple times with an `assert` that does not cover
331331
--> tests/ui/missing_asserts_for_indexing.rs:163:13
332332
|
333333
LL | assert_eq!(2, v3.len());
334-
| ----------------------- help: provide the highest index that is indexed with: `assert!(v3.len() == 3)`
334+
| ----------------------- help: provide the highest index that is indexed with: `assert_eq!(v3.len(), 3)`
335335
...
336336
LL | let _ = v3[0] + v3[1] + v3[2];
337337
| ^^^^^^^^^^^^^^^^^^^^^
@@ -353,5 +353,55 @@ LL | let _ = v3[0] + v3[1] + v3[2];
353353
| ^^^^^
354354
= note: asserting the length before indexing will elide bounds checks
355355

356-
error: aborting due to 13 previous errors
356+
error: indexing into a slice multiple times with an `assert` that does not cover the highest index
357+
--> tests/ui/missing_asserts_for_indexing.rs:172:17
358+
|
359+
LL | assert_eq!(v.len(), 2);
360+
| ---------------------- help: provide the highest index that is indexed with: `assert_eq!(v.len(), 3)`
361+
LL | let _ = v[0] + v[1] + v[2];
362+
| ^^^^^^^^^^^^^^^^^^
363+
|
364+
note: slice indexed here
365+
--> tests/ui/missing_asserts_for_indexing.rs:172:17
366+
|
367+
LL | let _ = v[0] + v[1] + v[2];
368+
| ^^^^
369+
note: slice indexed here
370+
--> tests/ui/missing_asserts_for_indexing.rs:172:24
371+
|
372+
LL | let _ = v[0] + v[1] + v[2];
373+
| ^^^^
374+
note: slice indexed here
375+
--> tests/ui/missing_asserts_for_indexing.rs:172:31
376+
|
377+
LL | let _ = v[0] + v[1] + v[2];
378+
| ^^^^
379+
= note: asserting the length before indexing will elide bounds checks
380+
381+
error: indexing into a slice multiple times with an `assert` that does not cover the highest index
382+
--> tests/ui/missing_asserts_for_indexing.rs:178:17
383+
|
384+
LL | debug_assert_eq!(v.len(), 2);
385+
| ---------------------------- help: provide the highest index that is indexed with: `debug_assert_eq!(v.len(), 3)`
386+
LL | let _ = v[0] + v[1] + v[2];
387+
| ^^^^^^^^^^^^^^^^^^
388+
|
389+
note: slice indexed here
390+
--> tests/ui/missing_asserts_for_indexing.rs:178:17
391+
|
392+
LL | let _ = v[0] + v[1] + v[2];
393+
| ^^^^
394+
note: slice indexed here
395+
--> tests/ui/missing_asserts_for_indexing.rs:178:24
396+
|
397+
LL | let _ = v[0] + v[1] + v[2];
398+
| ^^^^
399+
note: slice indexed here
400+
--> tests/ui/missing_asserts_for_indexing.rs:178:31
401+
|
402+
LL | let _ = v[0] + v[1] + v[2];
403+
| ^^^^
404+
= note: asserting the length before indexing will elide bounds checks
405+
406+
error: aborting due to 15 previous errors
357407

0 commit comments

Comments
 (0)