A check for `#[non_exhaustive]` is often done in combination with checking whether the type is local to the crate, in a variety of ways. Create a helper method and standardize on it as the way to check for this.
76 lines
2.4 KiB
Rust
76 lines
2.4 KiB
Rust
use clippy_utils::diagnostics::span_lint_and_sugg;
|
|
use clippy_utils::is_from_proc_macro;
|
|
use rustc_errors::Applicability;
|
|
use rustc_hir::def::{DefKind, Res};
|
|
use rustc_hir::{Pat, PatKind, QPath};
|
|
use rustc_lint::{LateContext, LateLintPass};
|
|
use rustc_session::declare_lint_pass;
|
|
|
|
declare_clippy_lint! {
|
|
/// ### What it does
|
|
/// Checks for struct patterns that match against unit variant.
|
|
///
|
|
/// ### Why is this bad?
|
|
/// Struct pattern `{ }` or `{ .. }` is not needed for unit variant.
|
|
///
|
|
/// ### Example
|
|
/// ```no_run
|
|
/// match Some(42) {
|
|
/// Some(v) => v,
|
|
/// None { .. } => 0,
|
|
/// };
|
|
/// // Or
|
|
/// match Some(42) {
|
|
/// Some(v) => v,
|
|
/// None { } => 0,
|
|
/// };
|
|
/// ```
|
|
/// Use instead:
|
|
/// ```no_run
|
|
/// match Some(42) {
|
|
/// Some(v) => v,
|
|
/// None => 0,
|
|
/// };
|
|
/// ```
|
|
#[clippy::version = "1.86.0"]
|
|
pub UNNEEDED_STRUCT_PATTERN,
|
|
style,
|
|
"using struct pattern to match against unit variant"
|
|
}
|
|
|
|
declare_lint_pass!(UnneededStructPattern => [UNNEEDED_STRUCT_PATTERN]);
|
|
|
|
impl LateLintPass<'_> for UnneededStructPattern {
|
|
fn check_pat(&mut self, cx: &LateContext<'_>, pat: &Pat<'_>) {
|
|
if !pat.span.from_expansion()
|
|
&& let PatKind::Struct(path, [], _) = &pat.kind
|
|
&& let QPath::Resolved(_, path) = path
|
|
&& let Res::Def(DefKind::Variant, did) = path.res
|
|
{
|
|
let enum_did = cx.tcx.parent(did);
|
|
let variant = cx.tcx.adt_def(enum_did).variant_with_id(did);
|
|
|
|
let has_only_fields_brackets = variant.ctor.is_some() && variant.fields.is_empty();
|
|
let non_exhaustive_activated = variant.field_list_has_applicable_non_exhaustive();
|
|
if !has_only_fields_brackets || non_exhaustive_activated {
|
|
return;
|
|
}
|
|
|
|
if is_from_proc_macro(cx, *path) {
|
|
return;
|
|
}
|
|
|
|
if let Some(brackets_span) = pat.span.trim_start(path.span) {
|
|
span_lint_and_sugg(
|
|
cx,
|
|
UNNEEDED_STRUCT_PATTERN,
|
|
brackets_span,
|
|
"struct pattern is not needed for a unit variant",
|
|
"remove the struct pattern",
|
|
String::new(),
|
|
Applicability::MachineApplicable,
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|