mirror of
https://github.com/rust-lang/rust-clippy
synced 2024-11-23 13:13:34 +00:00
Added lint match_vec_item
This commit is contained in:
parent
1d4dd3d428
commit
96e2bc80f5
6 changed files with 260 additions and 0 deletions
|
@ -1352,6 +1352,7 @@ Released 2018-09-13
|
|||
[`match_ref_pats`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_ref_pats
|
||||
[`match_same_arms`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_same_arms
|
||||
[`match_single_binding`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_single_binding
|
||||
[`match_vec_item`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_vec_item
|
||||
[`match_wild_err_arm`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_wild_err_arm
|
||||
[`maybe_infinite_iter`]: https://rust-lang.github.io/rust-clippy/master/index.html#maybe_infinite_iter
|
||||
[`mem_discriminant_non_enum`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_discriminant_non_enum
|
||||
|
|
|
@ -249,6 +249,7 @@ mod macro_use;
|
|||
mod main_recursion;
|
||||
mod map_clone;
|
||||
mod map_unit_fn;
|
||||
mod match_vec_item;
|
||||
mod matches;
|
||||
mod mem_discriminant;
|
||||
mod mem_forget;
|
||||
|
@ -629,6 +630,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||
&map_clone::MAP_CLONE,
|
||||
&map_unit_fn::OPTION_MAP_UNIT_FN,
|
||||
&map_unit_fn::RESULT_MAP_UNIT_FN,
|
||||
&match_vec_item::MATCH_VEC_ITEM,
|
||||
&matches::INFALLIBLE_DESTRUCTURING_MATCH,
|
||||
&matches::MATCH_AS_REF,
|
||||
&matches::MATCH_BOOL,
|
||||
|
@ -1060,6 +1062,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||
store.register_late_pass(|| box future_not_send::FutureNotSend);
|
||||
store.register_late_pass(|| box utils::internal_lints::CollapsibleCalls);
|
||||
store.register_late_pass(|| box if_let_mutex::IfLetMutex);
|
||||
store.register_late_pass(|| box match_vec_item::MatchVecItem);
|
||||
|
||||
store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![
|
||||
LintId::of(&arithmetic::FLOAT_ARITHMETIC),
|
||||
|
@ -1277,6 +1280,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||
LintId::of(&map_clone::MAP_CLONE),
|
||||
LintId::of(&map_unit_fn::OPTION_MAP_UNIT_FN),
|
||||
LintId::of(&map_unit_fn::RESULT_MAP_UNIT_FN),
|
||||
LintId::of(&match_vec_item::MATCH_VEC_ITEM),
|
||||
LintId::of(&matches::INFALLIBLE_DESTRUCTURING_MATCH),
|
||||
LintId::of(&matches::MATCH_AS_REF),
|
||||
LintId::of(&matches::MATCH_BOOL),
|
||||
|
@ -1469,6 +1473,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||
LintId::of(&loops::WHILE_LET_ON_ITERATOR),
|
||||
LintId::of(&main_recursion::MAIN_RECURSION),
|
||||
LintId::of(&map_clone::MAP_CLONE),
|
||||
LintId::of(&match_vec_item::MATCH_VEC_ITEM),
|
||||
LintId::of(&matches::INFALLIBLE_DESTRUCTURING_MATCH),
|
||||
LintId::of(&matches::MATCH_BOOL),
|
||||
LintId::of(&matches::MATCH_OVERLAPPING_ARM),
|
||||
|
|
111
clippy_lints/src/match_vec_item.rs
Normal file
111
clippy_lints/src/match_vec_item.rs
Normal file
|
@ -0,0 +1,111 @@
|
|||
use crate::utils::{is_wild, span_lint_and_help};
|
||||
use if_chain::if_chain;
|
||||
use rustc_hir::{Arm, Expr, ExprKind, MatchSource};
|
||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
use rustc_middle::ty::{self, AdtDef};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// **What it does:** Checks for `match vec[idx]` or `match vec[n..m]`.
|
||||
///
|
||||
/// **Why is this bad?** This can panic at runtime.
|
||||
///
|
||||
/// **Known problems:** None.
|
||||
///
|
||||
/// **Example:**
|
||||
/// ```rust, no_run
|
||||
/// let arr = vec![0, 1, 2, 3];
|
||||
/// let idx = 1;
|
||||
///
|
||||
/// // Bad
|
||||
/// match arr[idx] {
|
||||
/// 0 => println!("{}", 0),
|
||||
/// 1 => println!("{}", 3),
|
||||
/// _ => {},
|
||||
/// }
|
||||
/// ```
|
||||
/// Use instead:
|
||||
/// ```rust, no_run
|
||||
/// let arr = vec![0, 1, 2, 3];
|
||||
/// let idx = 1;
|
||||
///
|
||||
/// // Good
|
||||
/// match arr.get(idx) {
|
||||
/// Some(0) => println!("{}", 0),
|
||||
/// Some(1) => println!("{}", 3),
|
||||
/// _ => {},
|
||||
/// }
|
||||
/// ```
|
||||
pub MATCH_VEC_ITEM,
|
||||
style,
|
||||
"match vector by indexing can panic"
|
||||
}
|
||||
|
||||
declare_lint_pass!(MatchVecItem => [MATCH_VEC_ITEM]);
|
||||
|
||||
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MatchVecItem {
|
||||
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'tcx>) {
|
||||
if_chain! {
|
||||
if !in_external_macro(cx.sess(), expr.span);
|
||||
if let ExprKind::Match(ref ex, ref arms, MatchSource::Normal) = expr.kind;
|
||||
if contains_wild_arm(arms);
|
||||
if is_vec_indexing(cx, ex);
|
||||
|
||||
then {
|
||||
span_lint_and_help(
|
||||
cx,
|
||||
MATCH_VEC_ITEM,
|
||||
expr.span,
|
||||
"indexing vector may panic",
|
||||
None,
|
||||
"consider using `get(..)` instead.",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn contains_wild_arm(arms: &[Arm<'_>]) -> bool {
|
||||
arms.iter().any(|arm| is_wild(&arm.pat) && is_unit_expr(arm.body))
|
||||
}
|
||||
|
||||
fn is_vec_indexing<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
|
||||
if_chain! {
|
||||
if let ExprKind::Index(ref array, _) = expr.kind;
|
||||
let ty = cx.tables.expr_ty(array);
|
||||
if let ty::Adt(def, _) = ty.kind;
|
||||
if is_vec(cx, def);
|
||||
|
||||
then {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
fn is_vec<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, def: &'a AdtDef) -> bool {
|
||||
if_chain! {
|
||||
let def_path = cx.tcx.def_path(def.did);
|
||||
if def_path.data.len() == 2;
|
||||
if let Some(module) = def_path.data.get(0);
|
||||
if module.data.as_symbol() == sym!(vec);
|
||||
if let Some(name) = def_path.data.get(1);
|
||||
if name.data.as_symbol() == sym!(Vec);
|
||||
|
||||
then {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
fn is_unit_expr(expr: &Expr<'_>) -> bool {
|
||||
match expr.kind {
|
||||
ExprKind::Tup(ref v) if v.is_empty() => true,
|
||||
ExprKind::Block(ref b, _) if b.stmts.is_empty() && b.expr.is_none() => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
|
@ -1172,6 +1172,13 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![
|
|||
deprecation: None,
|
||||
module: "matches",
|
||||
},
|
||||
Lint {
|
||||
name: "match_vec_item",
|
||||
group: "style",
|
||||
desc: "match vector by indexing can panic",
|
||||
deprecation: None,
|
||||
module: "match_vec_item",
|
||||
},
|
||||
Lint {
|
||||
name: "match_wild_err_arm",
|
||||
group: "style",
|
||||
|
|
109
tests/ui/match_vec_item.rs
Normal file
109
tests/ui/match_vec_item.rs
Normal file
|
@ -0,0 +1,109 @@
|
|||
#![warn(clippy::match_vec_item)]
|
||||
|
||||
fn main() {
|
||||
match_with_wildcard();
|
||||
match_without_wildcard();
|
||||
match_wildcard_and_action();
|
||||
match_with_get();
|
||||
match_with_array();
|
||||
}
|
||||
|
||||
fn match_with_wildcard() {
|
||||
let arr = vec![0, 1, 2, 3];
|
||||
let range = 1..3;
|
||||
let idx = 1;
|
||||
|
||||
// Lint, may panic
|
||||
match arr[idx] {
|
||||
0 => println!("0"),
|
||||
1 => println!("1"),
|
||||
_ => {},
|
||||
}
|
||||
|
||||
// Lint, may panic
|
||||
match arr[range] {
|
||||
[0, 1] => println!("0 1"),
|
||||
[1, 2] => println!("1 2"),
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
|
||||
fn match_without_wildcard() {
|
||||
let arr = vec![0, 1, 2, 3];
|
||||
let range = 1..3;
|
||||
let idx = 2;
|
||||
|
||||
// Ok
|
||||
match arr[idx] {
|
||||
0 => println!("0"),
|
||||
1 => println!("1"),
|
||||
num => {},
|
||||
}
|
||||
|
||||
// Ok
|
||||
match arr[range] {
|
||||
[0, 1] => println!("0 1"),
|
||||
[1, 2] => println!("1 2"),
|
||||
[ref sub @ ..] => {},
|
||||
}
|
||||
}
|
||||
|
||||
fn match_wildcard_and_action() {
|
||||
let arr = vec![0, 1, 2, 3];
|
||||
let range = 1..3;
|
||||
let idx = 3;
|
||||
|
||||
// Ok
|
||||
match arr[idx] {
|
||||
0 => println!("0"),
|
||||
1 => println!("1"),
|
||||
_ => println!("Hello, World!"),
|
||||
}
|
||||
|
||||
// Ok
|
||||
match arr[range] {
|
||||
[0, 1] => println!("0 1"),
|
||||
[1, 2] => println!("1 2"),
|
||||
_ => println!("Hello, World!"),
|
||||
}
|
||||
}
|
||||
|
||||
fn match_with_get() {
|
||||
let arr = vec![0, 1, 2, 3];
|
||||
let range = 1..3;
|
||||
let idx = 3;
|
||||
|
||||
// Ok
|
||||
match arr.get(idx) {
|
||||
Some(0) => println!("0"),
|
||||
Some(1) => println!("1"),
|
||||
_ => {},
|
||||
}
|
||||
|
||||
// Ok
|
||||
match arr.get(range) {
|
||||
Some(&[0, 1]) => println!("0 1"),
|
||||
Some(&[1, 2]) => println!("1 2"),
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
|
||||
fn match_with_array() {
|
||||
let arr = [0, 1, 2, 3];
|
||||
let range = 1..3;
|
||||
let idx = 3;
|
||||
|
||||
// Ok
|
||||
match arr[idx] {
|
||||
0 => println!("0"),
|
||||
1 => println!("1"),
|
||||
_ => {},
|
||||
}
|
||||
|
||||
// Ok
|
||||
match arr[range] {
|
||||
[0, 1] => println!("0 1"),
|
||||
[1, 2] => println!("1 2"),
|
||||
_ => {},
|
||||
}
|
||||
}
|
27
tests/ui/match_vec_item.stderr
Normal file
27
tests/ui/match_vec_item.stderr
Normal file
|
@ -0,0 +1,27 @@
|
|||
error: indexing vector may panic
|
||||
--> $DIR/match_vec_item.rs:17:5
|
||||
|
|
||||
LL | / match arr[idx] {
|
||||
LL | | 0 => println!("0"),
|
||||
LL | | 1 => println!("1"),
|
||||
LL | | _ => {},
|
||||
LL | | }
|
||||
| |_____^
|
||||
|
|
||||
= note: `-D clippy::match-vec-item` implied by `-D warnings`
|
||||
= help: consider using `get(..)` instead.
|
||||
|
||||
error: indexing vector may panic
|
||||
--> $DIR/match_vec_item.rs:24:5
|
||||
|
|
||||
LL | / match arr[range] {
|
||||
LL | | [0, 1] => println!("0 1"),
|
||||
LL | | [1, 2] => println!("1 2"),
|
||||
LL | | _ => {},
|
||||
LL | | }
|
||||
| |_____^
|
||||
|
|
||||
= help: consider using `get(..)` instead.
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
Loading…
Reference in a new issue