Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 2a70439

Browse files
committed
Split out overlapping_arms
1 parent f3dd909 commit 2a70439

File tree

2 files changed

+186
-178
lines changed

2 files changed

+186
-178
lines changed

clippy_lints/src/matches/mod.rs

Lines changed: 5 additions & 178 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
use clippy_utils::consts::{constant, constant_full_int, miri_to_const, FullInt};
21
use clippy_utils::diagnostics::{
32
multispan_sugg, span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then,
43
};
@@ -19,18 +18,18 @@ use rustc_hir::def::{CtorKind, DefKind, Res};
1918
use rustc_hir::LangItem::{OptionNone, OptionSome};
2019
use rustc_hir::{
2120
self as hir, Arm, BindingAnnotation, BorrowKind, Expr, ExprKind, Local, MatchSource, Mutability, Node, Pat,
22-
PatKind, PathSegment, QPath, RangeEnd, TyKind,
21+
PatKind, PathSegment, QPath, TyKind,
2322
};
2423
use rustc_lint::{LateContext, LateLintPass};
25-
use rustc_middle::ty::{self, Ty, VariantDef};
24+
use rustc_middle::ty::{self, VariantDef};
2625
use rustc_semver::RustcVersion;
2726
use rustc_session::{declare_tool_lint, impl_lint_pass};
28-
use rustc_span::{sym, symbol::kw, Span};
29-
use std::cmp::Ordering;
27+
use rustc_span::{sym, symbol::kw};
3028

3129
mod match_bool;
3230
mod match_like_matches;
3331
mod match_same_arms;
32+
mod overlapping_arms;
3433
mod redundant_pattern_match;
3534
mod single_match;
3635

@@ -632,7 +631,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
632631
if let ExprKind::Match(ex, arms, MatchSource::Normal) = expr.kind {
633632
single_match::check(cx, ex, arms, expr);
634633
match_bool::check(cx, ex, arms, expr);
635-
check_overlapping_arms(cx, ex, arms);
634+
overlapping_arms::check(cx, ex, arms);
636635
check_wild_err_arm(cx, ex, arms);
637636
check_wild_enum_match(cx, ex, arms);
638637
check_match_as_ref(cx, ex, arms, expr);
@@ -710,24 +709,6 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
710709
extract_msrv_attr!(LateContext);
711710
}
712711

713-
fn check_overlapping_arms<'tcx>(cx: &LateContext<'tcx>, ex: &'tcx Expr<'_>, arms: &'tcx [Arm<'_>]) {
714-
if arms.len() >= 2 && cx.typeck_results().expr_ty(ex).is_integral() {
715-
let ranges = all_ranges(cx, arms, cx.typeck_results().expr_ty(ex));
716-
if !ranges.is_empty() {
717-
if let Some((start, end)) = overlapping(&ranges) {
718-
span_lint_and_note(
719-
cx,
720-
MATCH_OVERLAPPING_ARM,
721-
start.span,
722-
"some ranges overlap",
723-
Some(end.span),
724-
"overlaps with this",
725-
);
726-
}
727-
}
728-
}
729-
}
730-
731712
fn check_wild_err_arm<'tcx>(cx: &LateContext<'tcx>, ex: &Expr<'tcx>, arms: &[Arm<'tcx>]) {
732713
let ex_ty = cx.typeck_results().expr_ty(ex).peel_refs();
733714
if is_type_diagnostic_item(cx, ex_ty, sym::Result) {
@@ -1219,59 +1200,6 @@ fn opt_parent_let<'a>(cx: &LateContext<'a>, ex: &Expr<'a>) -> Option<&'a Local<'
12191200
None
12201201
}
12211202

1222-
/// Gets the ranges for each range pattern arm. Applies `ty` bounds for open ranges.
1223-
fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>) -> Vec<SpannedRange<FullInt>> {
1224-
arms.iter()
1225-
.filter_map(|arm| {
1226-
if let Arm { pat, guard: None, .. } = *arm {
1227-
if let PatKind::Range(ref lhs, ref rhs, range_end) = pat.kind {
1228-
let lhs_const = match lhs {
1229-
Some(lhs) => constant(cx, cx.typeck_results(), lhs)?.0,
1230-
None => miri_to_const(ty.numeric_min_val(cx.tcx)?)?,
1231-
};
1232-
let rhs_const = match rhs {
1233-
Some(rhs) => constant(cx, cx.typeck_results(), rhs)?.0,
1234-
None => miri_to_const(ty.numeric_max_val(cx.tcx)?)?,
1235-
};
1236-
1237-
let lhs_val = lhs_const.int_value(cx, ty)?;
1238-
let rhs_val = rhs_const.int_value(cx, ty)?;
1239-
1240-
let rhs_bound = match range_end {
1241-
RangeEnd::Included => EndBound::Included(rhs_val),
1242-
RangeEnd::Excluded => EndBound::Excluded(rhs_val),
1243-
};
1244-
return Some(SpannedRange {
1245-
span: pat.span,
1246-
node: (lhs_val, rhs_bound),
1247-
});
1248-
}
1249-
1250-
if let PatKind::Lit(value) = pat.kind {
1251-
let value = constant_full_int(cx, cx.typeck_results(), value)?;
1252-
return Some(SpannedRange {
1253-
span: pat.span,
1254-
node: (value, EndBound::Included(value)),
1255-
});
1256-
}
1257-
}
1258-
None
1259-
})
1260-
.collect()
1261-
}
1262-
1263-
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1264-
pub enum EndBound<T> {
1265-
Included(T),
1266-
Excluded(T),
1267-
}
1268-
1269-
#[derive(Debug, Eq, PartialEq)]
1270-
struct SpannedRange<T> {
1271-
pub span: Span,
1272-
pub node: (T, EndBound<T>),
1273-
}
1274-
12751203
// Checks if arm has the form `None => None`
12761204
fn is_none_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
12771205
matches!(arm.pat.kind, PatKind::Path(ref qpath) if is_lang_ctor(cx, qpath, OptionNone))
@@ -1317,104 +1245,3 @@ where
13171245
}
13181246
ref_count > 1
13191247
}
1320-
1321-
fn overlapping<T>(ranges: &[SpannedRange<T>]) -> Option<(&SpannedRange<T>, &SpannedRange<T>)>
1322-
where
1323-
T: Copy + Ord,
1324-
{
1325-
#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
1326-
enum BoundKind {
1327-
EndExcluded,
1328-
Start,
1329-
EndIncluded,
1330-
}
1331-
1332-
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
1333-
struct RangeBound<'a, T>(T, BoundKind, &'a SpannedRange<T>);
1334-
1335-
impl<'a, T: Copy + Ord> PartialOrd for RangeBound<'a, T> {
1336-
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
1337-
Some(self.cmp(other))
1338-
}
1339-
}
1340-
1341-
impl<'a, T: Copy + Ord> Ord for RangeBound<'a, T> {
1342-
fn cmp(&self, RangeBound(other_value, other_kind, _): &Self) -> Ordering {
1343-
let RangeBound(self_value, self_kind, _) = *self;
1344-
(self_value, self_kind).cmp(&(*other_value, *other_kind))
1345-
}
1346-
}
1347-
1348-
let mut values = Vec::with_capacity(2 * ranges.len());
1349-
1350-
for r @ SpannedRange { node: (start, end), .. } in ranges {
1351-
values.push(RangeBound(*start, BoundKind::Start, r));
1352-
values.push(match end {
1353-
EndBound::Excluded(val) => RangeBound(*val, BoundKind::EndExcluded, r),
1354-
EndBound::Included(val) => RangeBound(*val, BoundKind::EndIncluded, r),
1355-
});
1356-
}
1357-
1358-
values.sort();
1359-
1360-
let mut started = vec![];
1361-
1362-
for RangeBound(_, kind, range) in values {
1363-
match kind {
1364-
BoundKind::Start => started.push(range),
1365-
BoundKind::EndExcluded | BoundKind::EndIncluded => {
1366-
let mut overlap = None;
1367-
1368-
while let Some(last_started) = started.pop() {
1369-
if last_started == range {
1370-
break;
1371-
}
1372-
overlap = Some(last_started);
1373-
}
1374-
1375-
if let Some(first_overlapping) = overlap {
1376-
return Some((range, first_overlapping));
1377-
}
1378-
},
1379-
}
1380-
}
1381-
1382-
None
1383-
}
1384-
1385-
#[test]
1386-
fn test_overlapping() {
1387-
use rustc_span::source_map::DUMMY_SP;
1388-
1389-
let sp = |s, e| SpannedRange {
1390-
span: DUMMY_SP,
1391-
node: (s, e),
1392-
};
1393-
1394-
assert_eq!(None, overlapping::<u8>(&[]));
1395-
assert_eq!(None, overlapping(&[sp(1, EndBound::Included(4))]));
1396-
assert_eq!(
1397-
None,
1398-
overlapping(&[sp(1, EndBound::Included(4)), sp(5, EndBound::Included(6))])
1399-
);
1400-
assert_eq!(
1401-
None,
1402-
overlapping(&[
1403-
sp(1, EndBound::Included(4)),
1404-
sp(5, EndBound::Included(6)),
1405-
sp(10, EndBound::Included(11))
1406-
],)
1407-
);
1408-
assert_eq!(
1409-
Some((&sp(1, EndBound::Included(4)), &sp(3, EndBound::Included(6)))),
1410-
overlapping(&[sp(1, EndBound::Included(4)), sp(3, EndBound::Included(6))])
1411-
);
1412-
assert_eq!(
1413-
Some((&sp(5, EndBound::Included(6)), &sp(6, EndBound::Included(11)))),
1414-
overlapping(&[
1415-
sp(1, EndBound::Included(4)),
1416-
sp(5, EndBound::Included(6)),
1417-
sp(6, EndBound::Included(11))
1418-
],)
1419-
);
1420-
}

0 commit comments

Comments
 (0)