Skip to content

False positives and false negatives for clippy::missing_asserts_for_indexing. #14079

Closed
@sendittothenewts

Description

@sendittothenewts

Summary

The code let _square = slice[0] * slice[0]; falsely fires the clippy::missing_asserts_for_indexing lint. Following the suggestion to add assert!(slice.len() > 0); fires the clippy::len_zero lint instead (as does assert!(slice.len() >= 1);). Following clippy::len_zero's suggestion to change it to assert!(!slice.is_empty()); causes clippy::missing_asserts_for_indexing to reappear. Adding assert_ne!(slice.len(), 0); has no effect (arguably a false negative for clippy::len_zero), and assert!(slice.len() != 0); just gets both lints firing.

The false positive for clippy::missing_asserts_for_indexing occurs for multiple accesses to any index, but the unfortunate interaction with clippy::len_zero is specific to the case where that index is 0.

On a somewhat related note, clippy::missing_asserts_for_indexing also seems to ignore the ordering of things. While it correctly fires for let _product = slice[0] * slice[1];, it produces a false positive for let _product = slice[1] * slice[0]; and a false negative for let _product = slice[0] * slice[1]; assert!(slice.len() > 1);.

Possible fixes:

  1. Ignore any assert! that does not come before the first indexing operation.
  2. In the absence of such an assert!, treat the first indexing operation as equivalent to an assert!
  3. If the preceding fixes turn out to be tricky, ignoring multiple accesses to the same index would provide a partial fix
  4. Teaching clippy::missing_asserts_for_indexing about .is_empty() is possible, but this would not be needed if either of the previous two points were implemented.

Lint Name

clippy::missing_asserts_for_indexing

Reproducer

I tried this code:

#![warn(clippy::missing_asserts_for_indexing)]
pub fn foo(slice: &[i32]) -> i32 {
	assert!(!slice.is_empty());
	slice[0] * slice[0]
}
pub fn bar(slice: &[i32]) -> i32{
	slice[1] * slice[0]
}
pub fn baz(slice: &[i32]) -> i32 {
	let product = slice[0] * slice[1]; assert!(slice.len() > 1);
	product
}

I expected to see this happen:

A warning for baz, but nothing for foo and bar.

Instead, this happened:

warning: indexing into a slice multiple times without an `assert`
 --> src/bin/slice.rs:4:2
  |
4 |     slice[0] * slice[0]
  |     ^^^^^^^^^^^^^^^^^^^
  |
  = help: consider asserting the length before indexing: `assert!(slice.len() > 0);`
note: slice indexed here
 --> src/bin/slice.rs:4:2
  |
4 |     slice[0] * slice[0]
  |     ^^^^^^^^
note: slice indexed here
 --> src/bin/slice.rs:4:13
  |
4 |     slice[0] * slice[0]
  |                ^^^^^^^^
  = note: asserting the length before indexing will elide bounds checks
  = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#missing_asserts_for_indexing
note: the lint level is defined here
 --> src/bin/slice.rs:1:9
  |
1 | #![warn(clippy::missing_asserts_for_indexing)]
  |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

warning: indexing into a slice multiple times without an `assert`
 --> src/bin/slice.rs:7:2
  |
7 |     slice[1] * slice[0]
  |     ^^^^^^^^^^^^^^^^^^^
  |
  = help: consider asserting the length before indexing: `assert!(slice.len() > 1);`
note: slice indexed here
 --> src/bin/slice.rs:7:2
  |
7 |     slice[1] * slice[0]
  |     ^^^^^^^^
note: slice indexed here
 --> src/bin/slice.rs:7:13
  |
7 |     slice[1] * slice[0]
  |                ^^^^^^^^
  = note: asserting the length before indexing will elide bounds checks
  = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#missing_asserts_for_indexing

warning: `foo` (bin "slice") generated 2 warnings

Version

rustc 1.86.0-nightly (f7cc13af8 2025-01-25)
binary: rustc
commit-hash: f7cc13af822fe68c64fec0b05aa9dd1412451f7c
commit-date: 2025-01-25
host: x86_64-unknown-linux-gnu
release: 1.86.0-nightly
LLVM version: 19.1.7

and also on

rustc 1.84.0 (9fc6b4312 2025-01-07)
binary: rustc
commit-hash: 9fc6b43126469e3858e2fe86cafb4f0fd5068869
commit-date: 2025-01-07
host: x86_64-unknown-linux-gnu
release: 1.84.0
LLVM version: 19.1.5

and probably on every version since Rust 1.74.0.

Metadata

Metadata

Labels

C-bugCategory: Clippy is not doing the correct thingI-false-negativeIssue: The lint should have been triggered on code, but wasn't

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions