Make the match checking configurable
This commit is contained in:
parent
173a8e0480
commit
9bd70dbb88
@ -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)));
|
||||||
|
@ -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,
|
||||||
|
}
|
||||||
|
@ -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.
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user