Skip to content

Add new lint might_panic #11889

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5279,6 +5279,7 @@ Released 2018-09-13
[`mem_replace_option_with_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_replace_option_with_none
[`mem_replace_with_default`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_replace_with_default
[`mem_replace_with_uninit`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_replace_with_uninit
[`might_panic`]: https://rust-lang.github.io/rust-clippy/master/index.html#might_panic
[`min_ident_chars`]: https://rust-lang.github.io/rust-clippy/master/index.html#min_ident_chars
[`min_max`]: https://rust-lang.github.io/rust-clippy/master/index.html#min_max
[`misaligned_transmute`]: https://rust-lang.github.io/rust-clippy/master/index.html#misaligned_transmute
Expand Down
1 change: 1 addition & 0 deletions clippy_lints/src/declared_lints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
crate::methods::WAKER_CLONE_WAKE_INFO,
crate::methods::WRONG_SELF_CONVENTION_INFO,
crate::methods::ZST_OFFSET_INFO,
crate::might_panic::MIGHT_PANIC_INFO,
crate::min_ident_chars::MIN_IDENT_CHARS_INFO,
crate::minmax::MIN_MAX_INFO,
crate::misc::SHORT_CIRCUIT_STATEMENT_INFO,
Expand Down
2 changes: 2 additions & 0 deletions clippy_lints/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@ mod match_result_ok;
mod matches;
mod mem_replace;
mod methods;
mod might_panic;
mod min_ident_chars;
mod minmax;
mod misc;
Expand Down Expand Up @@ -1070,6 +1071,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
store.register_late_pass(|_| Box::new(iter_without_into_iter::IterWithoutIntoIter));
store.register_late_pass(|_| Box::new(iter_over_hash_type::IterOverHashType));
store.register_late_pass(|_| Box::new(impl_hash_with_borrow_str_and_bytes::ImplHashWithBorrowStrBytes));
store.register_late_pass(|_| Box::new(might_panic::MightPanic));
store.register_late_pass(|_| Box::new(repeat_vec_with_capacity::RepeatVecWithCapacity));
// add lints here, do not remove this comment, it's used in `new_lint`
}
Expand Down
89 changes: 89 additions & 0 deletions clippy_lints/src/might_panic.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::source::snippet_opt;
use rustc_ast::ast::LitKind;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::declare_lint_pass;

declare_clippy_lint! {
/// ### What it does
/// replace accessing array with an `idx`` by a `get(idx)`.
///
/// ### Why is this bad?
/// it's easier to locate error where you access array when
/// out of boundary; and you can write your error handle to
/// solve this problem.
///
/// ### Example
/// ```no_run
/// let numbers = &[4, 7, 3];
/// let my_number = numbers[5];
/// ```
/// Use instead:
/// ```no_run
/// let numbers = &[4, 7, 3];
/// let Some(my_number) = numbers.get(5) else {
/// panic!();
/// };
/// ```
#[clippy::version = "1.76.0"]
pub MIGHT_PANIC,
style,
"use `get()` function if you're not sure whether index is legal"
}

declare_lint_pass!(MightPanic => [MIGHT_PANIC]);

impl LateLintPass<'_> for MightPanic {
fn check_stmt<'tcx>(&mut self, cx: &LateContext<'tcx>, stmt: &hir::Stmt<'tcx>) {
// pattern matching an `let` stmt satisfy form like `let x: ty = arr[idx];`
if let hir::StmtKind::Local(hir::Local {
pat,
ty,
init,
els: _,
hir_id: _,
span,
source: _,
}) = &stmt.kind
&& let hir::PatKind::Binding(_, _, ident, _) = pat.kind
&& let Some(expr) = init
&& let hir::ExprKind::Index(arr, idx, _) = &expr.kind
&& let hir::ExprKind::Path(_) = arr.kind
&& let hir::ExprKind::Lit(spanned) = idx.kind
&& let LitKind::Int(v, _) = spanned.node
{
// get type info string by stmt.local.ty.span
// may not have an explict type, it doesn't matter
let mut ty_str = String::new();
if let Some(hir::Ty {
hir_id: _,
kind: _,
span: ty_span,
}) = ty
&& let Some(snip) = snippet_opt(cx, *ty_span)
{
ty_str = snip;
}
let span = *span;
span_lint_and_then(
cx,
MIGHT_PANIC,
span,
"use `get()` function if you're not sure whether index is legal",
|diag| {
if let Some(snip) = snippet_opt(cx, arr.span) {
// format sugg string
let sugg = if ty_str.is_empty() {
format!("let Some({ident}) = {snip}.get({v}) else {{ panic!() }};")
} else {
format!("let Some({ident}): Option<&{ty_str}> = {snip}.get({v}) else {{ panic!() }};")
};
diag.span_suggestion(span, "Try", sugg, Applicability::MachineApplicable);
}
},
);
}
}
}
18 changes: 18 additions & 0 deletions tests/ui/might_panic.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#![allow(clippy::might_panic)]

fn main() {
// declare 2 array to access
let arr1 = &[1, 2, 3];
let arr2 = &[[1], [2], [3]];

// trigger `might-panic` lint
// with and without explicit type declaration
let _num1 = arr1[1]; // warning
let _num2: i32 = arr1[5]; // warning

let _num3 = arr2[1]; // warning
let _num4: [i32; 1] = arr2[5]; // warning

// not trigger `might-panic` lint
let _num5 = arr2[0][0]; // no warning
}
1 change: 1 addition & 0 deletions tests/ui/missing_asserts_for_indexing_unfixable.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#![allow(unused)]
#![warn(clippy::missing_asserts_for_indexing)]
#![allow(clippy::might_panic)]

fn sum(v: &[u8]) -> u8 {
v[0] + v[1] + v[2] + v[3] + v[4]
Expand Down
56 changes: 28 additions & 28 deletions tests/ui/missing_asserts_for_indexing_unfixable.stderr
Original file line number Diff line number Diff line change
@@ -1,32 +1,32 @@
error: indexing into a slice multiple times without an `assert`
--> $DIR/missing_asserts_for_indexing_unfixable.rs:5:5
--> $DIR/missing_asserts_for_indexing_unfixable.rs:6:5
|
LL | v[0] + v[1] + v[2] + v[3] + v[4]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: consider asserting the length before indexing: `assert!(v.len() > 4);`
note: slice indexed here
--> $DIR/missing_asserts_for_indexing_unfixable.rs:5:5
--> $DIR/missing_asserts_for_indexing_unfixable.rs:6:5
|
LL | v[0] + v[1] + v[2] + v[3] + v[4]
| ^^^^
note: slice indexed here
--> $DIR/missing_asserts_for_indexing_unfixable.rs:5:12
--> $DIR/missing_asserts_for_indexing_unfixable.rs:6:12
|
LL | v[0] + v[1] + v[2] + v[3] + v[4]
| ^^^^
note: slice indexed here
--> $DIR/missing_asserts_for_indexing_unfixable.rs:5:19
--> $DIR/missing_asserts_for_indexing_unfixable.rs:6:19
|
LL | v[0] + v[1] + v[2] + v[3] + v[4]
| ^^^^
note: slice indexed here
--> $DIR/missing_asserts_for_indexing_unfixable.rs:5:26
--> $DIR/missing_asserts_for_indexing_unfixable.rs:6:26
|
LL | v[0] + v[1] + v[2] + v[3] + v[4]
| ^^^^
note: slice indexed here
--> $DIR/missing_asserts_for_indexing_unfixable.rs:5:33
--> $DIR/missing_asserts_for_indexing_unfixable.rs:6:33
|
LL | v[0] + v[1] + v[2] + v[3] + v[4]
| ^^^^
Expand All @@ -35,7 +35,7 @@ LL | v[0] + v[1] + v[2] + v[3] + v[4]
= help: to override `-D warnings` add `#[allow(clippy::missing_asserts_for_indexing)]`

error: indexing into a slice multiple times without an `assert`
--> $DIR/missing_asserts_for_indexing_unfixable.rs:10:13
--> $DIR/missing_asserts_for_indexing_unfixable.rs:11:13
|
LL | let _ = v[0];
| _____________^
Expand All @@ -45,19 +45,19 @@ LL | | let _ = v[1..4];
|
= help: consider asserting the length before indexing: `assert!(v.len() > 3);`
note: slice indexed here
--> $DIR/missing_asserts_for_indexing_unfixable.rs:10:13
--> $DIR/missing_asserts_for_indexing_unfixable.rs:11:13
|
LL | let _ = v[0];
| ^^^^
note: slice indexed here
--> $DIR/missing_asserts_for_indexing_unfixable.rs:12:13
--> $DIR/missing_asserts_for_indexing_unfixable.rs:13:13
|
LL | let _ = v[1..4];
| ^^^^^^^
= note: asserting the length before indexing will elide bounds checks

error: indexing into a slice multiple times without an `assert`
--> $DIR/missing_asserts_for_indexing_unfixable.rs:16:13
--> $DIR/missing_asserts_for_indexing_unfixable.rs:17:13
|
LL | let a = v[0];
| _____________^
Expand All @@ -68,112 +68,112 @@ LL | | let c = v[2];
|
= help: consider asserting the length before indexing: `assert!(v.len() > 2);`
note: slice indexed here
--> $DIR/missing_asserts_for_indexing_unfixable.rs:16:13
--> $DIR/missing_asserts_for_indexing_unfixable.rs:17:13
|
LL | let a = v[0];
| ^^^^
note: slice indexed here
--> $DIR/missing_asserts_for_indexing_unfixable.rs:18:13
--> $DIR/missing_asserts_for_indexing_unfixable.rs:19:13
|
LL | let b = v[1];
| ^^^^
note: slice indexed here
--> $DIR/missing_asserts_for_indexing_unfixable.rs:19:13
--> $DIR/missing_asserts_for_indexing_unfixable.rs:20:13
|
LL | let c = v[2];
| ^^^^
= note: asserting the length before indexing will elide bounds checks

error: indexing into a slice multiple times without an `assert`
--> $DIR/missing_asserts_for_indexing_unfixable.rs:24:13
--> $DIR/missing_asserts_for_indexing_unfixable.rs:25:13
|
LL | let _ = v1[0] + v1[12];
| ^^^^^^^^^^^^^^
|
= help: consider asserting the length before indexing: `assert!(v1.len() > 12);`
note: slice indexed here
--> $DIR/missing_asserts_for_indexing_unfixable.rs:24:13
--> $DIR/missing_asserts_for_indexing_unfixable.rs:25:13
|
LL | let _ = v1[0] + v1[12];
| ^^^^^
note: slice indexed here
--> $DIR/missing_asserts_for_indexing_unfixable.rs:24:21
--> $DIR/missing_asserts_for_indexing_unfixable.rs:25:21
|
LL | let _ = v1[0] + v1[12];
| ^^^^^^
= note: asserting the length before indexing will elide bounds checks

error: indexing into a slice multiple times without an `assert`
--> $DIR/missing_asserts_for_indexing_unfixable.rs:25:13
--> $DIR/missing_asserts_for_indexing_unfixable.rs:26:13
|
LL | let _ = v2[5] + v2[15];
| ^^^^^^^^^^^^^^
|
= help: consider asserting the length before indexing: `assert!(v2.len() > 15);`
note: slice indexed here
--> $DIR/missing_asserts_for_indexing_unfixable.rs:25:13
--> $DIR/missing_asserts_for_indexing_unfixable.rs:26:13
|
LL | let _ = v2[5] + v2[15];
| ^^^^^
note: slice indexed here
--> $DIR/missing_asserts_for_indexing_unfixable.rs:25:21
--> $DIR/missing_asserts_for_indexing_unfixable.rs:26:21
|
LL | let _ = v2[5] + v2[15];
| ^^^^^^
= note: asserting the length before indexing will elide bounds checks

error: indexing into a slice multiple times without an `assert`
--> $DIR/missing_asserts_for_indexing_unfixable.rs:31:13
--> $DIR/missing_asserts_for_indexing_unfixable.rs:32:13
|
LL | let _ = v2[5] + v2[15];
| ^^^^^^^^^^^^^^
|
= help: consider asserting the length before indexing: `assert!(v2.len() > 15);`
note: slice indexed here
--> $DIR/missing_asserts_for_indexing_unfixable.rs:31:13
--> $DIR/missing_asserts_for_indexing_unfixable.rs:32:13
|
LL | let _ = v2[5] + v2[15];
| ^^^^^
note: slice indexed here
--> $DIR/missing_asserts_for_indexing_unfixable.rs:31:21
--> $DIR/missing_asserts_for_indexing_unfixable.rs:32:21
|
LL | let _ = v2[5] + v2[15];
| ^^^^^^
= note: asserting the length before indexing will elide bounds checks

error: indexing into a slice multiple times without an `assert`
--> $DIR/missing_asserts_for_indexing_unfixable.rs:40:13
--> $DIR/missing_asserts_for_indexing_unfixable.rs:41:13
|
LL | let _ = f.v[0] + f.v[1];
| ^^^^^^^^^^^^^^^
|
= help: consider asserting the length before indexing: `assert!(f.v.len() > 1);`
note: slice indexed here
--> $DIR/missing_asserts_for_indexing_unfixable.rs:40:13
--> $DIR/missing_asserts_for_indexing_unfixable.rs:41:13
|
LL | let _ = f.v[0] + f.v[1];
| ^^^^^^
note: slice indexed here
--> $DIR/missing_asserts_for_indexing_unfixable.rs:40:22
--> $DIR/missing_asserts_for_indexing_unfixable.rs:41:22
|
LL | let _ = f.v[0] + f.v[1];
| ^^^^^^
= note: asserting the length before indexing will elide bounds checks

error: indexing into a slice multiple times without an `assert`
--> $DIR/missing_asserts_for_indexing_unfixable.rs:54:13
--> $DIR/missing_asserts_for_indexing_unfixable.rs:55:13
|
LL | let _ = x[0] + x[1];
| ^^^^^^^^^^^
|
= help: consider asserting the length before indexing: `assert!(x.len() > 1);`
note: slice indexed here
--> $DIR/missing_asserts_for_indexing_unfixable.rs:54:13
--> $DIR/missing_asserts_for_indexing_unfixable.rs:55:13
|
LL | let _ = x[0] + x[1];
| ^^^^
note: slice indexed here
--> $DIR/missing_asserts_for_indexing_unfixable.rs:54:20
--> $DIR/missing_asserts_for_indexing_unfixable.rs:55:20
|
LL | let _ = x[0] + x[1];
| ^^^^
Expand Down
3 changes: 2 additions & 1 deletion tests/ui/shadow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
clippy::let_unit_value,
clippy::needless_if,
clippy::redundant_guards,
clippy::redundant_locals
clippy::redundant_locals,
clippy::might_panic
)]

extern crate proc_macro_derive;
Expand Down
Loading