mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-22 20:03:37 +00:00
Auto merge of #5769 - robojumper:match_like_matches_macro, r=phansch
new lint: match_like_matches_macro Suggests using the `matches!` macro from `std` where appropriate. `redundant_pattern_matching` has been moved into the `matches` pass to allow suppressing the suggestion where `is_some` and friends are a better replacement. changelog: new lint: `match_like_matches_macro`
This commit is contained in:
commit
7d611d9224
@ -1513,6 +1513,7 @@ Released 2018-09-13
|
|||||||
[`map_unwrap_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_unwrap_or
|
[`map_unwrap_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_unwrap_or
|
||||||
[`match_as_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_as_ref
|
[`match_as_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_as_ref
|
||||||
[`match_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_bool
|
[`match_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_bool
|
||||||
|
[`match_like_matches_macro`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_like_matches_macro
|
||||||
[`match_on_vec_items`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_on_vec_items
|
[`match_on_vec_items`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_on_vec_items
|
||||||
[`match_overlapping_arm`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_overlapping_arm
|
[`match_overlapping_arm`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_overlapping_arm
|
||||||
[`match_ref_pats`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_ref_pats
|
[`match_ref_pats`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_ref_pats
|
||||||
|
@ -122,8 +122,5 @@ impl<'tcx> LateLintPass<'tcx> for ComparisonChain {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn kind_is_cmp(kind: BinOpKind) -> bool {
|
fn kind_is_cmp(kind: BinOpKind) -> bool {
|
||||||
match kind {
|
matches!(kind, BinOpKind::Lt | BinOpKind::Gt | BinOpKind::Eq)
|
||||||
BinOpKind::Lt | BinOpKind::Gt | BinOpKind::Eq => true,
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -214,20 +214,20 @@ impl<'tcx> LateLintPass<'tcx> for EqOp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn is_valid_operator(op: BinOp) -> bool {
|
fn is_valid_operator(op: BinOp) -> bool {
|
||||||
match op.node {
|
matches!(
|
||||||
|
op.node,
|
||||||
BinOpKind::Sub
|
BinOpKind::Sub
|
||||||
| BinOpKind::Div
|
| BinOpKind::Div
|
||||||
| BinOpKind::Eq
|
| BinOpKind::Eq
|
||||||
| BinOpKind::Lt
|
| BinOpKind::Lt
|
||||||
| BinOpKind::Le
|
| BinOpKind::Le
|
||||||
| BinOpKind::Gt
|
| BinOpKind::Gt
|
||||||
| BinOpKind::Ge
|
| BinOpKind::Ge
|
||||||
| BinOpKind::Ne
|
| BinOpKind::Ne
|
||||||
| BinOpKind::And
|
| BinOpKind::And
|
||||||
| BinOpKind::Or
|
| BinOpKind::Or
|
||||||
| BinOpKind::BitXor
|
| BinOpKind::BitXor
|
||||||
| BinOpKind::BitAnd
|
| BinOpKind::BitAnd
|
||||||
| BinOpKind::BitOr => true,
|
| BinOpKind::BitOr
|
||||||
_ => false,
|
)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -105,10 +105,7 @@ fn is_argument(map: rustc_middle::hir::map::Map<'_>, id: HirId) -> bool {
|
|||||||
_ => return false,
|
_ => return false,
|
||||||
}
|
}
|
||||||
|
|
||||||
match map.find(map.get_parent_node(id)) {
|
matches!(map.find(map.get_parent_node(id)), Some(Node::Param(_)))
|
||||||
Some(Node::Param(_)) => true,
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> {
|
impl<'a, 'tcx> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> {
|
||||||
|
@ -175,10 +175,7 @@ fn get_ufcs_type_name(cx: &LateContext<'_>, method_def_id: def_id::DefId, self_a
|
|||||||
fn match_borrow_depth(lhs: Ty<'_>, rhs: Ty<'_>) -> bool {
|
fn match_borrow_depth(lhs: Ty<'_>, rhs: Ty<'_>) -> bool {
|
||||||
match (&lhs.kind, &rhs.kind) {
|
match (&lhs.kind, &rhs.kind) {
|
||||||
(ty::Ref(_, t1, mut1), ty::Ref(_, t2, mut2)) => mut1 == mut2 && match_borrow_depth(&t1, &t2),
|
(ty::Ref(_, t1, mut1), ty::Ref(_, t2, mut2)) => mut1 == mut2 && match_borrow_depth(&t1, &t2),
|
||||||
(l, r) => match (l, r) {
|
(l, r) => !matches!((l, r), (ty::Ref(_, _, _), _) | (_, ty::Ref(_, _, _))),
|
||||||
(ty::Ref(_, _, _), _) | (_, ty::Ref(_, _, _)) => false,
|
|
||||||
(_, _) => true,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -305,18 +305,10 @@ fn check_missing_else(cx: &EarlyContext<'_>, first: &Expr, second: &Expr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn is_block(expr: &Expr) -> bool {
|
fn is_block(expr: &Expr) -> bool {
|
||||||
if let ExprKind::Block(..) = expr.kind {
|
matches!(expr.kind, ExprKind::Block(..))
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if the expression is an `if` or `if let`
|
/// Check if the expression is an `if` or `if let`
|
||||||
fn is_if(expr: &Expr) -> bool {
|
fn is_if(expr: &Expr) -> bool {
|
||||||
if let ExprKind::If(..) = expr.kind {
|
matches!(expr.kind, ExprKind::If(..))
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -645,13 +645,7 @@ fn is_mutated_static(cx: &LateContext<'_>, e: &hir::Expr<'_>) -> bool {
|
|||||||
use hir::ExprKind::{Field, Index, Path};
|
use hir::ExprKind::{Field, Index, Path};
|
||||||
|
|
||||||
match e.kind {
|
match e.kind {
|
||||||
Path(ref qpath) => {
|
Path(ref qpath) => !matches!(qpath_res(cx, qpath, e.hir_id), Res::Local(_)),
|
||||||
if let Res::Local(_) = qpath_res(cx, qpath, e.hir_id) {
|
|
||||||
false
|
|
||||||
} else {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Field(ref inner, _) | Index(ref inner, _) => is_mutated_static(cx, inner),
|
Field(ref inner, _) | Index(ref inner, _) => is_mutated_static(cx, inner),
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
|
@ -277,7 +277,6 @@ mod question_mark;
|
|||||||
mod ranges;
|
mod ranges;
|
||||||
mod redundant_clone;
|
mod redundant_clone;
|
||||||
mod redundant_field_names;
|
mod redundant_field_names;
|
||||||
mod redundant_pattern_matching;
|
|
||||||
mod redundant_pub_crate;
|
mod redundant_pub_crate;
|
||||||
mod redundant_static_lifetimes;
|
mod redundant_static_lifetimes;
|
||||||
mod reference;
|
mod reference;
|
||||||
@ -623,11 +622,13 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||||||
&matches::INFALLIBLE_DESTRUCTURING_MATCH,
|
&matches::INFALLIBLE_DESTRUCTURING_MATCH,
|
||||||
&matches::MATCH_AS_REF,
|
&matches::MATCH_AS_REF,
|
||||||
&matches::MATCH_BOOL,
|
&matches::MATCH_BOOL,
|
||||||
|
&matches::MATCH_LIKE_MATCHES_MACRO,
|
||||||
&matches::MATCH_OVERLAPPING_ARM,
|
&matches::MATCH_OVERLAPPING_ARM,
|
||||||
&matches::MATCH_REF_PATS,
|
&matches::MATCH_REF_PATS,
|
||||||
&matches::MATCH_SINGLE_BINDING,
|
&matches::MATCH_SINGLE_BINDING,
|
||||||
&matches::MATCH_WILDCARD_FOR_SINGLE_VARIANTS,
|
&matches::MATCH_WILDCARD_FOR_SINGLE_VARIANTS,
|
||||||
&matches::MATCH_WILD_ERR_ARM,
|
&matches::MATCH_WILD_ERR_ARM,
|
||||||
|
&matches::REDUNDANT_PATTERN_MATCHING,
|
||||||
&matches::REST_PAT_IN_FULLY_BOUND_STRUCTS,
|
&matches::REST_PAT_IN_FULLY_BOUND_STRUCTS,
|
||||||
&matches::SINGLE_MATCH,
|
&matches::SINGLE_MATCH,
|
||||||
&matches::SINGLE_MATCH_ELSE,
|
&matches::SINGLE_MATCH_ELSE,
|
||||||
@ -757,7 +758,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||||||
&ranges::REVERSED_EMPTY_RANGES,
|
&ranges::REVERSED_EMPTY_RANGES,
|
||||||
&redundant_clone::REDUNDANT_CLONE,
|
&redundant_clone::REDUNDANT_CLONE,
|
||||||
&redundant_field_names::REDUNDANT_FIELD_NAMES,
|
&redundant_field_names::REDUNDANT_FIELD_NAMES,
|
||||||
&redundant_pattern_matching::REDUNDANT_PATTERN_MATCHING,
|
|
||||||
&redundant_pub_crate::REDUNDANT_PUB_CRATE,
|
&redundant_pub_crate::REDUNDANT_PUB_CRATE,
|
||||||
&redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES,
|
&redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES,
|
||||||
&reference::DEREF_ADDROF,
|
&reference::DEREF_ADDROF,
|
||||||
@ -956,7 +956,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||||||
store.register_late_pass(|| box missing_doc::MissingDoc::new());
|
store.register_late_pass(|| box missing_doc::MissingDoc::new());
|
||||||
store.register_late_pass(|| box missing_inline::MissingInline);
|
store.register_late_pass(|| box missing_inline::MissingInline);
|
||||||
store.register_late_pass(|| box if_let_some_result::OkIfLet);
|
store.register_late_pass(|| box if_let_some_result::OkIfLet);
|
||||||
store.register_late_pass(|| box redundant_pattern_matching::RedundantPatternMatching);
|
|
||||||
store.register_late_pass(|| box partialeq_ne_impl::PartialEqNeImpl);
|
store.register_late_pass(|| box partialeq_ne_impl::PartialEqNeImpl);
|
||||||
store.register_late_pass(|| box unused_io_amount::UnusedIoAmount);
|
store.register_late_pass(|| box unused_io_amount::UnusedIoAmount);
|
||||||
let enum_variant_size_threshold = conf.enum_variant_size_threshold;
|
let enum_variant_size_threshold = conf.enum_variant_size_threshold;
|
||||||
@ -1295,9 +1294,11 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||||||
LintId::of(&map_unit_fn::RESULT_MAP_UNIT_FN),
|
LintId::of(&map_unit_fn::RESULT_MAP_UNIT_FN),
|
||||||
LintId::of(&matches::INFALLIBLE_DESTRUCTURING_MATCH),
|
LintId::of(&matches::INFALLIBLE_DESTRUCTURING_MATCH),
|
||||||
LintId::of(&matches::MATCH_AS_REF),
|
LintId::of(&matches::MATCH_AS_REF),
|
||||||
|
LintId::of(&matches::MATCH_LIKE_MATCHES_MACRO),
|
||||||
LintId::of(&matches::MATCH_OVERLAPPING_ARM),
|
LintId::of(&matches::MATCH_OVERLAPPING_ARM),
|
||||||
LintId::of(&matches::MATCH_REF_PATS),
|
LintId::of(&matches::MATCH_REF_PATS),
|
||||||
LintId::of(&matches::MATCH_SINGLE_BINDING),
|
LintId::of(&matches::MATCH_SINGLE_BINDING),
|
||||||
|
LintId::of(&matches::REDUNDANT_PATTERN_MATCHING),
|
||||||
LintId::of(&matches::SINGLE_MATCH),
|
LintId::of(&matches::SINGLE_MATCH),
|
||||||
LintId::of(&matches::WILDCARD_IN_OR_PATTERNS),
|
LintId::of(&matches::WILDCARD_IN_OR_PATTERNS),
|
||||||
LintId::of(&mem_discriminant::MEM_DISCRIMINANT_NON_ENUM),
|
LintId::of(&mem_discriminant::MEM_DISCRIMINANT_NON_ENUM),
|
||||||
@ -1387,7 +1388,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||||||
LintId::of(&ranges::REVERSED_EMPTY_RANGES),
|
LintId::of(&ranges::REVERSED_EMPTY_RANGES),
|
||||||
LintId::of(&redundant_clone::REDUNDANT_CLONE),
|
LintId::of(&redundant_clone::REDUNDANT_CLONE),
|
||||||
LintId::of(&redundant_field_names::REDUNDANT_FIELD_NAMES),
|
LintId::of(&redundant_field_names::REDUNDANT_FIELD_NAMES),
|
||||||
LintId::of(&redundant_pattern_matching::REDUNDANT_PATTERN_MATCHING),
|
|
||||||
LintId::of(&redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES),
|
LintId::of(&redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES),
|
||||||
LintId::of(&reference::DEREF_ADDROF),
|
LintId::of(&reference::DEREF_ADDROF),
|
||||||
LintId::of(&reference::REF_IN_DEREF),
|
LintId::of(&reference::REF_IN_DEREF),
|
||||||
@ -1488,8 +1488,10 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||||||
LintId::of(&manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE),
|
LintId::of(&manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE),
|
||||||
LintId::of(&map_clone::MAP_CLONE),
|
LintId::of(&map_clone::MAP_CLONE),
|
||||||
LintId::of(&matches::INFALLIBLE_DESTRUCTURING_MATCH),
|
LintId::of(&matches::INFALLIBLE_DESTRUCTURING_MATCH),
|
||||||
|
LintId::of(&matches::MATCH_LIKE_MATCHES_MACRO),
|
||||||
LintId::of(&matches::MATCH_OVERLAPPING_ARM),
|
LintId::of(&matches::MATCH_OVERLAPPING_ARM),
|
||||||
LintId::of(&matches::MATCH_REF_PATS),
|
LintId::of(&matches::MATCH_REF_PATS),
|
||||||
|
LintId::of(&matches::REDUNDANT_PATTERN_MATCHING),
|
||||||
LintId::of(&matches::SINGLE_MATCH),
|
LintId::of(&matches::SINGLE_MATCH),
|
||||||
LintId::of(&mem_replace::MEM_REPLACE_OPTION_WITH_NONE),
|
LintId::of(&mem_replace::MEM_REPLACE_OPTION_WITH_NONE),
|
||||||
LintId::of(&mem_replace::MEM_REPLACE_WITH_DEFAULT),
|
LintId::of(&mem_replace::MEM_REPLACE_WITH_DEFAULT),
|
||||||
@ -1526,7 +1528,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||||||
LintId::of(&ptr::PTR_ARG),
|
LintId::of(&ptr::PTR_ARG),
|
||||||
LintId::of(&question_mark::QUESTION_MARK),
|
LintId::of(&question_mark::QUESTION_MARK),
|
||||||
LintId::of(&redundant_field_names::REDUNDANT_FIELD_NAMES),
|
LintId::of(&redundant_field_names::REDUNDANT_FIELD_NAMES),
|
||||||
LintId::of(&redundant_pattern_matching::REDUNDANT_PATTERN_MATCHING),
|
|
||||||
LintId::of(&redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES),
|
LintId::of(&redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES),
|
||||||
LintId::of(®ex::TRIVIAL_REGEX),
|
LintId::of(®ex::TRIVIAL_REGEX),
|
||||||
LintId::of(&returns::NEEDLESS_RETURN),
|
LintId::of(&returns::NEEDLESS_RETURN),
|
||||||
|
@ -129,10 +129,10 @@ fn check_fn_inner<'tcx>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mut bounds_lts = Vec::new();
|
let mut bounds_lts = Vec::new();
|
||||||
let types = generics.params.iter().filter(|param| match param.kind {
|
let types = generics
|
||||||
GenericParamKind::Type { .. } => true,
|
.params
|
||||||
_ => false,
|
.iter()
|
||||||
});
|
.filter(|param| matches!(param.kind, GenericParamKind::Type { .. }));
|
||||||
for typ in types {
|
for typ in types {
|
||||||
for bound in typ.bounds {
|
for bound in typ.bounds {
|
||||||
let mut visitor = RefVisitor::new(cx);
|
let mut visitor = RefVisitor::new(cx);
|
||||||
@ -337,10 +337,10 @@ impl<'a, 'tcx> RefVisitor<'a, 'tcx> {
|
|||||||
fn collect_anonymous_lifetimes(&mut self, qpath: &QPath<'_>, ty: &Ty<'_>) {
|
fn collect_anonymous_lifetimes(&mut self, qpath: &QPath<'_>, ty: &Ty<'_>) {
|
||||||
if let Some(ref last_path_segment) = last_path_segment(qpath).args {
|
if let Some(ref last_path_segment) = last_path_segment(qpath).args {
|
||||||
if !last_path_segment.parenthesized
|
if !last_path_segment.parenthesized
|
||||||
&& !last_path_segment.args.iter().any(|arg| match arg {
|
&& !last_path_segment
|
||||||
GenericArg::Lifetime(_) => true,
|
.args
|
||||||
_ => false,
|
.iter()
|
||||||
})
|
.any(|arg| matches!(arg, GenericArg::Lifetime(_)))
|
||||||
{
|
{
|
||||||
let hir_id = ty.hir_id;
|
let hir_id = ty.hir_id;
|
||||||
match self.cx.qpath_res(qpath, hir_id) {
|
match self.cx.qpath_res(qpath, hir_id) {
|
||||||
|
@ -2091,17 +2091,11 @@ fn var_def_id(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<HirId> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn is_loop(expr: &Expr<'_>) -> bool {
|
fn is_loop(expr: &Expr<'_>) -> bool {
|
||||||
match expr.kind {
|
matches!(expr.kind, ExprKind::Loop(..))
|
||||||
ExprKind::Loop(..) => true,
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_conditional(expr: &Expr<'_>) -> bool {
|
fn is_conditional(expr: &Expr<'_>) -> bool {
|
||||||
match expr.kind {
|
matches!(expr.kind, ExprKind::Match(..))
|
||||||
ExprKind::Match(..) => true,
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_nested(cx: &LateContext<'_>, match_expr: &Expr<'_>, iter_expr: &Expr<'_>) -> bool {
|
fn is_nested(cx: &LateContext<'_>, match_expr: &Expr<'_>, iter_expr: &Expr<'_>) -> bool {
|
||||||
|
@ -13,14 +13,14 @@ use rustc_ast::ast::LitKind;
|
|||||||
use rustc_errors::Applicability;
|
use rustc_errors::Applicability;
|
||||||
use rustc_hir::def::CtorKind;
|
use rustc_hir::def::CtorKind;
|
||||||
use rustc_hir::{
|
use rustc_hir::{
|
||||||
Arm, BindingAnnotation, Block, BorrowKind, Expr, ExprKind, Local, MatchSource, Mutability, Node, Pat, PatKind,
|
Arm, BindingAnnotation, Block, BorrowKind, Expr, ExprKind, Guard, Local, MatchSource, Mutability, Node, Pat,
|
||||||
QPath, RangeEnd,
|
PatKind, QPath, RangeEnd,
|
||||||
};
|
};
|
||||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||||
use rustc_middle::lint::in_external_macro;
|
use rustc_middle::lint::in_external_macro;
|
||||||
use rustc_middle::ty::{self, Ty};
|
use rustc_middle::ty::{self, Ty};
|
||||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||||
use rustc_span::source_map::Span;
|
use rustc_span::source_map::{Span, Spanned};
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::collections::Bound;
|
use std::collections::Bound;
|
||||||
|
|
||||||
@ -409,6 +409,74 @@ declare_clippy_lint! {
|
|||||||
"a match on a struct that binds all fields but still uses the wildcard pattern"
|
"a match on a struct that binds all fields but still uses the wildcard pattern"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
declare_clippy_lint! {
|
||||||
|
/// **What it does:** Lint for redundant pattern matching over `Result` or
|
||||||
|
/// `Option`
|
||||||
|
///
|
||||||
|
/// **Why is this bad?** It's more concise and clear to just use the proper
|
||||||
|
/// utility function
|
||||||
|
///
|
||||||
|
/// **Known problems:** None.
|
||||||
|
///
|
||||||
|
/// **Example:**
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// if let Ok(_) = Ok::<i32, i32>(42) {}
|
||||||
|
/// if let Err(_) = Err::<i32, i32>(42) {}
|
||||||
|
/// if let None = None::<()> {}
|
||||||
|
/// if let Some(_) = Some(42) {}
|
||||||
|
/// match Ok::<i32, i32>(42) {
|
||||||
|
/// Ok(_) => true,
|
||||||
|
/// Err(_) => false,
|
||||||
|
/// };
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// The more idiomatic use would be:
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// if Ok::<i32, i32>(42).is_ok() {}
|
||||||
|
/// if Err::<i32, i32>(42).is_err() {}
|
||||||
|
/// if None::<()>.is_none() {}
|
||||||
|
/// if Some(42).is_some() {}
|
||||||
|
/// Ok::<i32, i32>(42).is_ok();
|
||||||
|
/// ```
|
||||||
|
pub REDUNDANT_PATTERN_MATCHING,
|
||||||
|
style,
|
||||||
|
"use the proper utility function avoiding an `if let`"
|
||||||
|
}
|
||||||
|
|
||||||
|
declare_clippy_lint! {
|
||||||
|
/// **What it does:** Checks for `match` or `if let` expressions producing a
|
||||||
|
/// `bool` that could be written using `matches!`
|
||||||
|
///
|
||||||
|
/// **Why is this bad?** Readability and needless complexity.
|
||||||
|
///
|
||||||
|
/// **Known problems:** None
|
||||||
|
///
|
||||||
|
/// **Example:**
|
||||||
|
/// ```rust
|
||||||
|
/// let x = Some(5);
|
||||||
|
///
|
||||||
|
/// // Bad
|
||||||
|
/// let a = match x {
|
||||||
|
/// Some(0) => true,
|
||||||
|
/// _ => false,
|
||||||
|
/// };
|
||||||
|
///
|
||||||
|
/// let a = if let Some(0) = x {
|
||||||
|
/// true
|
||||||
|
/// } else {
|
||||||
|
/// false
|
||||||
|
/// };
|
||||||
|
///
|
||||||
|
/// // Good
|
||||||
|
/// let a = matches!(x, Some(0));
|
||||||
|
/// ```
|
||||||
|
pub MATCH_LIKE_MATCHES_MACRO,
|
||||||
|
style,
|
||||||
|
"a match that could be written with the matches! macro"
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct Matches {
|
pub struct Matches {
|
||||||
infallible_destructuring_match_linted: bool,
|
infallible_destructuring_match_linted: bool,
|
||||||
@ -427,7 +495,9 @@ impl_lint_pass!(Matches => [
|
|||||||
WILDCARD_IN_OR_PATTERNS,
|
WILDCARD_IN_OR_PATTERNS,
|
||||||
MATCH_SINGLE_BINDING,
|
MATCH_SINGLE_BINDING,
|
||||||
INFALLIBLE_DESTRUCTURING_MATCH,
|
INFALLIBLE_DESTRUCTURING_MATCH,
|
||||||
REST_PAT_IN_FULLY_BOUND_STRUCTS
|
REST_PAT_IN_FULLY_BOUND_STRUCTS,
|
||||||
|
REDUNDANT_PATTERN_MATCHING,
|
||||||
|
MATCH_LIKE_MATCHES_MACRO
|
||||||
]);
|
]);
|
||||||
|
|
||||||
impl<'tcx> LateLintPass<'tcx> for Matches {
|
impl<'tcx> LateLintPass<'tcx> for Matches {
|
||||||
@ -435,6 +505,10 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
|
|||||||
if in_external_macro(cx.sess(), expr.span) {
|
if in_external_macro(cx.sess(), expr.span) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
redundant_pattern_match::check(cx, expr);
|
||||||
|
check_match_like_matches(cx, expr);
|
||||||
|
|
||||||
if let ExprKind::Match(ref ex, ref arms, MatchSource::Normal) = expr.kind {
|
if let ExprKind::Match(ref ex, ref arms, MatchSource::Normal) = expr.kind {
|
||||||
check_single_match(cx, ex, arms, expr);
|
check_single_match(cx, ex, arms, expr);
|
||||||
check_match_bool(cx, ex, arms, expr);
|
check_match_bool(cx, ex, arms, expr);
|
||||||
@ -808,13 +882,8 @@ fn check_wild_enum_match(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>])
|
|||||||
// Some simple checks for exhaustive patterns.
|
// Some simple checks for exhaustive patterns.
|
||||||
// There is a room for improvements to detect more cases,
|
// There is a room for improvements to detect more cases,
|
||||||
// but it can be more expensive to do so.
|
// but it can be more expensive to do so.
|
||||||
let is_pattern_exhaustive = |pat: &&Pat<'_>| {
|
let is_pattern_exhaustive =
|
||||||
if let PatKind::Wild | PatKind::Binding(.., None) = pat.kind {
|
|pat: &&Pat<'_>| matches!(pat.kind, PatKind::Wild | PatKind::Binding(.., None));
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
};
|
|
||||||
if patterns.iter().all(is_pattern_exhaustive) {
|
if patterns.iter().all(is_pattern_exhaustive) {
|
||||||
missing_variants.retain(|e| e.ctor_def_id != Some(p.res.def_id()));
|
missing_variants.retain(|e| e.ctor_def_id != Some(p.res.def_id()));
|
||||||
}
|
}
|
||||||
@ -995,6 +1064,79 @@ fn check_wild_in_or_pats(cx: &LateContext<'_>, arms: &[Arm<'_>]) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Lint a `match` or `if let .. { .. } else { .. }` expr that could be replaced by `matches!`
|
||||||
|
fn check_match_like_matches<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||||
|
if let ExprKind::Match(ex, arms, ref match_source) = &expr.kind {
|
||||||
|
match match_source {
|
||||||
|
MatchSource::Normal => find_matches_sugg(cx, ex, arms, expr, false),
|
||||||
|
MatchSource::IfLetDesugar { .. } => find_matches_sugg(cx, ex, arms, expr, true),
|
||||||
|
_ => return,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Lint a `match` or desugared `if let` for replacement by `matches!`
|
||||||
|
fn find_matches_sugg(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: &Expr<'_>, desugared: bool) {
|
||||||
|
if_chain! {
|
||||||
|
if arms.len() == 2;
|
||||||
|
if cx.tables().expr_ty(expr).is_bool();
|
||||||
|
if is_wild(&arms[1].pat);
|
||||||
|
if let Some(first) = find_bool_lit(&arms[0].body.kind, desugared);
|
||||||
|
if let Some(second) = find_bool_lit(&arms[1].body.kind, desugared);
|
||||||
|
if first != second;
|
||||||
|
then {
|
||||||
|
let mut applicability = Applicability::MachineApplicable;
|
||||||
|
|
||||||
|
let pat_and_guard = if let Some(Guard::If(g)) = arms[0].guard {
|
||||||
|
format!("{} if {}", snippet_with_applicability(cx, arms[0].pat.span, "..", &mut applicability), snippet_with_applicability(cx, g.span, "..", &mut applicability))
|
||||||
|
} else {
|
||||||
|
format!("{}", snippet_with_applicability(cx, arms[0].pat.span, "..", &mut applicability))
|
||||||
|
};
|
||||||
|
span_lint_and_sugg(
|
||||||
|
cx,
|
||||||
|
MATCH_LIKE_MATCHES_MACRO,
|
||||||
|
expr.span,
|
||||||
|
&format!("{} expression looks like `matches!` macro", if desugared { "if let .. else" } else { "match" }),
|
||||||
|
"try this",
|
||||||
|
format!(
|
||||||
|
"{}matches!({}, {})",
|
||||||
|
if first { "" } else { "!" },
|
||||||
|
snippet_with_applicability(cx, ex.span, "..", &mut applicability),
|
||||||
|
pat_and_guard,
|
||||||
|
),
|
||||||
|
applicability,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Extract a `bool` or `{ bool }`
|
||||||
|
fn find_bool_lit(ex: &ExprKind<'_>, desugared: bool) -> Option<bool> {
|
||||||
|
match ex {
|
||||||
|
ExprKind::Lit(Spanned {
|
||||||
|
node: LitKind::Bool(b), ..
|
||||||
|
}) => Some(*b),
|
||||||
|
ExprKind::Block(
|
||||||
|
rustc_hir::Block {
|
||||||
|
stmts: &[],
|
||||||
|
expr: Some(exp),
|
||||||
|
..
|
||||||
|
},
|
||||||
|
_,
|
||||||
|
) if desugared => {
|
||||||
|
if let ExprKind::Lit(Spanned {
|
||||||
|
node: LitKind::Bool(b), ..
|
||||||
|
}) = exp.kind
|
||||||
|
{
|
||||||
|
Some(b)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn check_match_single_binding<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], expr: &Expr<'_>) {
|
fn check_match_single_binding<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], expr: &Expr<'_>) {
|
||||||
if in_macro(expr.span) || arms.len() != 1 || is_refutable(cx, arms[0].pat) {
|
if in_macro(expr.span) || arms.len() != 1 || is_refutable(cx, arms[0].pat) {
|
||||||
return;
|
return;
|
||||||
@ -1185,10 +1327,7 @@ fn is_unit_expr(expr: &Expr<'_>) -> bool {
|
|||||||
|
|
||||||
// Checks if arm has the form `None => None`
|
// Checks if arm has the form `None => None`
|
||||||
fn is_none_arm(arm: &Arm<'_>) -> bool {
|
fn is_none_arm(arm: &Arm<'_>) -> bool {
|
||||||
match arm.pat.kind {
|
matches!(arm.pat.kind, PatKind::Path(ref path) if match_qpath(path, &paths::OPTION_NONE))
|
||||||
PatKind::Path(ref path) if match_qpath(path, &paths::OPTION_NONE) => true,
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks if arm has the form `Some(ref v) => Some(v)` (checks for `ref` and `ref mut`)
|
// Checks if arm has the form `Some(ref v) => Some(v)` (checks for `ref` and `ref mut`)
|
||||||
@ -1299,6 +1438,229 @@ where
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mod redundant_pattern_match {
|
||||||
|
use super::REDUNDANT_PATTERN_MATCHING;
|
||||||
|
use crate::utils::{in_constant, match_qpath, match_trait_method, paths, snippet, span_lint_and_then};
|
||||||
|
use if_chain::if_chain;
|
||||||
|
use rustc_ast::ast::LitKind;
|
||||||
|
use rustc_errors::Applicability;
|
||||||
|
use rustc_hir::{Arm, Expr, ExprKind, HirId, MatchSource, PatKind, QPath};
|
||||||
|
use rustc_lint::LateContext;
|
||||||
|
use rustc_middle::ty;
|
||||||
|
use rustc_mir::const_eval::is_const_fn;
|
||||||
|
use rustc_span::source_map::Symbol;
|
||||||
|
|
||||||
|
pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||||
|
if let ExprKind::Match(op, arms, ref match_source) = &expr.kind {
|
||||||
|
match match_source {
|
||||||
|
MatchSource::Normal => find_sugg_for_match(cx, expr, op, arms),
|
||||||
|
MatchSource::IfLetDesugar { .. } => find_sugg_for_if_let(cx, expr, op, arms, "if"),
|
||||||
|
MatchSource::WhileLetDesugar => find_sugg_for_if_let(cx, expr, op, arms, "while"),
|
||||||
|
_ => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_sugg_for_if_let<'tcx>(
|
||||||
|
cx: &LateContext<'tcx>,
|
||||||
|
expr: &'tcx Expr<'_>,
|
||||||
|
op: &Expr<'_>,
|
||||||
|
arms: &[Arm<'_>],
|
||||||
|
keyword: &'static str,
|
||||||
|
) {
|
||||||
|
fn find_suggestion(cx: &LateContext<'_>, hir_id: HirId, path: &QPath<'_>) -> Option<&'static str> {
|
||||||
|
if match_qpath(path, &paths::RESULT_OK) && can_suggest(cx, hir_id, sym!(result_type), "is_ok") {
|
||||||
|
return Some("is_ok()");
|
||||||
|
}
|
||||||
|
if match_qpath(path, &paths::RESULT_ERR) && can_suggest(cx, hir_id, sym!(result_type), "is_err") {
|
||||||
|
return Some("is_err()");
|
||||||
|
}
|
||||||
|
if match_qpath(path, &paths::OPTION_SOME) && can_suggest(cx, hir_id, sym!(option_type), "is_some") {
|
||||||
|
return Some("is_some()");
|
||||||
|
}
|
||||||
|
if match_qpath(path, &paths::OPTION_NONE) && can_suggest(cx, hir_id, sym!(option_type), "is_none") {
|
||||||
|
return Some("is_none()");
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
let hir_id = expr.hir_id;
|
||||||
|
let good_method = match arms[0].pat.kind {
|
||||||
|
PatKind::TupleStruct(ref path, ref patterns, _) if patterns.len() == 1 => {
|
||||||
|
if let PatKind::Wild = patterns[0].kind {
|
||||||
|
find_suggestion(cx, hir_id, path)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
},
|
||||||
|
PatKind::Path(ref path) => find_suggestion(cx, hir_id, path),
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
let good_method = match good_method {
|
||||||
|
Some(method) => method,
|
||||||
|
None => return,
|
||||||
|
};
|
||||||
|
|
||||||
|
// check that `while_let_on_iterator` lint does not trigger
|
||||||
|
if_chain! {
|
||||||
|
if keyword == "while";
|
||||||
|
if let ExprKind::MethodCall(method_path, _, _, _) = op.kind;
|
||||||
|
if method_path.ident.name == sym!(next);
|
||||||
|
if match_trait_method(cx, op, &paths::ITERATOR);
|
||||||
|
then {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
span_lint_and_then(
|
||||||
|
cx,
|
||||||
|
REDUNDANT_PATTERN_MATCHING,
|
||||||
|
arms[0].pat.span,
|
||||||
|
&format!("redundant pattern matching, consider using `{}`", good_method),
|
||||||
|
|diag| {
|
||||||
|
// while let ... = ... { ... }
|
||||||
|
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
let expr_span = expr.span;
|
||||||
|
|
||||||
|
// while let ... = ... { ... }
|
||||||
|
// ^^^
|
||||||
|
let op_span = op.span.source_callsite();
|
||||||
|
|
||||||
|
// while let ... = ... { ... }
|
||||||
|
// ^^^^^^^^^^^^^^^^^^^
|
||||||
|
let span = expr_span.until(op_span.shrink_to_hi());
|
||||||
|
diag.span_suggestion(
|
||||||
|
span,
|
||||||
|
"try this",
|
||||||
|
format!("{} {}.{}", keyword, snippet(cx, op_span, "_"), good_method),
|
||||||
|
Applicability::MachineApplicable, // snippet
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_sugg_for_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op: &Expr<'_>, arms: &[Arm<'_>]) {
|
||||||
|
if arms.len() == 2 {
|
||||||
|
let node_pair = (&arms[0].pat.kind, &arms[1].pat.kind);
|
||||||
|
|
||||||
|
let hir_id = expr.hir_id;
|
||||||
|
let found_good_method = match node_pair {
|
||||||
|
(
|
||||||
|
PatKind::TupleStruct(ref path_left, ref patterns_left, _),
|
||||||
|
PatKind::TupleStruct(ref path_right, ref patterns_right, _),
|
||||||
|
) if patterns_left.len() == 1 && patterns_right.len() == 1 => {
|
||||||
|
if let (PatKind::Wild, PatKind::Wild) = (&patterns_left[0].kind, &patterns_right[0].kind) {
|
||||||
|
find_good_method_for_match(
|
||||||
|
arms,
|
||||||
|
path_left,
|
||||||
|
path_right,
|
||||||
|
&paths::RESULT_OK,
|
||||||
|
&paths::RESULT_ERR,
|
||||||
|
"is_ok()",
|
||||||
|
"is_err()",
|
||||||
|
|| can_suggest(cx, hir_id, sym!(result_type), "is_ok"),
|
||||||
|
|| can_suggest(cx, hir_id, sym!(result_type), "is_err"),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
},
|
||||||
|
(PatKind::TupleStruct(ref path_left, ref patterns, _), PatKind::Path(ref path_right))
|
||||||
|
| (PatKind::Path(ref path_left), PatKind::TupleStruct(ref path_right, ref patterns, _))
|
||||||
|
if patterns.len() == 1 =>
|
||||||
|
{
|
||||||
|
if let PatKind::Wild = patterns[0].kind {
|
||||||
|
find_good_method_for_match(
|
||||||
|
arms,
|
||||||
|
path_left,
|
||||||
|
path_right,
|
||||||
|
&paths::OPTION_SOME,
|
||||||
|
&paths::OPTION_NONE,
|
||||||
|
"is_some()",
|
||||||
|
"is_none()",
|
||||||
|
|| can_suggest(cx, hir_id, sym!(option_type), "is_some"),
|
||||||
|
|| can_suggest(cx, hir_id, sym!(option_type), "is_none"),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(good_method) = found_good_method {
|
||||||
|
span_lint_and_then(
|
||||||
|
cx,
|
||||||
|
REDUNDANT_PATTERN_MATCHING,
|
||||||
|
expr.span,
|
||||||
|
&format!("redundant pattern matching, consider using `{}`", good_method),
|
||||||
|
|diag| {
|
||||||
|
let span = expr.span.to(op.span);
|
||||||
|
diag.span_suggestion(
|
||||||
|
span,
|
||||||
|
"try this",
|
||||||
|
format!("{}.{}", snippet(cx, op.span, "_"), good_method),
|
||||||
|
Applicability::MaybeIncorrect, // snippet
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
|
fn find_good_method_for_match<'a>(
|
||||||
|
arms: &[Arm<'_>],
|
||||||
|
path_left: &QPath<'_>,
|
||||||
|
path_right: &QPath<'_>,
|
||||||
|
expected_left: &[&str],
|
||||||
|
expected_right: &[&str],
|
||||||
|
should_be_left: &'a str,
|
||||||
|
should_be_right: &'a str,
|
||||||
|
can_suggest_left: impl Fn() -> bool,
|
||||||
|
can_suggest_right: impl Fn() -> bool,
|
||||||
|
) -> Option<&'a str> {
|
||||||
|
let body_node_pair = if match_qpath(path_left, expected_left) && match_qpath(path_right, expected_right) {
|
||||||
|
(&(*arms[0].body).kind, &(*arms[1].body).kind)
|
||||||
|
} else if match_qpath(path_right, expected_left) && match_qpath(path_left, expected_right) {
|
||||||
|
(&(*arms[1].body).kind, &(*arms[0].body).kind)
|
||||||
|
} else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
|
||||||
|
match body_node_pair {
|
||||||
|
(ExprKind::Lit(ref lit_left), ExprKind::Lit(ref lit_right)) => match (&lit_left.node, &lit_right.node) {
|
||||||
|
(LitKind::Bool(true), LitKind::Bool(false)) if can_suggest_left() => Some(should_be_left),
|
||||||
|
(LitKind::Bool(false), LitKind::Bool(true)) if can_suggest_right() => Some(should_be_right),
|
||||||
|
_ => None,
|
||||||
|
},
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn can_suggest(cx: &LateContext<'_>, hir_id: HirId, diag_item: Symbol, name: &str) -> bool {
|
||||||
|
if !in_constant(cx, hir_id) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Avoid suggesting calls to non-`const fn`s in const contexts, see #5697.
|
||||||
|
cx.tcx
|
||||||
|
.get_diagnostic_item(diag_item)
|
||||||
|
.and_then(|def_id| {
|
||||||
|
cx.tcx.inherent_impls(def_id).iter().find_map(|imp| {
|
||||||
|
cx.tcx
|
||||||
|
.associated_items(*imp)
|
||||||
|
.in_definition_order()
|
||||||
|
.find_map(|item| match item.kind {
|
||||||
|
ty::AssocKind::Fn if item.ident.name.as_str() == name => Some(item.def_id),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.map_or(false, |def_id| is_const_fn(cx.tcx, def_id))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_overlapping() {
|
fn test_overlapping() {
|
||||||
use rustc_span::source_map::DUMMY_SP;
|
use rustc_span::source_map::DUMMY_SP;
|
||||||
|
@ -1844,10 +1844,10 @@ fn lint_expect_fun_call(
|
|||||||
ty::Ref(ty::ReStatic, ..)
|
ty::Ref(ty::ReStatic, ..)
|
||||||
)
|
)
|
||||||
}),
|
}),
|
||||||
hir::ExprKind::Path(ref p) => match cx.qpath_res(p, arg.hir_id) {
|
hir::ExprKind::Path(ref p) => matches!(
|
||||||
hir::def::Res::Def(hir::def::DefKind::Const | hir::def::DefKind::Static, _) => true,
|
cx.qpath_res(p, arg.hir_id),
|
||||||
_ => false,
|
hir::def::Res::Def(hir::def::DefKind::Const | hir::def::DefKind::Static, _)
|
||||||
},
|
),
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2028,13 +2028,7 @@ fn lint_clone_on_copy(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Exp
|
|||||||
.tables()
|
.tables()
|
||||||
.expr_adjustments(arg)
|
.expr_adjustments(arg)
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|adj| {
|
.filter(|adj| matches!(adj.kind, ty::adjustment::Adjust::Deref(_)))
|
||||||
if let ty::adjustment::Adjust::Deref(_) = adj.kind {
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.count();
|
.count();
|
||||||
let derefs: String = iter::repeat('*').take(deref_count).collect();
|
let derefs: String = iter::repeat('*').take(deref_count).collect();
|
||||||
snip = Some(("try dereferencing it", format!("{}{}", derefs, snippet)));
|
snip = Some(("try dereferencing it", format!("{}{}", derefs, snippet)));
|
||||||
|
@ -694,12 +694,7 @@ fn in_attributes_expansion(expr: &Expr<'_>) -> bool {
|
|||||||
use rustc_span::hygiene::MacroKind;
|
use rustc_span::hygiene::MacroKind;
|
||||||
if expr.span.from_expansion() {
|
if expr.span.from_expansion() {
|
||||||
let data = expr.span.ctxt().outer_expn_data();
|
let data = expr.span.ctxt().outer_expn_data();
|
||||||
|
matches!(data.kind, ExpnKind::Macro(MacroKind::Attr, _))
|
||||||
if let ExpnKind::Macro(MacroKind::Attr, _) = data.kind {
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
@ -641,28 +641,22 @@ fn check_unneeded_wildcard_pattern(cx: &EarlyContext<'_>, pat: &Pat) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::trivially_copy_pass_by_ref)]
|
|
||||||
fn is_wild<P: std::ops::Deref<Target = Pat>>(pat: &&P) -> bool {
|
|
||||||
if let PatKind::Wild = pat.kind {
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(rest_index) = patterns.iter().position(|pat| pat.is_rest()) {
|
if let Some(rest_index) = patterns.iter().position(|pat| pat.is_rest()) {
|
||||||
if let Some((left_index, left_pat)) = patterns[..rest_index]
|
if let Some((left_index, left_pat)) = patterns[..rest_index]
|
||||||
.iter()
|
.iter()
|
||||||
.rev()
|
.rev()
|
||||||
.take_while(is_wild)
|
.take_while(|pat| matches!(pat.kind, PatKind::Wild))
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.last()
|
.last()
|
||||||
{
|
{
|
||||||
span_lint(cx, left_pat.span.until(patterns[rest_index].span), left_index == 0);
|
span_lint(cx, left_pat.span.until(patterns[rest_index].span), left_index == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some((right_index, right_pat)) =
|
if let Some((right_index, right_pat)) = patterns[rest_index + 1..]
|
||||||
patterns[rest_index + 1..].iter().take_while(is_wild).enumerate().last()
|
.iter()
|
||||||
|
.take_while(|pat| matches!(pat.kind, PatKind::Wild))
|
||||||
|
.enumerate()
|
||||||
|
.last()
|
||||||
{
|
{
|
||||||
span_lint(
|
span_lint(
|
||||||
cx,
|
cx,
|
||||||
|
@ -71,10 +71,11 @@ fn check_missing_inline_attrs(cx: &LateContext<'_>, attrs: &[ast::Attribute], sp
|
|||||||
fn is_executable(cx: &LateContext<'_>) -> bool {
|
fn is_executable(cx: &LateContext<'_>) -> bool {
|
||||||
use rustc_session::config::CrateType;
|
use rustc_session::config::CrateType;
|
||||||
|
|
||||||
cx.tcx.sess.crate_types().iter().any(|t: &CrateType| match t {
|
cx.tcx
|
||||||
CrateType::Executable => true,
|
.sess
|
||||||
_ => false,
|
.crate_types()
|
||||||
})
|
.iter()
|
||||||
|
.any(|t: &CrateType| matches!(t, CrateType::Executable))
|
||||||
}
|
}
|
||||||
|
|
||||||
declare_lint_pass!(MissingInline => [MISSING_INLINE_IN_PUBLIC_ITEMS]);
|
declare_lint_pass!(MissingInline => [MISSING_INLINE_IN_PUBLIC_ITEMS]);
|
||||||
|
@ -80,10 +80,12 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault {
|
|||||||
// can't be implemented for unsafe new
|
// can't be implemented for unsafe new
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if impl_item.generics.params.iter().any(|gen| match gen.kind {
|
if impl_item
|
||||||
hir::GenericParamKind::Type { .. } => true,
|
.generics
|
||||||
_ => false,
|
.params
|
||||||
}) {
|
.iter()
|
||||||
|
.any(|gen| matches!(gen.kind, hir::GenericParamKind::Type { .. }))
|
||||||
|
{
|
||||||
// when the result of `new()` depends on a type parameter we should not require
|
// when the result of `new()` depends on a type parameter we should not require
|
||||||
// an
|
// an
|
||||||
// impl of `Default`
|
// impl of `Default`
|
||||||
|
@ -238,10 +238,10 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst {
|
|||||||
|
|
||||||
let ty = if needs_check_adjustment {
|
let ty = if needs_check_adjustment {
|
||||||
let adjustments = cx.tables().expr_adjustments(dereferenced_expr);
|
let adjustments = cx.tables().expr_adjustments(dereferenced_expr);
|
||||||
if let Some(i) = adjustments.iter().position(|adj| match adj.kind {
|
if let Some(i) = adjustments
|
||||||
Adjust::Borrow(_) | Adjust::Deref(_) => true,
|
.iter()
|
||||||
_ => false,
|
.position(|adj| matches!(adj.kind, Adjust::Borrow(_) | Adjust::Deref(_)))
|
||||||
}) {
|
{
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
cx.tables().expr_ty(dereferenced_expr)
|
cx.tables().expr_ty(dereferenced_expr)
|
||||||
} else {
|
} else {
|
||||||
|
@ -148,17 +148,11 @@ fn is_arith_expr(expr: &Expr) -> bool {
|
|||||||
#[must_use]
|
#[must_use]
|
||||||
fn is_bit_op(op: BinOpKind) -> bool {
|
fn is_bit_op(op: BinOpKind) -> bool {
|
||||||
use rustc_ast::ast::BinOpKind::{BitAnd, BitOr, BitXor, Shl, Shr};
|
use rustc_ast::ast::BinOpKind::{BitAnd, BitOr, BitXor, Shl, Shr};
|
||||||
match op {
|
matches!(op, BitXor | BitAnd | BitOr | Shl | Shr)
|
||||||
BitXor | BitAnd | BitOr | Shl | Shr => true,
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
fn is_arith_op(op: BinOpKind) -> bool {
|
fn is_arith_op(op: BinOpKind) -> bool {
|
||||||
use rustc_ast::ast::BinOpKind::{Add, Div, Mul, Rem, Sub};
|
use rustc_ast::ast::BinOpKind::{Add, Div, Mul, Rem, Sub};
|
||||||
match op {
|
matches!(op, Add | Sub | Mul | Div | Rem)
|
||||||
Add | Sub | Mul | Div | Rem => true,
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,260 +0,0 @@
|
|||||||
use crate::utils::{in_constant, match_qpath, match_trait_method, paths, snippet, span_lint_and_then};
|
|
||||||
use if_chain::if_chain;
|
|
||||||
use rustc_ast::ast::LitKind;
|
|
||||||
use rustc_errors::Applicability;
|
|
||||||
use rustc_hir::{Arm, Expr, ExprKind, HirId, MatchSource, PatKind, QPath};
|
|
||||||
use rustc_lint::{LateContext, LateLintPass};
|
|
||||||
use rustc_middle::ty;
|
|
||||||
use rustc_mir::const_eval::is_const_fn;
|
|
||||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
|
||||||
use rustc_span::source_map::Symbol;
|
|
||||||
|
|
||||||
declare_clippy_lint! {
|
|
||||||
/// **What it does:** Lint for redundant pattern matching over `Result` or
|
|
||||||
/// `Option`
|
|
||||||
///
|
|
||||||
/// **Why is this bad?** It's more concise and clear to just use the proper
|
|
||||||
/// utility function
|
|
||||||
///
|
|
||||||
/// **Known problems:** None.
|
|
||||||
///
|
|
||||||
/// **Example:**
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// if let Ok(_) = Ok::<i32, i32>(42) {}
|
|
||||||
/// if let Err(_) = Err::<i32, i32>(42) {}
|
|
||||||
/// if let None = None::<()> {}
|
|
||||||
/// if let Some(_) = Some(42) {}
|
|
||||||
/// match Ok::<i32, i32>(42) {
|
|
||||||
/// Ok(_) => true,
|
|
||||||
/// Err(_) => false,
|
|
||||||
/// };
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// The more idiomatic use would be:
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// if Ok::<i32, i32>(42).is_ok() {}
|
|
||||||
/// if Err::<i32, i32>(42).is_err() {}
|
|
||||||
/// if None::<()>.is_none() {}
|
|
||||||
/// if Some(42).is_some() {}
|
|
||||||
/// Ok::<i32, i32>(42).is_ok();
|
|
||||||
/// ```
|
|
||||||
pub REDUNDANT_PATTERN_MATCHING,
|
|
||||||
style,
|
|
||||||
"use the proper utility function avoiding an `if let`"
|
|
||||||
}
|
|
||||||
|
|
||||||
declare_lint_pass!(RedundantPatternMatching => [REDUNDANT_PATTERN_MATCHING]);
|
|
||||||
|
|
||||||
impl<'tcx> LateLintPass<'tcx> for RedundantPatternMatching {
|
|
||||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
|
||||||
if let ExprKind::Match(op, arms, ref match_source) = &expr.kind {
|
|
||||||
match match_source {
|
|
||||||
MatchSource::Normal => find_sugg_for_match(cx, expr, op, arms),
|
|
||||||
MatchSource::IfLetDesugar { .. } => find_sugg_for_if_let(cx, expr, op, arms, "if"),
|
|
||||||
MatchSource::WhileLetDesugar => find_sugg_for_if_let(cx, expr, op, arms, "while"),
|
|
||||||
_ => return,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn find_sugg_for_if_let<'tcx>(
|
|
||||||
cx: &LateContext<'tcx>,
|
|
||||||
expr: &'tcx Expr<'_>,
|
|
||||||
op: &Expr<'_>,
|
|
||||||
arms: &[Arm<'_>],
|
|
||||||
keyword: &'static str,
|
|
||||||
) {
|
|
||||||
fn find_suggestion(cx: &LateContext<'_>, hir_id: HirId, path: &QPath<'_>) -> Option<&'static str> {
|
|
||||||
if match_qpath(path, &paths::RESULT_OK) && can_suggest(cx, hir_id, sym!(result_type), "is_ok") {
|
|
||||||
return Some("is_ok()");
|
|
||||||
}
|
|
||||||
if match_qpath(path, &paths::RESULT_ERR) && can_suggest(cx, hir_id, sym!(result_type), "is_err") {
|
|
||||||
return Some("is_err()");
|
|
||||||
}
|
|
||||||
if match_qpath(path, &paths::OPTION_SOME) && can_suggest(cx, hir_id, sym!(option_type), "is_some") {
|
|
||||||
return Some("is_some()");
|
|
||||||
}
|
|
||||||
if match_qpath(path, &paths::OPTION_NONE) && can_suggest(cx, hir_id, sym!(option_type), "is_none") {
|
|
||||||
return Some("is_none()");
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
let hir_id = expr.hir_id;
|
|
||||||
let good_method = match arms[0].pat.kind {
|
|
||||||
PatKind::TupleStruct(ref path, ref patterns, _) if patterns.len() == 1 => {
|
|
||||||
if let PatKind::Wild = patterns[0].kind {
|
|
||||||
find_suggestion(cx, hir_id, path)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
},
|
|
||||||
PatKind::Path(ref path) => find_suggestion(cx, hir_id, path),
|
|
||||||
_ => None,
|
|
||||||
};
|
|
||||||
let good_method = match good_method {
|
|
||||||
Some(method) => method,
|
|
||||||
None => return,
|
|
||||||
};
|
|
||||||
|
|
||||||
// check that `while_let_on_iterator` lint does not trigger
|
|
||||||
if_chain! {
|
|
||||||
if keyword == "while";
|
|
||||||
if let ExprKind::MethodCall(method_path, _, _, _) = op.kind;
|
|
||||||
if method_path.ident.name == sym!(next);
|
|
||||||
if match_trait_method(cx, op, &paths::ITERATOR);
|
|
||||||
then {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
span_lint_and_then(
|
|
||||||
cx,
|
|
||||||
REDUNDANT_PATTERN_MATCHING,
|
|
||||||
arms[0].pat.span,
|
|
||||||
&format!("redundant pattern matching, consider using `{}`", good_method),
|
|
||||||
|diag| {
|
|
||||||
// while let ... = ... { ... }
|
|
||||||
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
let expr_span = expr.span;
|
|
||||||
|
|
||||||
// while let ... = ... { ... }
|
|
||||||
// ^^^
|
|
||||||
let op_span = op.span.source_callsite();
|
|
||||||
|
|
||||||
// while let ... = ... { ... }
|
|
||||||
// ^^^^^^^^^^^^^^^^^^^
|
|
||||||
let span = expr_span.until(op_span.shrink_to_hi());
|
|
||||||
diag.span_suggestion(
|
|
||||||
span,
|
|
||||||
"try this",
|
|
||||||
format!("{} {}.{}", keyword, snippet(cx, op_span, "_"), good_method),
|
|
||||||
Applicability::MachineApplicable, // snippet
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn find_sugg_for_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op: &Expr<'_>, arms: &[Arm<'_>]) {
|
|
||||||
if arms.len() == 2 {
|
|
||||||
let node_pair = (&arms[0].pat.kind, &arms[1].pat.kind);
|
|
||||||
|
|
||||||
let hir_id = expr.hir_id;
|
|
||||||
let found_good_method = match node_pair {
|
|
||||||
(
|
|
||||||
PatKind::TupleStruct(ref path_left, ref patterns_left, _),
|
|
||||||
PatKind::TupleStruct(ref path_right, ref patterns_right, _),
|
|
||||||
) if patterns_left.len() == 1 && patterns_right.len() == 1 => {
|
|
||||||
if let (PatKind::Wild, PatKind::Wild) = (&patterns_left[0].kind, &patterns_right[0].kind) {
|
|
||||||
find_good_method_for_match(
|
|
||||||
arms,
|
|
||||||
path_left,
|
|
||||||
path_right,
|
|
||||||
&paths::RESULT_OK,
|
|
||||||
&paths::RESULT_ERR,
|
|
||||||
"is_ok()",
|
|
||||||
"is_err()",
|
|
||||||
|| can_suggest(cx, hir_id, sym!(result_type), "is_ok"),
|
|
||||||
|| can_suggest(cx, hir_id, sym!(result_type), "is_err"),
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
},
|
|
||||||
(PatKind::TupleStruct(ref path_left, ref patterns, _), PatKind::Path(ref path_right))
|
|
||||||
| (PatKind::Path(ref path_left), PatKind::TupleStruct(ref path_right, ref patterns, _))
|
|
||||||
if patterns.len() == 1 =>
|
|
||||||
{
|
|
||||||
if let PatKind::Wild = patterns[0].kind {
|
|
||||||
find_good_method_for_match(
|
|
||||||
arms,
|
|
||||||
path_left,
|
|
||||||
path_right,
|
|
||||||
&paths::OPTION_SOME,
|
|
||||||
&paths::OPTION_NONE,
|
|
||||||
"is_some()",
|
|
||||||
"is_none()",
|
|
||||||
|| can_suggest(cx, hir_id, sym!(option_type), "is_some"),
|
|
||||||
|| can_suggest(cx, hir_id, sym!(option_type), "is_none"),
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_ => None,
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(good_method) = found_good_method {
|
|
||||||
span_lint_and_then(
|
|
||||||
cx,
|
|
||||||
REDUNDANT_PATTERN_MATCHING,
|
|
||||||
expr.span,
|
|
||||||
&format!("redundant pattern matching, consider using `{}`", good_method),
|
|
||||||
|diag| {
|
|
||||||
let span = expr.span.to(op.span);
|
|
||||||
diag.span_suggestion(
|
|
||||||
span,
|
|
||||||
"try this",
|
|
||||||
format!("{}.{}", snippet(cx, op.span, "_"), good_method),
|
|
||||||
Applicability::MaybeIncorrect, // snippet
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(clippy::too_many_arguments)]
|
|
||||||
fn find_good_method_for_match<'a>(
|
|
||||||
arms: &[Arm<'_>],
|
|
||||||
path_left: &QPath<'_>,
|
|
||||||
path_right: &QPath<'_>,
|
|
||||||
expected_left: &[&str],
|
|
||||||
expected_right: &[&str],
|
|
||||||
should_be_left: &'a str,
|
|
||||||
should_be_right: &'a str,
|
|
||||||
can_suggest_left: impl Fn() -> bool,
|
|
||||||
can_suggest_right: impl Fn() -> bool,
|
|
||||||
) -> Option<&'a str> {
|
|
||||||
let body_node_pair = if match_qpath(path_left, expected_left) && match_qpath(path_right, expected_right) {
|
|
||||||
(&(*arms[0].body).kind, &(*arms[1].body).kind)
|
|
||||||
} else if match_qpath(path_right, expected_left) && match_qpath(path_left, expected_right) {
|
|
||||||
(&(*arms[1].body).kind, &(*arms[0].body).kind)
|
|
||||||
} else {
|
|
||||||
return None;
|
|
||||||
};
|
|
||||||
|
|
||||||
match body_node_pair {
|
|
||||||
(ExprKind::Lit(ref lit_left), ExprKind::Lit(ref lit_right)) => match (&lit_left.node, &lit_right.node) {
|
|
||||||
(LitKind::Bool(true), LitKind::Bool(false)) if can_suggest_left() => Some(should_be_left),
|
|
||||||
(LitKind::Bool(false), LitKind::Bool(true)) if can_suggest_right() => Some(should_be_right),
|
|
||||||
_ => None,
|
|
||||||
},
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn can_suggest(cx: &LateContext<'_>, hir_id: HirId, diag_item: Symbol, name: &str) -> bool {
|
|
||||||
if !in_constant(cx, hir_id) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Avoid suggesting calls to non-`const fn`s in const contexts, see #5697.
|
|
||||||
cx.tcx
|
|
||||||
.get_diagnostic_item(diag_item)
|
|
||||||
.and_then(|def_id| {
|
|
||||||
cx.tcx.inherent_impls(def_id).iter().find_map(|imp| {
|
|
||||||
cx.tcx
|
|
||||||
.associated_items(*imp)
|
|
||||||
.in_definition_order()
|
|
||||||
.find_map(|item| match item.kind {
|
|
||||||
ty::AssocKind::Fn if item.ident.name.as_str() == name => Some(item.def_id),
|
|
||||||
_ => None,
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.map_or(false, |def_id| is_const_fn(cx.tcx, def_id))
|
|
||||||
}
|
|
@ -99,12 +99,7 @@ fn is_trivial_regex(s: ®ex_syntax::hir::Hir) -> Option<&'static str> {
|
|||||||
use regex_syntax::hir::Anchor::{EndText, StartText};
|
use regex_syntax::hir::Anchor::{EndText, StartText};
|
||||||
use regex_syntax::hir::HirKind::{Alternation, Anchor, Concat, Empty, Literal};
|
use regex_syntax::hir::HirKind::{Alternation, Anchor, Concat, Empty, Literal};
|
||||||
|
|
||||||
let is_literal = |e: &[regex_syntax::hir::Hir]| {
|
let is_literal = |e: &[regex_syntax::hir::Hir]| e.iter().all(|e| matches!(*e.kind(), Literal(_)));
|
||||||
e.iter().all(|e| match *e.kind() {
|
|
||||||
Literal(_) => true,
|
|
||||||
_ => false,
|
|
||||||
})
|
|
||||||
};
|
|
||||||
|
|
||||||
match *s.kind() {
|
match *s.kind() {
|
||||||
Empty | Anchor(_) => Some("the regex is unlikely to be useful as it is"),
|
Empty | Anchor(_) => Some("the regex is unlikely to be useful as it is"),
|
||||||
|
@ -165,10 +165,7 @@ fn check_local<'tcx>(cx: &LateContext<'tcx>, local: &'tcx Local<'_>, bindings: &
|
|||||||
|
|
||||||
fn is_binding(cx: &LateContext<'_>, pat_id: HirId) -> bool {
|
fn is_binding(cx: &LateContext<'_>, pat_id: HirId) -> bool {
|
||||||
let var_ty = cx.tables().node_type_opt(pat_id);
|
let var_ty = cx.tables().node_type_opt(pat_id);
|
||||||
var_ty.map_or(false, |var_ty| match var_ty.kind {
|
var_ty.map_or(false, |var_ty| !matches!(var_ty.kind, ty::Adt(..)))
|
||||||
ty::Adt(..) => false,
|
|
||||||
_ => true,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_pat<'tcx>(
|
fn check_pat<'tcx>(
|
||||||
|
@ -25,13 +25,7 @@ declare_clippy_lint! {
|
|||||||
fn is_temporary(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
|
fn is_temporary(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
|
||||||
match &expr.kind {
|
match &expr.kind {
|
||||||
ExprKind::Struct(..) | ExprKind::Tup(..) => true,
|
ExprKind::Struct(..) | ExprKind::Tup(..) => true,
|
||||||
ExprKind::Path(qpath) => {
|
ExprKind::Path(qpath) => matches!(cx.qpath_res(qpath, expr.hir_id), Res::Def(DefKind::Const, ..)),
|
||||||
if let Res::Def(DefKind::Const, ..) = cx.qpath_res(qpath, expr.hir_id) {
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -775,11 +775,7 @@ impl<'tcx> LateLintPass<'tcx> for UnitArg {
|
|||||||
.iter()
|
.iter()
|
||||||
.filter(|arg| {
|
.filter(|arg| {
|
||||||
if is_unit(cx.tables().expr_ty(arg)) && !is_unit_literal(arg) {
|
if is_unit(cx.tables().expr_ty(arg)) && !is_unit_literal(arg) {
|
||||||
if let ExprKind::Match(.., MatchSource::TryDesugar) = &arg.kind {
|
!matches!(&arg.kind, ExprKind::Match(.., MatchSource::TryDesugar))
|
||||||
false
|
|
||||||
} else {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
@ -899,17 +895,11 @@ fn is_questionmark_desugar_marked_call(expr: &Expr<'_>) -> bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn is_unit(ty: Ty<'_>) -> bool {
|
fn is_unit(ty: Ty<'_>) -> bool {
|
||||||
match ty.kind {
|
matches!(ty.kind, ty::Tuple(slice) if slice.is_empty())
|
||||||
ty::Tuple(slice) if slice.is_empty() => true,
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_unit_literal(expr: &Expr<'_>) -> bool {
|
fn is_unit_literal(expr: &Expr<'_>) -> bool {
|
||||||
match expr.kind {
|
matches!(expr.kind, ExprKind::Tup(ref slice) if slice.is_empty())
|
||||||
ExprKind::Tup(ref slice) if slice.is_empty() => true,
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
declare_clippy_lint! {
|
declare_clippy_lint! {
|
||||||
@ -1154,10 +1144,7 @@ fn int_ty_to_nbits(typ: Ty<'_>, tcx: TyCtxt<'_>) -> u64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn is_isize_or_usize(typ: Ty<'_>) -> bool {
|
fn is_isize_or_usize(typ: Ty<'_>) -> bool {
|
||||||
match typ.kind {
|
matches!(typ.kind, ty::Int(IntTy::Isize) | ty::Uint(UintTy::Usize))
|
||||||
ty::Int(IntTy::Isize) | ty::Uint(UintTy::Usize) => true,
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn span_precision_loss_lint(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, cast_to_f64: bool) {
|
fn span_precision_loss_lint(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, cast_to_f64: bool) {
|
||||||
@ -1737,10 +1724,10 @@ impl<'tcx> Visitor<'tcx> for TypeComplexityVisitor {
|
|||||||
|
|
||||||
TyKind::TraitObject(ref param_bounds, _) => {
|
TyKind::TraitObject(ref param_bounds, _) => {
|
||||||
let has_lifetime_parameters = param_bounds.iter().any(|bound| {
|
let has_lifetime_parameters = param_bounds.iter().any(|bound| {
|
||||||
bound.bound_generic_params.iter().any(|gen| match gen.kind {
|
bound
|
||||||
GenericParamKind::Lifetime { .. } => true,
|
.bound_generic_params
|
||||||
_ => false,
|
.iter()
|
||||||
})
|
.any(|gen| matches!(gen.kind, GenericParamKind::Lifetime { .. }))
|
||||||
});
|
});
|
||||||
if has_lifetime_parameters {
|
if has_lifetime_parameters {
|
||||||
// complex trait bounds like A<'a, 'b>
|
// complex trait bounds like A<'a, 'b>
|
||||||
|
@ -58,10 +58,10 @@ declare_lint_pass!(UnnamedAddress => [FN_ADDRESS_COMPARISONS, VTABLE_ADDRESS_COM
|
|||||||
impl LateLintPass<'_> for UnnamedAddress {
|
impl LateLintPass<'_> for UnnamedAddress {
|
||||||
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
|
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
|
||||||
fn is_comparison(binop: BinOpKind) -> bool {
|
fn is_comparison(binop: BinOpKind) -> bool {
|
||||||
match binop {
|
matches!(
|
||||||
BinOpKind::Eq | BinOpKind::Lt | BinOpKind::Le | BinOpKind::Ne | BinOpKind::Ge | BinOpKind::Gt => true,
|
binop,
|
||||||
_ => false,
|
BinOpKind::Eq | BinOpKind::Lt | BinOpKind::Le | BinOpKind::Ne | BinOpKind::Ge | BinOpKind::Gt
|
||||||
}
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_trait_ptr(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
|
fn is_trait_ptr(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
|
||||||
@ -72,11 +72,7 @@ impl LateLintPass<'_> for UnnamedAddress {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn is_fn_def(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
|
fn is_fn_def(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
|
||||||
if let ty::FnDef(..) = cx.tables().expr_ty(expr).kind {
|
matches!(cx.tables().expr_ty(expr).kind, ty::FnDef(..))
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if_chain! {
|
if_chain! {
|
||||||
|
@ -169,10 +169,8 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
|
|||||||
let parameters = &item_path.segments.last().expect(SEGMENTS_MSG).args;
|
let parameters = &item_path.segments.last().expect(SEGMENTS_MSG).args;
|
||||||
let should_check = parameters.as_ref().map_or(
|
let should_check = parameters.as_ref().map_or(
|
||||||
true,
|
true,
|
||||||
|params| !params.parenthesized && !params.args.iter().any(|arg| match arg {
|
|params| !params.parenthesized
|
||||||
GenericArg::Lifetime(_) => true,
|
&&!params.args.iter().any(|arg| matches!(arg, GenericArg::Lifetime(_)))
|
||||||
_ => false,
|
|
||||||
})
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if should_check {
|
if should_check {
|
||||||
|
@ -387,10 +387,7 @@ pub fn eq_use_tree_kind(l: &UseTreeKind, r: &UseTreeKind) -> bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn eq_defaultness(l: Defaultness, r: Defaultness) -> bool {
|
pub fn eq_defaultness(l: Defaultness, r: Defaultness) -> bool {
|
||||||
match (l, r) {
|
matches!((l, r), (Defaultness::Final, Defaultness::Final) | (Defaultness::Default(_), Defaultness::Default(_)))
|
||||||
(Defaultness::Final, Defaultness::Final) | (Defaultness::Default(_), Defaultness::Default(_)) => true,
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn eq_vis(l: &Visibility, r: &Visibility) -> bool {
|
pub fn eq_vis(l: &Visibility, r: &Visibility) -> bool {
|
||||||
|
@ -102,11 +102,7 @@ pub fn in_constant(cx: &LateContext<'_>, id: HirId) -> bool {
|
|||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn in_macro(span: Span) -> bool {
|
pub fn in_macro(span: Span) -> bool {
|
||||||
if span.from_expansion() {
|
if span.from_expansion() {
|
||||||
if let ExpnKind::Desugaring(..) = span.ctxt().outer_expn_data().kind {
|
!matches!(span.ctxt().outer_expn_data().kind, ExpnKind::Desugaring(..))
|
||||||
false
|
|
||||||
} else {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
@ -127,10 +123,7 @@ pub fn is_present_in_source<T: LintContext>(cx: &T, span: Span) -> bool {
|
|||||||
|
|
||||||
/// Checks if given pattern is a wildcard (`_`)
|
/// Checks if given pattern is a wildcard (`_`)
|
||||||
pub fn is_wild<'tcx>(pat: &impl std::ops::Deref<Target = Pat<'tcx>>) -> bool {
|
pub fn is_wild<'tcx>(pat: &impl std::ops::Deref<Target = Pat<'tcx>>) -> bool {
|
||||||
match pat.kind {
|
matches!(pat.kind, PatKind::Wild)
|
||||||
PatKind::Wild => true,
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks if type is struct, enum or union type with the given def path.
|
/// Checks if type is struct, enum or union type with the given def path.
|
||||||
|
@ -51,7 +51,7 @@ impl<'a> NumericLiteral<'a> {
|
|||||||
pub fn from_lit_kind(src: &'a str, lit_kind: &LitKind) -> Option<NumericLiteral<'a>> {
|
pub fn from_lit_kind(src: &'a str, lit_kind: &LitKind) -> Option<NumericLiteral<'a>> {
|
||||||
if lit_kind.is_numeric() && src.chars().next().map_or(false, |c| c.is_digit(10)) {
|
if lit_kind.is_numeric() && src.chars().next().map_or(false, |c| c.is_digit(10)) {
|
||||||
let (unsuffixed, suffix) = split_suffix(&src, lit_kind);
|
let (unsuffixed, suffix) = split_suffix(&src, lit_kind);
|
||||||
let float = if let LitKind::Float(..) = lit_kind { true } else { false };
|
let float = matches!(lit_kind, LitKind::Float(..));
|
||||||
Some(NumericLiteral::new(unsuffixed, suffix, float))
|
Some(NumericLiteral::new(unsuffixed, suffix, float))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
@ -382,13 +382,8 @@ pub fn main() {
|
|||||||
|
|
||||||
let should_describe_lints = || {
|
let should_describe_lints = || {
|
||||||
let args: Vec<_> = env::args().collect();
|
let args: Vec<_> = env::args().collect();
|
||||||
args.windows(2).any(|args| {
|
args.windows(2)
|
||||||
args[1] == "help"
|
.any(|args| args[1] == "help" && matches!(args[0].as_str(), "-W" | "-A" | "-D" | "-F"))
|
||||||
&& match args[0].as_str() {
|
|
||||||
"-W" | "-A" | "-D" | "-F" => true,
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if !wrapper_mode && should_describe_lints() {
|
if !wrapper_mode && should_describe_lints() {
|
||||||
|
@ -1179,6 +1179,13 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![
|
|||||||
deprecation: None,
|
deprecation: None,
|
||||||
module: "matches",
|
module: "matches",
|
||||||
},
|
},
|
||||||
|
Lint {
|
||||||
|
name: "match_like_matches_macro",
|
||||||
|
group: "style",
|
||||||
|
desc: "a match that could be written with the matches! macro",
|
||||||
|
deprecation: None,
|
||||||
|
module: "matches",
|
||||||
|
},
|
||||||
Lint {
|
Lint {
|
||||||
name: "match_on_vec_items",
|
name: "match_on_vec_items",
|
||||||
group: "pedantic",
|
group: "pedantic",
|
||||||
@ -1856,7 +1863,7 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![
|
|||||||
group: "style",
|
group: "style",
|
||||||
desc: "use the proper utility function avoiding an `if let`",
|
desc: "use the proper utility function avoiding an `if let`",
|
||||||
deprecation: None,
|
deprecation: None,
|
||||||
module: "redundant_pattern_matching",
|
module: "matches",
|
||||||
},
|
},
|
||||||
Lint {
|
Lint {
|
||||||
name: "redundant_pub_crate",
|
name: "redundant_pub_crate",
|
||||||
|
@ -19,6 +19,7 @@ fn main() {
|
|||||||
|
|
||||||
let _: Option<i32> = a.iter().find(|s| s.parse::<i32>().is_ok()).map(|s| s.parse().unwrap());
|
let _: Option<i32> = a.iter().find(|s| s.parse::<i32>().is_ok()).map(|s| s.parse().unwrap());
|
||||||
|
|
||||||
|
#[allow(clippy::match_like_matches_macro)]
|
||||||
let _: Option<Flavor> = desserts_of_the_week
|
let _: Option<Flavor> = desserts_of_the_week
|
||||||
.iter()
|
.iter()
|
||||||
.find(|dessert| match *dessert {
|
.find(|dessert| match *dessert {
|
||||||
|
@ -8,7 +8,7 @@ LL | let _: Option<i32> = a.iter().find(|s| s.parse::<i32>().is_ok()).map(|s
|
|||||||
= help: this is more succinctly expressed by calling `.find_map(..)` instead
|
= help: this is more succinctly expressed by calling `.find_map(..)` instead
|
||||||
|
|
||||||
error: called `find(p).map(q)` on an `Iterator`
|
error: called `find(p).map(q)` on an `Iterator`
|
||||||
--> $DIR/find_map.rs:22:29
|
--> $DIR/find_map.rs:23:29
|
||||||
|
|
|
|
||||||
LL | let _: Option<Flavor> = desserts_of_the_week
|
LL | let _: Option<Flavor> = desserts_of_the_week
|
||||||
| _____________________________^
|
| _____________________________^
|
||||||
|
36
tests/ui/match_expr_like_matches_macro.fixed
Normal file
36
tests/ui/match_expr_like_matches_macro.fixed
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
// run-rustfix
|
||||||
|
|
||||||
|
#![warn(clippy::match_like_matches_macro)]
|
||||||
|
#![allow(unreachable_patterns)]
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let x = Some(5);
|
||||||
|
|
||||||
|
// Lint
|
||||||
|
let _y = matches!(x, Some(0));
|
||||||
|
|
||||||
|
// Lint
|
||||||
|
let _w = matches!(x, Some(_));
|
||||||
|
|
||||||
|
// Turn into is_none
|
||||||
|
let _z = x.is_none();
|
||||||
|
|
||||||
|
// Lint
|
||||||
|
let _zz = !matches!(x, Some(r) if r == 0);
|
||||||
|
|
||||||
|
// Lint
|
||||||
|
let _zzz = matches!(x, Some(5));
|
||||||
|
|
||||||
|
// No lint
|
||||||
|
let _a = match x {
|
||||||
|
Some(_) => false,
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
|
|
||||||
|
// No lint
|
||||||
|
let _ab = match x {
|
||||||
|
Some(0) => false,
|
||||||
|
_ => true,
|
||||||
|
None => false,
|
||||||
|
};
|
||||||
|
}
|
48
tests/ui/match_expr_like_matches_macro.rs
Normal file
48
tests/ui/match_expr_like_matches_macro.rs
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
// run-rustfix
|
||||||
|
|
||||||
|
#![warn(clippy::match_like_matches_macro)]
|
||||||
|
#![allow(unreachable_patterns)]
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let x = Some(5);
|
||||||
|
|
||||||
|
// Lint
|
||||||
|
let _y = match x {
|
||||||
|
Some(0) => true,
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Lint
|
||||||
|
let _w = match x {
|
||||||
|
Some(_) => true,
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Turn into is_none
|
||||||
|
let _z = match x {
|
||||||
|
Some(_) => false,
|
||||||
|
None => true,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Lint
|
||||||
|
let _zz = match x {
|
||||||
|
Some(r) if r == 0 => false,
|
||||||
|
_ => true,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Lint
|
||||||
|
let _zzz = if let Some(5) = x { true } else { false };
|
||||||
|
|
||||||
|
// No lint
|
||||||
|
let _a = match x {
|
||||||
|
Some(_) => false,
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
|
|
||||||
|
// No lint
|
||||||
|
let _ab = match x {
|
||||||
|
Some(0) => false,
|
||||||
|
_ => true,
|
||||||
|
None => false,
|
||||||
|
};
|
||||||
|
}
|
52
tests/ui/match_expr_like_matches_macro.stderr
Normal file
52
tests/ui/match_expr_like_matches_macro.stderr
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
error: match expression looks like `matches!` macro
|
||||||
|
--> $DIR/match_expr_like_matches_macro.rs:10:14
|
||||||
|
|
|
||||||
|
LL | let _y = match x {
|
||||||
|
| ______________^
|
||||||
|
LL | | Some(0) => true,
|
||||||
|
LL | | _ => false,
|
||||||
|
LL | | };
|
||||||
|
| |_____^ help: try this: `matches!(x, Some(0))`
|
||||||
|
|
|
||||||
|
= note: `-D clippy::match-like-matches-macro` implied by `-D warnings`
|
||||||
|
|
||||||
|
error: match expression looks like `matches!` macro
|
||||||
|
--> $DIR/match_expr_like_matches_macro.rs:16:14
|
||||||
|
|
|
||||||
|
LL | let _w = match x {
|
||||||
|
| ______________^
|
||||||
|
LL | | Some(_) => true,
|
||||||
|
LL | | _ => false,
|
||||||
|
LL | | };
|
||||||
|
| |_____^ help: try this: `matches!(x, Some(_))`
|
||||||
|
|
||||||
|
error: redundant pattern matching, consider using `is_none()`
|
||||||
|
--> $DIR/match_expr_like_matches_macro.rs:22:14
|
||||||
|
|
|
||||||
|
LL | let _z = match x {
|
||||||
|
| ______________^
|
||||||
|
LL | | Some(_) => false,
|
||||||
|
LL | | None => true,
|
||||||
|
LL | | };
|
||||||
|
| |_____^ help: try this: `x.is_none()`
|
||||||
|
|
|
||||||
|
= note: `-D clippy::redundant-pattern-matching` implied by `-D warnings`
|
||||||
|
|
||||||
|
error: match expression looks like `matches!` macro
|
||||||
|
--> $DIR/match_expr_like_matches_macro.rs:28:15
|
||||||
|
|
|
||||||
|
LL | let _zz = match x {
|
||||||
|
| _______________^
|
||||||
|
LL | | Some(r) if r == 0 => false,
|
||||||
|
LL | | _ => true,
|
||||||
|
LL | | };
|
||||||
|
| |_____^ help: try this: `!matches!(x, Some(r) if r == 0)`
|
||||||
|
|
||||||
|
error: if let .. else expression looks like `matches!` macro
|
||||||
|
--> $DIR/match_expr_like_matches_macro.rs:34:16
|
||||||
|
|
|
||||||
|
LL | let _zzz = if let Some(5) = x { true } else { false };
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `matches!(x, Some(5))`
|
||||||
|
|
||||||
|
error: aborting due to 5 previous errors
|
||||||
|
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
|
|
||||||
#[allow(clippy::unnested_or_patterns)]
|
#[allow(clippy::unnested_or_patterns, clippy::match_like_matches_macro)]
|
||||||
#[warn(clippy::neg_cmp_op_on_partial_ord)]
|
#[warn(clippy::neg_cmp_op_on_partial_ord)]
|
||||||
fn main() {
|
fn main() {
|
||||||
let a_value = 1.0;
|
let a_value = 1.0;
|
||||||
|
@ -2,7 +2,13 @@
|
|||||||
|
|
||||||
#![warn(clippy::all)]
|
#![warn(clippy::all)]
|
||||||
#![warn(clippy::redundant_pattern_matching)]
|
#![warn(clippy::redundant_pattern_matching)]
|
||||||
#![allow(clippy::unit_arg, unused_must_use, clippy::needless_bool, deprecated)]
|
#![allow(
|
||||||
|
clippy::unit_arg,
|
||||||
|
unused_must_use,
|
||||||
|
clippy::needless_bool,
|
||||||
|
clippy::match_like_matches_macro,
|
||||||
|
deprecated
|
||||||
|
)]
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
if Ok::<i32, i32>(42).is_ok() {}
|
if Ok::<i32, i32>(42).is_ok() {}
|
||||||
|
@ -2,7 +2,13 @@
|
|||||||
|
|
||||||
#![warn(clippy::all)]
|
#![warn(clippy::all)]
|
||||||
#![warn(clippy::redundant_pattern_matching)]
|
#![warn(clippy::redundant_pattern_matching)]
|
||||||
#![allow(clippy::unit_arg, unused_must_use, clippy::needless_bool, deprecated)]
|
#![allow(
|
||||||
|
clippy::unit_arg,
|
||||||
|
unused_must_use,
|
||||||
|
clippy::needless_bool,
|
||||||
|
clippy::match_like_matches_macro,
|
||||||
|
deprecated
|
||||||
|
)]
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
if let Ok(_) = Ok::<i32, i32>(42) {}
|
if let Ok(_) = Ok::<i32, i32>(42) {}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
error: redundant pattern matching, consider using `is_ok()`
|
error: redundant pattern matching, consider using `is_ok()`
|
||||||
--> $DIR/redundant_pattern_matching.rs:8:12
|
--> $DIR/redundant_pattern_matching.rs:14:12
|
||||||
|
|
|
|
||||||
LL | if let Ok(_) = Ok::<i32, i32>(42) {}
|
LL | if let Ok(_) = Ok::<i32, i32>(42) {}
|
||||||
| -------^^^^^--------------------- help: try this: `if Ok::<i32, i32>(42).is_ok()`
|
| -------^^^^^--------------------- help: try this: `if Ok::<i32, i32>(42).is_ok()`
|
||||||
@ -7,67 +7,67 @@ LL | if let Ok(_) = Ok::<i32, i32>(42) {}
|
|||||||
= note: `-D clippy::redundant-pattern-matching` implied by `-D warnings`
|
= note: `-D clippy::redundant-pattern-matching` implied by `-D warnings`
|
||||||
|
|
||||||
error: redundant pattern matching, consider using `is_err()`
|
error: redundant pattern matching, consider using `is_err()`
|
||||||
--> $DIR/redundant_pattern_matching.rs:10:12
|
--> $DIR/redundant_pattern_matching.rs:16:12
|
||||||
|
|
|
|
||||||
LL | if let Err(_) = Err::<i32, i32>(42) {}
|
LL | if let Err(_) = Err::<i32, i32>(42) {}
|
||||||
| -------^^^^^^---------------------- help: try this: `if Err::<i32, i32>(42).is_err()`
|
| -------^^^^^^---------------------- help: try this: `if Err::<i32, i32>(42).is_err()`
|
||||||
|
|
||||||
error: redundant pattern matching, consider using `is_none()`
|
error: redundant pattern matching, consider using `is_none()`
|
||||||
--> $DIR/redundant_pattern_matching.rs:12:12
|
--> $DIR/redundant_pattern_matching.rs:18:12
|
||||||
|
|
|
|
||||||
LL | if let None = None::<()> {}
|
LL | if let None = None::<()> {}
|
||||||
| -------^^^^------------- help: try this: `if None::<()>.is_none()`
|
| -------^^^^------------- help: try this: `if None::<()>.is_none()`
|
||||||
|
|
||||||
error: redundant pattern matching, consider using `is_some()`
|
error: redundant pattern matching, consider using `is_some()`
|
||||||
--> $DIR/redundant_pattern_matching.rs:14:12
|
--> $DIR/redundant_pattern_matching.rs:20:12
|
||||||
|
|
|
|
||||||
LL | if let Some(_) = Some(42) {}
|
LL | if let Some(_) = Some(42) {}
|
||||||
| -------^^^^^^^----------- help: try this: `if Some(42).is_some()`
|
| -------^^^^^^^----------- help: try this: `if Some(42).is_some()`
|
||||||
|
|
||||||
error: redundant pattern matching, consider using `is_some()`
|
error: redundant pattern matching, consider using `is_some()`
|
||||||
--> $DIR/redundant_pattern_matching.rs:16:12
|
--> $DIR/redundant_pattern_matching.rs:22:12
|
||||||
|
|
|
|
||||||
LL | if let Some(_) = Some(42) {
|
LL | if let Some(_) = Some(42) {
|
||||||
| -------^^^^^^^----------- help: try this: `if Some(42).is_some()`
|
| -------^^^^^^^----------- help: try this: `if Some(42).is_some()`
|
||||||
|
|
||||||
error: redundant pattern matching, consider using `is_some()`
|
error: redundant pattern matching, consider using `is_some()`
|
||||||
--> $DIR/redundant_pattern_matching.rs:22:15
|
--> $DIR/redundant_pattern_matching.rs:28:15
|
||||||
|
|
|
|
||||||
LL | while let Some(_) = Some(42) {}
|
LL | while let Some(_) = Some(42) {}
|
||||||
| ----------^^^^^^^----------- help: try this: `while Some(42).is_some()`
|
| ----------^^^^^^^----------- help: try this: `while Some(42).is_some()`
|
||||||
|
|
||||||
error: redundant pattern matching, consider using `is_none()`
|
error: redundant pattern matching, consider using `is_none()`
|
||||||
--> $DIR/redundant_pattern_matching.rs:24:15
|
--> $DIR/redundant_pattern_matching.rs:30:15
|
||||||
|
|
|
|
||||||
LL | while let None = Some(42) {}
|
LL | while let None = Some(42) {}
|
||||||
| ----------^^^^----------- help: try this: `while Some(42).is_none()`
|
| ----------^^^^----------- help: try this: `while Some(42).is_none()`
|
||||||
|
|
||||||
error: redundant pattern matching, consider using `is_none()`
|
error: redundant pattern matching, consider using `is_none()`
|
||||||
--> $DIR/redundant_pattern_matching.rs:26:15
|
--> $DIR/redundant_pattern_matching.rs:32:15
|
||||||
|
|
|
|
||||||
LL | while let None = None::<()> {}
|
LL | while let None = None::<()> {}
|
||||||
| ----------^^^^------------- help: try this: `while None::<()>.is_none()`
|
| ----------^^^^------------- help: try this: `while None::<()>.is_none()`
|
||||||
|
|
||||||
error: redundant pattern matching, consider using `is_ok()`
|
error: redundant pattern matching, consider using `is_ok()`
|
||||||
--> $DIR/redundant_pattern_matching.rs:28:15
|
--> $DIR/redundant_pattern_matching.rs:34:15
|
||||||
|
|
|
|
||||||
LL | while let Ok(_) = Ok::<i32, i32>(10) {}
|
LL | while let Ok(_) = Ok::<i32, i32>(10) {}
|
||||||
| ----------^^^^^--------------------- help: try this: `while Ok::<i32, i32>(10).is_ok()`
|
| ----------^^^^^--------------------- help: try this: `while Ok::<i32, i32>(10).is_ok()`
|
||||||
|
|
||||||
error: redundant pattern matching, consider using `is_err()`
|
error: redundant pattern matching, consider using `is_err()`
|
||||||
--> $DIR/redundant_pattern_matching.rs:30:15
|
--> $DIR/redundant_pattern_matching.rs:36:15
|
||||||
|
|
|
|
||||||
LL | while let Err(_) = Ok::<i32, i32>(10) {}
|
LL | while let Err(_) = Ok::<i32, i32>(10) {}
|
||||||
| ----------^^^^^^--------------------- help: try this: `while Ok::<i32, i32>(10).is_err()`
|
| ----------^^^^^^--------------------- help: try this: `while Ok::<i32, i32>(10).is_err()`
|
||||||
|
|
||||||
error: redundant pattern matching, consider using `is_some()`
|
error: redundant pattern matching, consider using `is_some()`
|
||||||
--> $DIR/redundant_pattern_matching.rs:33:15
|
--> $DIR/redundant_pattern_matching.rs:39:15
|
||||||
|
|
|
|
||||||
LL | while let Some(_) = v.pop() {
|
LL | while let Some(_) = v.pop() {
|
||||||
| ----------^^^^^^^---------- help: try this: `while v.pop().is_some()`
|
| ----------^^^^^^^---------- help: try this: `while v.pop().is_some()`
|
||||||
|
|
||||||
error: redundant pattern matching, consider using `is_ok()`
|
error: redundant pattern matching, consider using `is_ok()`
|
||||||
--> $DIR/redundant_pattern_matching.rs:49:5
|
--> $DIR/redundant_pattern_matching.rs:55:5
|
||||||
|
|
|
|
||||||
LL | / match Ok::<i32, i32>(42) {
|
LL | / match Ok::<i32, i32>(42) {
|
||||||
LL | | Ok(_) => true,
|
LL | | Ok(_) => true,
|
||||||
@ -76,7 +76,7 @@ LL | | };
|
|||||||
| |_____^ help: try this: `Ok::<i32, i32>(42).is_ok()`
|
| |_____^ help: try this: `Ok::<i32, i32>(42).is_ok()`
|
||||||
|
|
||||||
error: redundant pattern matching, consider using `is_err()`
|
error: redundant pattern matching, consider using `is_err()`
|
||||||
--> $DIR/redundant_pattern_matching.rs:54:5
|
--> $DIR/redundant_pattern_matching.rs:60:5
|
||||||
|
|
|
|
||||||
LL | / match Ok::<i32, i32>(42) {
|
LL | / match Ok::<i32, i32>(42) {
|
||||||
LL | | Ok(_) => false,
|
LL | | Ok(_) => false,
|
||||||
@ -85,7 +85,7 @@ LL | | };
|
|||||||
| |_____^ help: try this: `Ok::<i32, i32>(42).is_err()`
|
| |_____^ help: try this: `Ok::<i32, i32>(42).is_err()`
|
||||||
|
|
||||||
error: redundant pattern matching, consider using `is_err()`
|
error: redundant pattern matching, consider using `is_err()`
|
||||||
--> $DIR/redundant_pattern_matching.rs:59:5
|
--> $DIR/redundant_pattern_matching.rs:65:5
|
||||||
|
|
|
|
||||||
LL | / match Err::<i32, i32>(42) {
|
LL | / match Err::<i32, i32>(42) {
|
||||||
LL | | Ok(_) => false,
|
LL | | Ok(_) => false,
|
||||||
@ -94,7 +94,7 @@ LL | | };
|
|||||||
| |_____^ help: try this: `Err::<i32, i32>(42).is_err()`
|
| |_____^ help: try this: `Err::<i32, i32>(42).is_err()`
|
||||||
|
|
||||||
error: redundant pattern matching, consider using `is_ok()`
|
error: redundant pattern matching, consider using `is_ok()`
|
||||||
--> $DIR/redundant_pattern_matching.rs:64:5
|
--> $DIR/redundant_pattern_matching.rs:70:5
|
||||||
|
|
|
|
||||||
LL | / match Err::<i32, i32>(42) {
|
LL | / match Err::<i32, i32>(42) {
|
||||||
LL | | Ok(_) => true,
|
LL | | Ok(_) => true,
|
||||||
@ -103,7 +103,7 @@ LL | | };
|
|||||||
| |_____^ help: try this: `Err::<i32, i32>(42).is_ok()`
|
| |_____^ help: try this: `Err::<i32, i32>(42).is_ok()`
|
||||||
|
|
||||||
error: redundant pattern matching, consider using `is_some()`
|
error: redundant pattern matching, consider using `is_some()`
|
||||||
--> $DIR/redundant_pattern_matching.rs:69:5
|
--> $DIR/redundant_pattern_matching.rs:75:5
|
||||||
|
|
|
|
||||||
LL | / match Some(42) {
|
LL | / match Some(42) {
|
||||||
LL | | Some(_) => true,
|
LL | | Some(_) => true,
|
||||||
@ -112,7 +112,7 @@ LL | | };
|
|||||||
| |_____^ help: try this: `Some(42).is_some()`
|
| |_____^ help: try this: `Some(42).is_some()`
|
||||||
|
|
||||||
error: redundant pattern matching, consider using `is_none()`
|
error: redundant pattern matching, consider using `is_none()`
|
||||||
--> $DIR/redundant_pattern_matching.rs:74:5
|
--> $DIR/redundant_pattern_matching.rs:80:5
|
||||||
|
|
|
|
||||||
LL | / match None::<()> {
|
LL | / match None::<()> {
|
||||||
LL | | Some(_) => false,
|
LL | | Some(_) => false,
|
||||||
@ -121,7 +121,7 @@ LL | | };
|
|||||||
| |_____^ help: try this: `None::<()>.is_none()`
|
| |_____^ help: try this: `None::<()>.is_none()`
|
||||||
|
|
||||||
error: redundant pattern matching, consider using `is_none()`
|
error: redundant pattern matching, consider using `is_none()`
|
||||||
--> $DIR/redundant_pattern_matching.rs:79:13
|
--> $DIR/redundant_pattern_matching.rs:85:13
|
||||||
|
|
|
|
||||||
LL | let _ = match None::<()> {
|
LL | let _ = match None::<()> {
|
||||||
| _____________^
|
| _____________^
|
||||||
@ -131,61 +131,61 @@ LL | | };
|
|||||||
| |_____^ help: try this: `None::<()>.is_none()`
|
| |_____^ help: try this: `None::<()>.is_none()`
|
||||||
|
|
||||||
error: redundant pattern matching, consider using `is_ok()`
|
error: redundant pattern matching, consider using `is_ok()`
|
||||||
--> $DIR/redundant_pattern_matching.rs:84:20
|
--> $DIR/redundant_pattern_matching.rs:90:20
|
||||||
|
|
|
|
||||||
LL | let _ = if let Ok(_) = Ok::<usize, ()>(4) { true } else { false };
|
LL | let _ = if let Ok(_) = Ok::<usize, ()>(4) { true } else { false };
|
||||||
| -------^^^^^--------------------- help: try this: `if Ok::<usize, ()>(4).is_ok()`
|
| -------^^^^^--------------------- help: try this: `if Ok::<usize, ()>(4).is_ok()`
|
||||||
|
|
||||||
error: redundant pattern matching, consider using `is_some()`
|
error: redundant pattern matching, consider using `is_some()`
|
||||||
--> $DIR/redundant_pattern_matching.rs:87:20
|
--> $DIR/redundant_pattern_matching.rs:93:20
|
||||||
|
|
|
|
||||||
LL | let x = if let Some(_) = opt { true } else { false };
|
LL | let x = if let Some(_) = opt { true } else { false };
|
||||||
| -------^^^^^^^------ help: try this: `if opt.is_some()`
|
| -------^^^^^^^------ help: try this: `if opt.is_some()`
|
||||||
|
|
||||||
error: redundant pattern matching, consider using `is_some()`
|
error: redundant pattern matching, consider using `is_some()`
|
||||||
--> $DIR/redundant_pattern_matching.rs:93:20
|
--> $DIR/redundant_pattern_matching.rs:99:20
|
||||||
|
|
|
|
||||||
LL | let _ = if let Some(_) = gen_opt() {
|
LL | let _ = if let Some(_) = gen_opt() {
|
||||||
| -------^^^^^^^------------ help: try this: `if gen_opt().is_some()`
|
| -------^^^^^^^------------ help: try this: `if gen_opt().is_some()`
|
||||||
|
|
||||||
error: redundant pattern matching, consider using `is_none()`
|
error: redundant pattern matching, consider using `is_none()`
|
||||||
--> $DIR/redundant_pattern_matching.rs:95:19
|
--> $DIR/redundant_pattern_matching.rs:101:19
|
||||||
|
|
|
|
||||||
LL | } else if let None = gen_opt() {
|
LL | } else if let None = gen_opt() {
|
||||||
| -------^^^^------------ help: try this: `if gen_opt().is_none()`
|
| -------^^^^------------ help: try this: `if gen_opt().is_none()`
|
||||||
|
|
||||||
error: redundant pattern matching, consider using `is_ok()`
|
error: redundant pattern matching, consider using `is_ok()`
|
||||||
--> $DIR/redundant_pattern_matching.rs:97:19
|
--> $DIR/redundant_pattern_matching.rs:103:19
|
||||||
|
|
|
|
||||||
LL | } else if let Ok(_) = gen_res() {
|
LL | } else if let Ok(_) = gen_res() {
|
||||||
| -------^^^^^------------ help: try this: `if gen_res().is_ok()`
|
| -------^^^^^------------ help: try this: `if gen_res().is_ok()`
|
||||||
|
|
||||||
error: redundant pattern matching, consider using `is_err()`
|
error: redundant pattern matching, consider using `is_err()`
|
||||||
--> $DIR/redundant_pattern_matching.rs:99:19
|
--> $DIR/redundant_pattern_matching.rs:105:19
|
||||||
|
|
|
|
||||||
LL | } else if let Err(_) = gen_res() {
|
LL | } else if let Err(_) = gen_res() {
|
||||||
| -------^^^^^^------------ help: try this: `if gen_res().is_err()`
|
| -------^^^^^^------------ help: try this: `if gen_res().is_err()`
|
||||||
|
|
||||||
error: redundant pattern matching, consider using `is_some()`
|
error: redundant pattern matching, consider using `is_some()`
|
||||||
--> $DIR/redundant_pattern_matching.rs:132:19
|
--> $DIR/redundant_pattern_matching.rs:138:19
|
||||||
|
|
|
|
||||||
LL | while let Some(_) = r#try!(result_opt()) {}
|
LL | while let Some(_) = r#try!(result_opt()) {}
|
||||||
| ----------^^^^^^^----------------------- help: try this: `while r#try!(result_opt()).is_some()`
|
| ----------^^^^^^^----------------------- help: try this: `while r#try!(result_opt()).is_some()`
|
||||||
|
|
||||||
error: redundant pattern matching, consider using `is_some()`
|
error: redundant pattern matching, consider using `is_some()`
|
||||||
--> $DIR/redundant_pattern_matching.rs:133:16
|
--> $DIR/redundant_pattern_matching.rs:139:16
|
||||||
|
|
|
|
||||||
LL | if let Some(_) = r#try!(result_opt()) {}
|
LL | if let Some(_) = r#try!(result_opt()) {}
|
||||||
| -------^^^^^^^----------------------- help: try this: `if r#try!(result_opt()).is_some()`
|
| -------^^^^^^^----------------------- help: try this: `if r#try!(result_opt()).is_some()`
|
||||||
|
|
||||||
error: redundant pattern matching, consider using `is_some()`
|
error: redundant pattern matching, consider using `is_some()`
|
||||||
--> $DIR/redundant_pattern_matching.rs:139:12
|
--> $DIR/redundant_pattern_matching.rs:145:12
|
||||||
|
|
|
|
||||||
LL | if let Some(_) = m!() {}
|
LL | if let Some(_) = m!() {}
|
||||||
| -------^^^^^^^------- help: try this: `if m!().is_some()`
|
| -------^^^^^^^------- help: try this: `if m!().is_some()`
|
||||||
|
|
||||||
error: redundant pattern matching, consider using `is_some()`
|
error: redundant pattern matching, consider using `is_some()`
|
||||||
--> $DIR/redundant_pattern_matching.rs:140:15
|
--> $DIR/redundant_pattern_matching.rs:146:15
|
||||||
|
|
|
|
||||||
LL | while let Some(_) = m!() {}
|
LL | while let Some(_) = m!() {}
|
||||||
| ----------^^^^^^^------- help: try this: `while m!().is_some()`
|
| ----------^^^^^^^------- help: try this: `while m!().is_some()`
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
#![feature(const_result)]
|
#![feature(const_result)]
|
||||||
#![warn(clippy::redundant_pattern_matching)]
|
#![warn(clippy::redundant_pattern_matching)]
|
||||||
#![allow(unused)]
|
#![allow(clippy::match_like_matches_macro, unused)]
|
||||||
|
|
||||||
// Test that results are linted with the feature enabled.
|
// Test that results are linted with the feature enabled.
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
#![feature(const_result)]
|
#![feature(const_result)]
|
||||||
#![warn(clippy::redundant_pattern_matching)]
|
#![warn(clippy::redundant_pattern_matching)]
|
||||||
#![allow(unused)]
|
#![allow(clippy::match_like_matches_macro, unused)]
|
||||||
|
|
||||||
// Test that results are linted with the feature enabled.
|
// Test that results are linted with the feature enabled.
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user