Move UnitHash into Methods lint pass
This commit is contained in:
parent
e213b6ee35
commit
bb0584dfb4
7 changed files with 76 additions and 83 deletions
|
|
@ -208,6 +208,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
|
|||
LintId::of(methods::SUSPICIOUS_MAP),
|
||||
LintId::of(methods::SUSPICIOUS_SPLITN),
|
||||
LintId::of(methods::UNINIT_ASSUMED_INIT),
|
||||
LintId::of(methods::UNIT_HASH),
|
||||
LintId::of(methods::UNNECESSARY_FILTER_MAP),
|
||||
LintId::of(methods::UNNECESSARY_FIND_MAP),
|
||||
LintId::of(methods::UNNECESSARY_FOLD),
|
||||
|
|
@ -326,7 +327,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
|
|||
LintId::of(types::VEC_BOX),
|
||||
LintId::of(unicode::INVISIBLE_CHARACTERS),
|
||||
LintId::of(uninit_vec::UNINIT_VEC),
|
||||
LintId::of(unit_hash::UNIT_HASH),
|
||||
LintId::of(unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD),
|
||||
LintId::of(unit_types::LET_UNIT_VALUE),
|
||||
LintId::of(unit_types::UNIT_ARG),
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ store.register_group(true, "clippy::correctness", Some("clippy_correctness"), ve
|
|||
LintId::of(methods::NONSENSICAL_OPEN_OPTIONS),
|
||||
LintId::of(methods::SUSPICIOUS_SPLITN),
|
||||
LintId::of(methods::UNINIT_ASSUMED_INIT),
|
||||
LintId::of(methods::UNIT_HASH),
|
||||
LintId::of(methods::ZST_OFFSET),
|
||||
LintId::of(minmax::MIN_MAX),
|
||||
LintId::of(non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS),
|
||||
|
|
@ -67,7 +68,6 @@ store.register_group(true, "clippy::correctness", Some("clippy_correctness"), ve
|
|||
LintId::of(transmute::WRONG_TRANSMUTE),
|
||||
LintId::of(unicode::INVISIBLE_CHARACTERS),
|
||||
LintId::of(uninit_vec::UNINIT_VEC),
|
||||
LintId::of(unit_hash::UNIT_HASH),
|
||||
LintId::of(unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD),
|
||||
LintId::of(unit_types::UNIT_CMP),
|
||||
LintId::of(unnamed_address::FN_ADDRESS_COMPARISONS),
|
||||
|
|
|
|||
|
|
@ -358,6 +358,7 @@ store.register_lints(&[
|
|||
methods::SUSPICIOUS_MAP,
|
||||
methods::SUSPICIOUS_SPLITN,
|
||||
methods::UNINIT_ASSUMED_INIT,
|
||||
methods::UNIT_HASH,
|
||||
methods::UNNECESSARY_FILTER_MAP,
|
||||
methods::UNNECESSARY_FIND_MAP,
|
||||
methods::UNNECESSARY_FOLD,
|
||||
|
|
@ -558,7 +559,6 @@ store.register_lints(&[
|
|||
unicode::NON_ASCII_LITERAL,
|
||||
unicode::UNICODE_NOT_NFC,
|
||||
uninit_vec::UNINIT_VEC,
|
||||
unit_hash::UNIT_HASH,
|
||||
unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD,
|
||||
unit_types::LET_UNIT_VALUE,
|
||||
unit_types::UNIT_ARG,
|
||||
|
|
|
|||
|
|
@ -371,7 +371,6 @@ mod types;
|
|||
mod undocumented_unsafe_blocks;
|
||||
mod unicode;
|
||||
mod uninit_vec;
|
||||
mod unit_hash;
|
||||
mod unit_return_expecting_ord;
|
||||
mod unit_types;
|
||||
mod unnamed_address;
|
||||
|
|
@ -582,7 +581,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||
store.register_late_pass(|| Box::new(blocks_in_if_conditions::BlocksInIfConditions));
|
||||
store.register_late_pass(|| Box::new(unicode::Unicode));
|
||||
store.register_late_pass(|| Box::new(uninit_vec::UninitVec));
|
||||
store.register_late_pass(|| Box::new(unit_hash::UnitHash));
|
||||
store.register_late_pass(|| Box::new(unit_return_expecting_ord::UnitReturnExpectingOrd));
|
||||
store.register_late_pass(|| Box::new(strings::StringAdd));
|
||||
store.register_late_pass(|| Box::new(implicit_return::ImplicitReturn));
|
||||
|
|
|
|||
|
|
@ -78,6 +78,7 @@ mod string_extend_chars;
|
|||
mod suspicious_map;
|
||||
mod suspicious_splitn;
|
||||
mod uninit_assumed_init;
|
||||
mod unit_hash;
|
||||
mod unnecessary_filter_map;
|
||||
mod unnecessary_fold;
|
||||
mod unnecessary_iter_cloned;
|
||||
|
|
@ -2832,6 +2833,45 @@ declare_clippy_lint! {
|
|||
"use of sort() when sort_unstable() is equivalent"
|
||||
}
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Detects `().hash(_)`.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// Hashing a unit value doesn't do anything as the implementation of `Hash` for `()` is a no-op.
|
||||
///
|
||||
/// ### Example
|
||||
/// ```rust
|
||||
/// # use std::hash::Hash;
|
||||
/// # use std::collections::hash_map::DefaultHasher;
|
||||
/// # enum Foo { Empty, WithValue(u8) }
|
||||
/// # use Foo::*;
|
||||
/// # let mut state = DefaultHasher::new();
|
||||
/// # let my_enum = Foo::Empty;
|
||||
/// match my_enum {
|
||||
/// Empty => ().hash(&mut state),
|
||||
/// WithValue(x) => x.hash(&mut state),
|
||||
/// }
|
||||
/// ```
|
||||
/// Use instead:
|
||||
/// ```rust
|
||||
/// # use std::hash::Hash;
|
||||
/// # use std::collections::hash_map::DefaultHasher;
|
||||
/// # enum Foo { Empty, WithValue(u8) }
|
||||
/// # use Foo::*;
|
||||
/// # let mut state = DefaultHasher::new();
|
||||
/// # let my_enum = Foo::Empty;
|
||||
/// match my_enum {
|
||||
/// Empty => 0_u8.hash(&mut state),
|
||||
/// WithValue(x) => x.hash(&mut state),
|
||||
/// }
|
||||
/// ```
|
||||
#[clippy::version = "1.58.0"]
|
||||
pub UNIT_HASH,
|
||||
correctness,
|
||||
"hashing a unit value, which does nothing"
|
||||
}
|
||||
|
||||
pub struct Methods {
|
||||
avoid_breaking_exported_api: bool,
|
||||
msrv: Option<RustcVersion>,
|
||||
|
|
@ -2949,6 +2989,7 @@ impl_lint_pass!(Methods => [
|
|||
RANGE_ZIP_WITH_LEN,
|
||||
REPEAT_ONCE,
|
||||
STABLE_SORT_PRIMITIVE,
|
||||
UNIT_HASH,
|
||||
]);
|
||||
|
||||
/// Extracts a method call name, args, and `Span` of the method name.
|
||||
|
|
@ -3258,6 +3299,9 @@ impl Methods {
|
|||
get_last_with_len::check(cx, expr, recv, arg);
|
||||
},
|
||||
("get_or_insert_with", [arg]) => unnecessary_lazy_eval::check(cx, expr, recv, arg, "get_or_insert"),
|
||||
("hash", [arg]) => {
|
||||
unit_hash::check(cx, expr, recv, arg);
|
||||
},
|
||||
("is_file", []) => filetype_is_file::check(cx, expr, recv),
|
||||
("is_digit", [radix]) => is_digit_ascii_radix::check(cx, expr, recv, radix, self.msrv),
|
||||
("is_none", []) => check_is_some_is_none(cx, expr, recv, false),
|
||||
|
|
|
|||
29
clippy_lints/src/methods/unit_hash.rs
Normal file
29
clippy_lints/src/methods/unit_hash.rs
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::is_trait_method;
|
||||
use clippy_utils::source::snippet;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::Expr;
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_span::sym;
|
||||
|
||||
use super::UNIT_HASH;
|
||||
|
||||
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, recv: &'tcx Expr<'_>, arg: &'tcx Expr<'_>) {
|
||||
if is_trait_method(cx, expr, sym::Hash) && cx.typeck_results().expr_ty(recv).is_unit() {
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
UNIT_HASH,
|
||||
expr.span,
|
||||
"this call to `hash` on the unit type will do nothing",
|
||||
|diag| {
|
||||
diag.span_suggestion(
|
||||
expr.span,
|
||||
"remove the call to `hash` or consider using",
|
||||
format!("0_u8.hash({})", snippet(cx, arg.span, ".."),),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
diag.note("the implementation of `Hash` for `()` is a no-op");
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,78 +0,0 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::source::snippet;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Expr, ExprKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::sym;
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Detects `().hash(_)`.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// Hashing a unit value doesn't do anything as the implementation of `Hash` for `()` is a no-op.
|
||||
///
|
||||
/// ### Example
|
||||
/// ```rust
|
||||
/// # use std::hash::Hash;
|
||||
/// # use std::collections::hash_map::DefaultHasher;
|
||||
/// # enum Foo { Empty, WithValue(u8) }
|
||||
/// # use Foo::*;
|
||||
/// # let mut state = DefaultHasher::new();
|
||||
/// # let my_enum = Foo::Empty;
|
||||
/// match my_enum {
|
||||
/// Empty => ().hash(&mut state),
|
||||
/// WithValue(x) => x.hash(&mut state),
|
||||
/// }
|
||||
/// ```
|
||||
/// Use instead:
|
||||
/// ```rust
|
||||
/// # use std::hash::Hash;
|
||||
/// # use std::collections::hash_map::DefaultHasher;
|
||||
/// # enum Foo { Empty, WithValue(u8) }
|
||||
/// # use Foo::*;
|
||||
/// # let mut state = DefaultHasher::new();
|
||||
/// # let my_enum = Foo::Empty;
|
||||
/// match my_enum {
|
||||
/// Empty => 0_u8.hash(&mut state),
|
||||
/// WithValue(x) => x.hash(&mut state),
|
||||
/// }
|
||||
/// ```
|
||||
#[clippy::version = "1.58.0"]
|
||||
pub UNIT_HASH,
|
||||
correctness,
|
||||
"hashing a unit value, which does nothing"
|
||||
}
|
||||
declare_lint_pass!(UnitHash => [UNIT_HASH]);
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for UnitHash {
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
|
||||
if_chain! {
|
||||
if let ExprKind::MethodCall(name_ident, args, _) = &expr.kind;
|
||||
if name_ident.ident.name == sym::hash;
|
||||
if let [recv, state_param] = args;
|
||||
if cx.typeck_results().expr_ty(recv).is_unit();
|
||||
then {
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
UNIT_HASH,
|
||||
expr.span,
|
||||
"this call to `hash` on the unit type will do nothing",
|
||||
|diag| {
|
||||
diag.span_suggestion(
|
||||
expr.span,
|
||||
"remove the call to `hash` or consider using",
|
||||
format!(
|
||||
"0_u8.hash({})",
|
||||
snippet(cx, state_param.span, ".."),
|
||||
),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
diag.note("the implementation of `Hash` for `()` is a no-op");
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue