Skip to content

Commit 3d8d734

Browse files
committed
Move MatchOnVecItems into Matches lint pass
1 parent b337f9e commit 3d8d734

File tree

6 files changed

+103
-108
lines changed

6 files changed

+103
-108
lines changed

clippy_lints/src/lib.register_lints.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,6 @@ store.register_lints(&[
258258
map_err_ignore::MAP_ERR_IGNORE,
259259
map_unit_fn::OPTION_MAP_UNIT_FN,
260260
map_unit_fn::RESULT_MAP_UNIT_FN,
261-
match_on_vec_items::MATCH_ON_VEC_ITEMS,
262261
match_result_ok::MATCH_RESULT_OK,
263262
match_str_case_mismatch::MATCH_STR_CASE_MISMATCH,
264263
matches::COLLAPSIBLE_MATCH,
@@ -267,6 +266,7 @@ store.register_lints(&[
267266
matches::MATCH_AS_REF,
268267
matches::MATCH_BOOL,
269268
matches::MATCH_LIKE_MATCHES_MACRO,
269+
matches::MATCH_ON_VEC_ITEMS,
270270
matches::MATCH_OVERLAPPING_ARM,
271271
matches::MATCH_REF_PATS,
272272
matches::MATCH_SAME_ARMS,

clippy_lints/src/lib.register_pedantic.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,8 @@ store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![
5151
LintId::of(macro_use::MACRO_USE_IMPORTS),
5252
LintId::of(manual_assert::MANUAL_ASSERT),
5353
LintId::of(manual_ok_or::MANUAL_OK_OR),
54-
LintId::of(match_on_vec_items::MATCH_ON_VEC_ITEMS),
5554
LintId::of(matches::MATCH_BOOL),
55+
LintId::of(matches::MATCH_ON_VEC_ITEMS),
5656
LintId::of(matches::MATCH_SAME_ARMS),
5757
LintId::of(matches::MATCH_WILDCARD_FOR_SINGLE_VARIANTS),
5858
LintId::of(matches::MATCH_WILD_ERR_ARM),

clippy_lints/src/lib.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,6 @@ mod manual_strip;
286286
mod map_clone;
287287
mod map_err_ignore;
288288
mod map_unit_fn;
289-
mod match_on_vec_items;
290289
mod match_result_ok;
291290
mod match_str_case_mismatch;
292291
mod matches;
@@ -815,7 +814,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
815814
store.register_late_pass(|| Box::new(if_not_else::IfNotElse));
816815
store.register_late_pass(|| Box::new(equatable_if_let::PatternEquality));
817816
store.register_late_pass(|| Box::new(mut_mutex_lock::MutMutexLock));
818-
store.register_late_pass(|| Box::new(match_on_vec_items::MatchOnVecItems));
819817
store.register_late_pass(|| Box::new(manual_async_fn::ManualAsyncFn));
820818
store.register_late_pass(|| Box::new(vec_resize_to_zero::VecResizeToZero));
821819
store.register_late_pass(|| Box::new(panic_in_result_fn::PanicInResultFn));

clippy_lints/src/match_on_vec_items.rs

Lines changed: 0 additions & 104 deletions
This file was deleted.
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
use clippy_utils::diagnostics::span_lint_and_sugg;
2+
use clippy_utils::source::snippet;
3+
use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item};
4+
use if_chain::if_chain;
5+
use rustc_errors::Applicability;
6+
use rustc_hir::{Expr, ExprKind, LangItem};
7+
use rustc_lint::LateContext;
8+
use rustc_span::sym;
9+
10+
use super::MATCH_ON_VEC_ITEMS;
11+
12+
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, scrutinee: &'tcx Expr<'_>) {
13+
if_chain! {
14+
if let Some(idx_expr) = is_vec_indexing(cx, scrutinee);
15+
if let ExprKind::Index(vec, idx) = idx_expr.kind;
16+
17+
then {
18+
// FIXME: could be improved to suggest surrounding every pattern with Some(_),
19+
// but only when `or_patterns` are stabilized.
20+
span_lint_and_sugg(
21+
cx,
22+
MATCH_ON_VEC_ITEMS,
23+
scrutinee.span,
24+
"indexing into a vector may panic",
25+
"try this",
26+
format!(
27+
"{}.get({})",
28+
snippet(cx, vec.span, ".."),
29+
snippet(cx, idx.span, "..")
30+
),
31+
Applicability::MaybeIncorrect
32+
);
33+
}
34+
}
35+
}
36+
37+
fn is_vec_indexing<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> {
38+
if_chain! {
39+
if let ExprKind::Index(array, index) = expr.kind;
40+
if is_vector(cx, array);
41+
if !is_full_range(cx, index);
42+
43+
then {
44+
return Some(expr);
45+
}
46+
}
47+
48+
None
49+
}
50+
51+
fn is_vector(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
52+
let ty = cx.typeck_results().expr_ty(expr);
53+
let ty = ty.peel_refs();
54+
is_type_diagnostic_item(cx, ty, sym::Vec)
55+
}
56+
57+
fn is_full_range(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
58+
let ty = cx.typeck_results().expr_ty(expr);
59+
let ty = ty.peel_refs();
60+
is_type_lang_item(cx, ty, LangItem::RangeFull)
61+
}

clippy_lints/src/matches/mod.rs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ mod manual_unwrap_or;
1414
mod match_as_ref;
1515
mod match_bool;
1616
mod match_like_matches;
17+
mod match_on_vec_items;
1718
mod match_ref_pats;
1819
mod match_same_arms;
1920
mod match_single_binding;
@@ -678,6 +679,43 @@ declare_clippy_lint! {
678679
"finds patterns that can be encoded more concisely with `Option::unwrap_or` or `Result::unwrap_or`"
679680
}
680681

682+
declare_clippy_lint! {
683+
/// ### What it does
684+
/// Checks for `match vec[idx]` or `match vec[n..m]`.
685+
///
686+
/// ### Why is this bad?
687+
/// This can panic at runtime.
688+
///
689+
/// ### Example
690+
/// ```rust, no_run
691+
/// let arr = vec![0, 1, 2, 3];
692+
/// let idx = 1;
693+
///
694+
/// // Bad
695+
/// match arr[idx] {
696+
/// 0 => println!("{}", 0),
697+
/// 1 => println!("{}", 3),
698+
/// _ => {},
699+
/// }
700+
/// ```
701+
/// Use instead:
702+
/// ```rust, no_run
703+
/// let arr = vec![0, 1, 2, 3];
704+
/// let idx = 1;
705+
///
706+
/// // Good
707+
/// match arr.get(idx) {
708+
/// Some(0) => println!("{}", 0),
709+
/// Some(1) => println!("{}", 3),
710+
/// _ => {},
711+
/// }
712+
/// ```
713+
#[clippy::version = "1.45.0"]
714+
pub MATCH_ON_VEC_ITEMS,
715+
pedantic,
716+
"matching on vector elements can panic"
717+
}
718+
681719
#[derive(Default)]
682720
pub struct Matches {
683721
msrv: Option<RustcVersion>,
@@ -714,6 +752,7 @@ impl_lint_pass!(Matches => [
714752
NEEDLESS_MATCH,
715753
COLLAPSIBLE_MATCH,
716754
MANUAL_UNWRAP_OR,
755+
MATCH_ON_VEC_ITEMS,
717756
]);
718757

719758
impl<'tcx> LateLintPass<'tcx> for Matches {
@@ -750,6 +789,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
750789
match_wild_enum::check(cx, ex, arms);
751790
match_as_ref::check(cx, ex, arms, expr);
752791
needless_match::check_match(cx, ex, arms, expr);
792+
match_on_vec_items::check(cx, ex);
753793

754794
if !in_constant(cx, expr.hir_id) {
755795
manual_unwrap_or::check(cx, expr, ex, arms);

0 commit comments

Comments
 (0)