Skip to content

Commit 28d2363

Browse files
committed
Exhaustively handle expressions in patterns
1 parent 11f38ad commit 28d2363

19 files changed

+198
-85
lines changed

Diff for: clippy_lints/src/default_numeric_fallback.rs

+21-2
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,11 @@ use clippy_utils::numeric_literal;
33
use clippy_utils::source::snippet_opt;
44
use rustc_ast::ast::{LitFloatType, LitIntType, LitKind};
55
use rustc_errors::Applicability;
6-
use rustc_hir::intravisit::{Visitor, walk_expr, walk_stmt};
7-
use rustc_hir::{Block, Body, ConstContext, Expr, ExprKind, FnRetTy, HirId, Lit, Stmt, StmtKind, StructTailExpr};
6+
use rustc_hir::intravisit::{Visitor, walk_expr, walk_pat, walk_stmt};
7+
use rustc_hir::{
8+
Block, Body, ConstContext, Expr, ExprKind, FnRetTy, HirId, Lit, Pat, PatExpr, PatExprKind, PatKind, Stmt, StmtKind,
9+
StructTailExpr,
10+
};
811
use rustc_lint::{LateContext, LateLintPass, LintContext};
912
use rustc_middle::lint::in_external_macro;
1013
use rustc_middle::ty::{self, FloatTy, IntTy, PolyFnSig, Ty};
@@ -219,6 +222,22 @@ impl<'tcx> Visitor<'tcx> for NumericFallbackVisitor<'_, 'tcx> {
219222
walk_expr(self, expr);
220223
}
221224

225+
fn visit_pat(&mut self, pat: &'tcx Pat<'_>) {
226+
match pat.kind {
227+
PatKind::Lit(&PatExpr {
228+
hir_id,
229+
kind: PatExprKind::Lit { lit, .. },
230+
..
231+
}) => {
232+
let ty = self.cx.typeck_results().node_type(hir_id);
233+
self.check_lit(lit, ty, hir_id);
234+
return;
235+
},
236+
_ => {},
237+
}
238+
walk_pat(self, pat)
239+
}
240+
222241
fn visit_stmt(&mut self, stmt: &'tcx Stmt<'_>) {
223242
match stmt.kind {
224243
// we cannot check the exact type since it's a hir::Ty which does not implement `is_numeric`

Diff for: clippy_lints/src/len_zero.rs

+9-3
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ use rustc_hir::def::Res;
88
use rustc_hir::def_id::{DefId, DefIdSet};
99
use rustc_hir::{
1010
AssocItemKind, BinOpKind, Expr, ExprKind, FnRetTy, GenericArg, GenericBound, ImplItem, ImplItemKind,
11-
ImplicitSelfKind, Item, ItemKind, Mutability, Node, OpaqueTyOrigin, PatKind, PathSegment, PrimTy, QPath,
12-
TraitItemRef, TyKind,
11+
ImplicitSelfKind, Item, ItemKind, Mutability, Node, OpaqueTyOrigin, PatExprKind, PatKind, PathSegment, PrimTy,
12+
QPath, TraitItemRef, TyKind,
1313
};
1414
use rustc_lint::{LateContext, LateLintPass};
1515
use rustc_middle::ty::{self, AssocKind, FnSig, Ty};
@@ -163,7 +163,13 @@ impl<'tcx> LateLintPass<'tcx> for LenZero {
163163
if let ExprKind::Let(lt) = expr.kind
164164
&& match lt.pat.kind {
165165
PatKind::Slice([], None, []) => true,
166-
PatKind::Lit(lit) if is_empty_string(lit) => true,
166+
PatKind::Lit(lit) => match lit.kind {
167+
PatExprKind::Lit { lit, .. } => match lit.node {
168+
LitKind::Str(lit, _) => lit.as_str().is_empty(),
169+
_ => false,
170+
},
171+
_ => false,
172+
},
167173
_ => false,
168174
}
169175
&& !expr.span.from_expansion()

Diff for: clippy_lints/src/manual_is_ascii_check.rs

+26-11
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use clippy_utils::{higher, is_in_const_context, path_to_local, peel_ref_operator
77
use rustc_ast::LitKind::{Byte, Char};
88
use rustc_ast::ast::RangeLimits;
99
use rustc_errors::Applicability;
10-
use rustc_hir::{Expr, ExprKind, Node, Param, PatKind, RangeEnd};
10+
use rustc_hir::{Expr, ExprKind, Node, Param, PatKind, RangeEnd, PatExpr, PatExprKind, Lit};
1111
use rustc_lint::{LateContext, LateLintPass};
1212
use rustc_middle::ty;
1313
use rustc_session::impl_lint_pass;
@@ -115,7 +115,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualIsAsciiCheck {
115115
{
116116
let arg = peel_ref_operators(cx, arg);
117117
let ty_sugg = get_ty_sugg(cx, arg, start);
118-
let range = check_range(start, end);
118+
let range = check_expr_range(start, end);
119119
check_is_ascii(cx, expr.span, arg, &range, ty_sugg);
120120
}
121121
}
@@ -196,19 +196,34 @@ fn check_pat(pat_kind: &PatKind<'_>) -> CharRange {
196196
}
197197
}
198198

199-
fn check_range(start: &Expr<'_>, end: &Expr<'_>) -> CharRange {
199+
fn check_expr_range(start: &Expr<'_>, end: &Expr<'_>) -> CharRange {
200200
if let ExprKind::Lit(start_lit) = &start.kind
201201
&& let ExprKind::Lit(end_lit) = &end.kind
202202
{
203-
match (&start_lit.node, &end_lit.node) {
204-
(Char('a'), Char('z')) | (Byte(b'a'), Byte(b'z')) => CharRange::LowerChar,
205-
(Char('A'), Char('Z')) | (Byte(b'A'), Byte(b'Z')) => CharRange::UpperChar,
206-
(Char('a'), Char('f')) | (Byte(b'a'), Byte(b'f')) => CharRange::LowerHexLetter,
207-
(Char('A'), Char('F')) | (Byte(b'A'), Byte(b'F')) => CharRange::UpperHexLetter,
208-
(Char('0'), Char('9')) | (Byte(b'0'), Byte(b'9')) => CharRange::Digit,
209-
_ => CharRange::Otherwise,
210-
}
203+
check_lit_range(start_lit, end_lit)
204+
} else {
205+
CharRange::Otherwise
206+
}
207+
}
208+
209+
210+
fn check_range(start: &PatExpr<'_>, end: &PatExpr<'_>) -> CharRange {
211+
if let PatExprKind::Lit{ lit: start_lit, negated: false } = &start.kind
212+
&& let PatExprKind::Lit{ lit: end_lit, negated: false } = &end.kind
213+
{
214+
check_lit_range(start_lit, end_lit)
211215
} else {
212216
CharRange::Otherwise
213217
}
214218
}
219+
220+
fn check_lit_range(start_lit: &Lit, end_lit: &Lit) -> CharRange {
221+
match (&start_lit.node, &end_lit.node) {
222+
(Char('a'), Char('z')) | (Byte(b'a'), Byte(b'z')) => CharRange::LowerChar,
223+
(Char('A'), Char('Z')) | (Byte(b'A'), Byte(b'Z')) => CharRange::UpperChar,
224+
(Char('a'), Char('f')) | (Byte(b'a'), Byte(b'f')) => CharRange::LowerHexLetter,
225+
(Char('A'), Char('F')) | (Byte(b'A'), Byte(b'F')) => CharRange::UpperHexLetter,
226+
(Char('0'), Char('9')) | (Byte(b'0'), Byte(b'9')) => CharRange::Digit,
227+
_ => CharRange::Otherwise,
228+
}
229+
}

Diff for: clippy_lints/src/manual_range_patterns.rs

+6-7
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use clippy_utils::source::SpanRangeExt;
33
use rustc_ast::LitKind;
44
use rustc_data_structures::fx::FxHashSet;
55
use rustc_errors::Applicability;
6-
use rustc_hir::{Expr, ExprKind, PatKind, RangeEnd, UnOp};
6+
use rustc_hir::{PatExpr, PatExprKind, PatKind, RangeEnd};
77
use rustc_lint::{LateContext, LateLintPass, LintContext};
88
use rustc_middle::lint::in_external_macro;
99
use rustc_session::declare_lint_pass;
@@ -38,14 +38,13 @@ declare_clippy_lint! {
3838
}
3939
declare_lint_pass!(ManualRangePatterns => [MANUAL_RANGE_PATTERNS]);
4040

41-
fn expr_as_i128(expr: &Expr<'_>) -> Option<i128> {
42-
if let ExprKind::Unary(UnOp::Neg, expr) = expr.kind {
43-
expr_as_i128(expr).map(|num| -num)
44-
} else if let ExprKind::Lit(lit) = expr.kind
41+
fn expr_as_i128(expr: &PatExpr<'_>) -> Option<i128> {
42+
if let PatExprKind::Lit { lit, negated } = expr.kind
4543
&& let LitKind::Int(num, _) = lit.node
4644
{
4745
// Intentionally not handling numbers greater than i128::MAX (for u128 literals) for now.
48-
num.get().try_into().ok()
46+
let n = i128::try_from(num.get()).ok()?;
47+
Some(if negated { -n } else { n })
4948
} else {
5049
None
5150
}
@@ -58,7 +57,7 @@ struct Num {
5857
}
5958

6059
impl Num {
61-
fn new(expr: &Expr<'_>) -> Option<Self> {
60+
fn new(expr: &PatExpr<'_>) -> Option<Self> {
6261
Some(Self {
6362
val: expr_as_i128(expr)?,
6463
span: expr.span,

Diff for: clippy_lints/src/matches/match_bool.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use clippy_utils::source::{expr_block, snippet};
44
use clippy_utils::sugg::Sugg;
55
use rustc_ast::LitKind;
66
use rustc_errors::Applicability;
7-
use rustc_hir::{Arm, Expr, ExprKind, PatKind};
7+
use rustc_hir::{Arm, Expr, PatExprKind, PatKind};
88
use rustc_lint::LateContext;
99
use rustc_middle::ty;
1010

@@ -22,7 +22,7 @@ pub(crate) fn check(cx: &LateContext<'_>, scrutinee: &Expr<'_>, arms: &[Arm<'_>]
2222
if arms.len() == 2 {
2323
// no guards
2424
let exprs = if let PatKind::Lit(arm_bool) = arms[0].pat.kind {
25-
if let ExprKind::Lit(lit) = arm_bool.kind {
25+
if let PatExprKind::Lit { lit, .. } = arm_bool.kind {
2626
match lit.node {
2727
LitKind::Bool(true) => Some((arms[0].body, arms[1].body)),
2828
LitKind::Bool(false) => Some((arms[1].body, arms[0].body)),

Diff for: clippy_lints/src/matches/match_same_arms.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use rustc_arena::DroplessArena;
77
use rustc_ast::ast::LitKind;
88
use rustc_errors::Applicability;
99
use rustc_hir::def_id::DefId;
10-
use rustc_hir::{Arm, Expr, ExprKind, HirId, HirIdMap, HirIdMapEntry, HirIdSet, Pat, PatKind, RangeEnd};
10+
use rustc_hir::{Arm, Expr, PatExprKind, HirId, HirIdMap, HirIdMapEntry, HirIdSet, Pat, PatKind, RangeEnd};
1111
use rustc_lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS;
1212
use rustc_lint::{LateContext, LintContext};
1313
use rustc_middle::ty;
@@ -313,7 +313,7 @@ impl<'a> NormalizedPat<'a> {
313313
},
314314
PatKind::Lit(e) => match &e.kind {
315315
// TODO: Handle negative integers. They're currently treated as a wild match.
316-
ExprKind::Lit(lit) => match lit.node {
316+
PatExprKind::Lit{ lit, negated: false } => match lit.node {
317317
LitKind::Str(sym, _) => Self::LitStr(sym),
318318
LitKind::ByteStr(ref bytes, _) | LitKind::CStr(ref bytes, _) => Self::LitBytes(bytes),
319319
LitKind::Byte(val) => Self::LitInt(val.into()),
@@ -330,7 +330,7 @@ impl<'a> NormalizedPat<'a> {
330330
let start = match start {
331331
None => 0,
332332
Some(e) => match &e.kind {
333-
ExprKind::Lit(lit) => match lit.node {
333+
PatExprKind::Lit { lit, negated: false } => match lit.node {
334334
LitKind::Int(val, _) => val.get(),
335335
LitKind::Char(val) => val.into(),
336336
LitKind::Byte(val) => val.into(),
@@ -342,7 +342,7 @@ impl<'a> NormalizedPat<'a> {
342342
let (end, bounds) = match end {
343343
None => (u128::MAX, RangeEnd::Included),
344344
Some(e) => match &e.kind {
345-
ExprKind::Lit(lit) => match lit.node {
345+
PatExprKind::Lit { lit, negated: false } => match lit.node {
346346
LitKind::Int(val, _) => (val.get(), bounds),
347347
LitKind::Char(val) => (val.into(), bounds),
348348
LitKind::Byte(val) => (val.into(), bounds),

Diff for: clippy_lints/src/matches/match_str_case_mismatch.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use clippy_utils::ty::is_type_lang_item;
55
use rustc_ast::ast::LitKind;
66
use rustc_errors::Applicability;
77
use rustc_hir::intravisit::{Visitor, walk_expr};
8-
use rustc_hir::{Arm, Expr, ExprKind, LangItem, PatKind};
8+
use rustc_hir::{Arm, Expr, ExprKind, PatExpr, PatExprKind, LangItem, PatKind};
99
use rustc_lint::LateContext;
1010
use rustc_middle::ty;
1111
use rustc_span::Span;
@@ -85,8 +85,8 @@ fn verify_case<'a>(case_method: &'a CaseMethod, arms: &'a [Arm<'_>]) -> Option<(
8585
};
8686

8787
for arm in arms {
88-
if let PatKind::Lit(Expr {
89-
kind: ExprKind::Lit(lit),
88+
if let PatKind::Lit(PatExpr {
89+
kind: PatExprKind::Lit { lit, negated: false },
9090
..
9191
}) = arm.pat.kind
9292
&& let LitKind::Str(symbol, _) = lit.node

Diff for: clippy_lints/src/matches/needless_match.rs

+8-4
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use clippy_utils::{
88
};
99
use rustc_errors::Applicability;
1010
use rustc_hir::LangItem::OptionNone;
11-
use rustc_hir::{Arm, BindingMode, ByRef, Expr, ExprKind, ItemKind, Node, Pat, PatKind, Path, QPath};
11+
use rustc_hir::{Arm, BindingMode, ByRef, Expr, ExprKind, ItemKind, Node, Pat, PatExprKind, PatKind, Path, QPath};
1212
use rustc_lint::LateContext;
1313
use rustc_span::sym;
1414

@@ -133,7 +133,7 @@ fn expr_ty_matches_p_ty(cx: &LateContext<'_>, expr: &Expr<'_>, p_expr: &Expr<'_>
133133
},
134134
// compare match_expr ty with RetTy in `fn foo() -> RetTy`
135135
Node::Item(item) => {
136-
if let ItemKind::Fn{ .. } = item.kind {
136+
if let ItemKind::Fn { .. } = item.kind {
137137
let output = cx
138138
.tcx
139139
.fn_sig(item.owner_id)
@@ -189,8 +189,12 @@ fn pat_same_as_expr(pat: &Pat<'_>, expr: &Expr<'_>) -> bool {
189189
});
190190
},
191191
// Example: `5 => 5`
192-
(PatKind::Lit(pat_lit_expr), ExprKind::Lit(expr_spanned)) => {
193-
if let ExprKind::Lit(pat_spanned) = &pat_lit_expr.kind {
192+
(PatKind::Lit(pat_expr_expr), ExprKind::Lit(expr_spanned)) => {
193+
if let PatExprKind::Lit {
194+
lit: pat_spanned,
195+
negated: false,
196+
} = &pat_expr_expr.kind
197+
{
194198
return pat_spanned.node == expr_spanned.node;
195199
}
196200
},

Diff for: clippy_lints/src/matches/overlapping_arms.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,13 @@ fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>)
3434
if let Arm { pat, guard: None, .. } = *arm {
3535
if let PatKind::Range(ref lhs, ref rhs, range_end) = pat.kind {
3636
let lhs_const = if let Some(lhs) = lhs {
37-
ConstEvalCtxt::new(cx).eval(lhs)?
37+
ConstEvalCtxt::new(cx).eval_pat_expr(lhs)?
3838
} else {
3939
let min_val_const = ty.numeric_min_val(cx.tcx)?;
4040
mir_to_const(cx.tcx, mir::Const::from_ty_const(min_val_const, ty, cx.tcx))?
4141
};
4242
let rhs_const = if let Some(rhs) = rhs {
43-
ConstEvalCtxt::new(cx).eval(rhs)?
43+
ConstEvalCtxt::new(cx).eval_pat_expr(rhs)?
4444
} else {
4545
let max_val_const = ty.numeric_max_val(cx.tcx)?;
4646
mir_to_const(cx.tcx, mir::Const::from_ty_const(max_val_const, ty, cx.tcx))?
@@ -58,7 +58,9 @@ fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>)
5858
}
5959

6060
if let PatKind::Lit(value) = pat.kind {
61-
let value = ConstEvalCtxt::new(cx).eval_full_int(value)?;
61+
let value = ConstEvalCtxt::new(cx)
62+
.eval_pat_expr(value)?
63+
.int_value(cx.tcx, cx.typeck_results().node_type(pat.hir_id))?;
6264
return Some(SpannedRange {
6365
span: pat.span,
6466
node: (value, EndBound::Included(value)),

Diff for: clippy_lints/src/matches/redundant_pattern_match.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use rustc_ast::ast::LitKind;
99
use rustc_errors::Applicability;
1010
use rustc_hir::LangItem::{self, OptionNone, OptionSome, PollPending, PollReady, ResultErr, ResultOk};
1111
use rustc_hir::def::{DefKind, Res};
12-
use rustc_hir::{Arm, Expr, ExprKind, Node, Pat, PatKind, QPath, UnOp};
12+
use rustc_hir::{Arm, Expr, ExprKind, Node, Pat, PatKind, QPath, UnOp, PatExprKind};
1313
use rustc_lint::LateContext;
1414
use rustc_middle::ty::{self, GenericArgKind, Ty};
1515
use rustc_span::{Span, Symbol, sym};
@@ -75,7 +75,7 @@ fn find_match_true<'tcx>(
7575
message: &'static str,
7676
) {
7777
if let PatKind::Lit(lit) = pat.kind
78-
&& let ExprKind::Lit(lit) = lit.kind
78+
&& let PatExprKind::Lit{ lit, negated: false } = lit.kind
7979
&& let LitKind::Bool(pat_is_true) = lit.node
8080
{
8181
let mut applicability = Applicability::MachineApplicable;

Diff for: clippy_lints/src/matches/single_match.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use rustc_arena::DroplessArena;
99
use rustc_errors::Applicability;
1010
use rustc_hir::def::{DefKind, Res};
1111
use rustc_hir::intravisit::{Visitor, walk_pat};
12-
use rustc_hir::{Arm, Expr, ExprKind, HirId, Node, Pat, PatKind, QPath, StmtKind};
12+
use rustc_hir::{Arm, Expr, ExprKind, HirId, Node, Pat, PatKind, QPath, StmtKind, PatExpr, PatExprKind};
1313
use rustc_lint::LateContext;
1414
use rustc_middle::ty::{self, AdtDef, TyCtxt, TypeckResults, VariantDef};
1515
use rustc_span::{Span, sym};
@@ -126,8 +126,8 @@ fn report_single_pattern(cx: &LateContext<'_>, ex: &Expr<'_>, arm: &Arm<'_>, exp
126126
// scrutinee derives PartialEq and the pattern is a constant.
127127
let pat_ref_count = match pat.kind {
128128
// string literals are already a reference.
129-
PatKind::Lit(Expr {
130-
kind: ExprKind::Lit(lit),
129+
PatKind::Lit(PatExpr {
130+
kind: PatExprKind::Lit { lit, negated: false },
131131
..
132132
}) if lit.node.is_str() || lit.node.is_bytestr() => pat_ref_count + 1,
133133
_ => pat_ref_count,

Diff for: clippy_lints/src/string_patterns.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use clippy_utils::visitors::{Descend, for_each_expr};
1111
use itertools::Itertools;
1212
use rustc_ast::{BinOpKind, LitKind};
1313
use rustc_errors::Applicability;
14-
use rustc_hir::{Expr, ExprKind, PatKind};
14+
use rustc_hir::{Expr, ExprKind, PatExprKind, PatKind};
1515
use rustc_lint::{LateContext, LateLintPass};
1616
use rustc_middle::ty;
1717
use rustc_session::impl_lint_pass;
@@ -171,7 +171,7 @@ fn check_manual_pattern_char_comparison(cx: &LateContext<'_>, method_arg: &Expr<
171171
return ControlFlow::Break(());
172172
}
173173
if arm.pat.walk_short(|pat| match pat.kind {
174-
PatKind::Lit(expr) if let ExprKind::Lit(lit) = expr.kind => {
174+
PatKind::Lit(expr) if let PatExprKind::Lit { lit, negated: false } = expr.kind => {
175175
if let LitKind::Char(_) = lit.node {
176176
set_char_spans.push(lit.span);
177177
}

0 commit comments

Comments
 (0)