Make the match checking configurable

This commit is contained in:
est31 2022-10-08 02:50:30 +02:00
parent 173a8e0480
commit 9bd70dbb88
4 changed files with 34 additions and 5 deletions

View File

@ -604,7 +604,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
)) ))
}); });
store.register_late_pass(move |_| Box::new(matches::Matches::new(msrv))); store.register_late_pass(move |_| Box::new(matches::Matches::new(msrv)));
store.register_late_pass(move |_| Box::new(manual_let_else::ManualLetElse::new(msrv))); let matches_for_let_else = conf.matches_for_let_else;
store.register_late_pass(move |_| Box::new(manual_let_else::ManualLetElse::new(msrv, matches_for_let_else)));
store.register_early_pass(move || Box::new(manual_non_exhaustive::ManualNonExhaustiveStruct::new(msrv))); store.register_early_pass(move || Box::new(manual_non_exhaustive::ManualNonExhaustiveStruct::new(msrv)));
store.register_late_pass(move |_| Box::new(manual_non_exhaustive::ManualNonExhaustiveEnum::new(msrv))); store.register_late_pass(move |_| Box::new(manual_non_exhaustive::ManualNonExhaustiveEnum::new(msrv)));
store.register_late_pass(move |_| Box::new(manual_strip::ManualStrip::new(msrv))); store.register_late_pass(move |_| Box::new(manual_strip::ManualStrip::new(msrv)));

View File

@ -11,6 +11,7 @@
use rustc_semver::RustcVersion; use rustc_semver::RustcVersion;
use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::symbol::sym; use rustc_span::symbol::sym;
use serde::Deserialize;
use std::ops::ControlFlow; use std::ops::ControlFlow;
declare_clippy_lint! { declare_clippy_lint! {
@ -47,12 +48,16 @@
pub struct ManualLetElse { pub struct ManualLetElse {
msrv: Option<RustcVersion>, msrv: Option<RustcVersion>,
matches_behaviour: MatchLintBehaviour,
} }
impl ManualLetElse { impl ManualLetElse {
#[must_use] #[must_use]
pub fn new(msrv: Option<RustcVersion>) -> Self { pub fn new(msrv: Option<RustcVersion>, matches_behaviour: MatchLintBehaviour) -> Self {
Self { msrv } Self {
msrv,
matches_behaviour,
}
} }
} }
@ -89,6 +94,9 @@ fn check_stmt(&mut self, cx: &LateContext<'_>, stmt: &'tcx Stmt<'tcx>) {
} }
}, },
IfLetOrMatch::Match(_match_expr, arms, source) => { IfLetOrMatch::Match(_match_expr, arms, source) => {
if self.matches_behaviour == MatchLintBehaviour::Never {
return;
}
if source != MatchSource::Normal { if source != MatchSource::Normal {
return; return;
} }
@ -97,6 +105,7 @@ fn check_stmt(&mut self, cx: &LateContext<'_>, stmt: &'tcx Stmt<'tcx>) {
if arms.len() != 2 { if arms.len() != 2 {
return; return;
} }
let check_types = self.matches_behaviour == MatchLintBehaviour::WellKnownTypes;
// We iterate over both arms, trying to find one that is an identity, // We iterate over both arms, trying to find one that is an identity,
// one that diverges. Our check needs to work regardless of the order // one that diverges. Our check needs to work regardless of the order
// of both arms. // of both arms.
@ -109,7 +118,7 @@ fn check_stmt(&mut self, cx: &LateContext<'_>, stmt: &'tcx Stmt<'tcx>) {
} }
if expr_is_simple_identity(arm.pat, arm.body) { if expr_is_simple_identity(arm.pat, arm.body) {
found_identity_arm = true; found_identity_arm = true;
} else if expr_diverges(cx, arm.body) && pat_allowed_for_else(cx, arm.pat) { } else if expr_diverges(cx, arm.body) && pat_allowed_for_else(cx, arm.pat, check_types) {
found_diverging_arm = true; found_diverging_arm = true;
} }
} }
@ -178,7 +187,7 @@ fn is_never(cx: &LateContext<'_>, expr: &'_ Expr<'_>) -> bool {
.is_some() .is_some()
} }
fn pat_allowed_for_else(cx: &LateContext<'_>, pat: &'_ Pat<'_>) -> bool { fn pat_allowed_for_else(cx: &LateContext<'_>, pat: &'_ Pat<'_>, check_types: bool) -> bool {
// Check whether the pattern contains any bindings, as the // Check whether the pattern contains any bindings, as the
// binding might potentially be used in the body. // binding might potentially be used in the body.
// TODO: only look for *used* bindings. // TODO: only look for *used* bindings.
@ -188,6 +197,11 @@ fn pat_allowed_for_else(cx: &LateContext<'_>, pat: &'_ Pat<'_>) -> bool {
return false; return false;
} }
// If we shouldn't check the types, exit early.
if !check_types {
return true;
}
// Check whether any possibly "unknown" patterns are included, // Check whether any possibly "unknown" patterns are included,
// because users might not know which values some enum has. // because users might not know which values some enum has.
// Well-known enums are excepted, as we assume people know them. // Well-known enums are excepted, as we assume people know them.
@ -245,3 +259,10 @@ fn expr_is_simple_identity(pat: &'_ Pat<'_>, expr: &'_ Expr<'_>) -> bool {
} }
true true
} }
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Deserialize)]
pub enum MatchLintBehaviour {
AllTypes,
WellKnownTypes,
Never,
}

View File

@ -335,6 +335,12 @@ pub(crate) fn get_configuration_metadata() -> Vec<ClippyConfiguration> {
/// ///
/// Enables verbose mode. Triggers if there is more than one uppercase char next to each other /// Enables verbose mode. Triggers if there is more than one uppercase char next to each other
(upper_case_acronyms_aggressive: bool = false), (upper_case_acronyms_aggressive: bool = false),
/// Lint: MANUAL_LET_ELSE.
///
/// Whether the matches should be considered by the lint, and whether there should
/// be filtering for common types.
(matches_for_let_else: crate::manual_let_else::MatchLintBehaviour =
crate::manual_let_else::MatchLintBehaviour::WellKnownTypes),
/// Lint: _CARGO_COMMON_METADATA. /// Lint: _CARGO_COMMON_METADATA.
/// ///
/// For internal testing only, ignores the current `publish` settings in the Cargo manifest. /// For internal testing only, ignores the current `publish` settings in the Cargo manifest.

View File

@ -22,6 +22,7 @@ error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown fie
enum-variant-size-threshold enum-variant-size-threshold
large-error-threshold large-error-threshold
literal-representation-threshold literal-representation-threshold
matches-for-let-else
max-fn-params-bools max-fn-params-bools
max-include-file-size max-include-file-size
max-struct-bools max-struct-bools