new lint: option_as_ref_cloned
This commit is contained in:
parent
0153ca95ae
commit
5960107415
9 changed files with 138 additions and 3 deletions
|
|
@ -410,6 +410,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
|
|||
crate::methods::NO_EFFECT_REPLACE_INFO,
|
||||
crate::methods::OBFUSCATED_IF_ELSE_INFO,
|
||||
crate::methods::OK_EXPECT_INFO,
|
||||
crate::methods::OPTION_AS_REF_CLONED_INFO,
|
||||
crate::methods::OPTION_AS_REF_DEREF_INFO,
|
||||
crate::methods::OPTION_FILTER_MAP_INFO,
|
||||
crate::methods::OPTION_MAP_OR_ERR_OK_INFO,
|
||||
|
|
|
|||
|
|
@ -71,6 +71,7 @@ mod no_effect_replace;
|
|||
mod obfuscated_if_else;
|
||||
mod ok_expect;
|
||||
mod open_options;
|
||||
mod option_as_ref_cloned;
|
||||
mod option_as_ref_deref;
|
||||
mod option_map_or_err_ok;
|
||||
mod option_map_or_none;
|
||||
|
|
@ -3887,6 +3888,31 @@ declare_clippy_lint! {
|
|||
"splitting a trimmed string at hard-coded newlines"
|
||||
}
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Checks for usage of `.as_ref().cloned()` and `.as_mut().cloned()` on `Option`s
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// This can be written more concisely by cloning the `Option` directly.
|
||||
///
|
||||
/// ### Example
|
||||
/// ```no_run
|
||||
/// fn foo(bar: &Option<Vec<u8>>) -> Option<Vec<u8>> {
|
||||
/// bar.as_ref().cloned()
|
||||
/// }
|
||||
/// ```
|
||||
/// Use instead:
|
||||
/// ```no_run
|
||||
/// fn foo(bar: &Option<Vec<u8>>) -> Option<Vec<u8>> {
|
||||
/// bar.clone()
|
||||
/// }
|
||||
/// ```
|
||||
#[clippy::version = "1.77.0"]
|
||||
pub OPTION_AS_REF_CLONED,
|
||||
pedantic,
|
||||
"cloning an `Option` via `as_ref().cloned()`"
|
||||
}
|
||||
|
||||
pub struct Methods {
|
||||
avoid_breaking_exported_api: bool,
|
||||
msrv: Msrv,
|
||||
|
|
@ -4043,6 +4069,7 @@ impl_lint_pass!(Methods => [
|
|||
ITER_FILTER_IS_OK,
|
||||
MANUAL_IS_VARIANT_AND,
|
||||
STR_SPLIT_AT_NEWLINE,
|
||||
OPTION_AS_REF_CLONED,
|
||||
]);
|
||||
|
||||
/// Extracts a method call name, args, and `Span` of the method name.
|
||||
|
|
@ -4290,7 +4317,10 @@ impl Methods {
|
|||
("as_mut", []) => useless_asref::check(cx, expr, "as_mut", recv),
|
||||
("as_ref", []) => useless_asref::check(cx, expr, "as_ref", recv),
|
||||
("assume_init", []) => uninit_assumed_init::check(cx, expr, recv),
|
||||
("cloned", []) => cloned_instead_of_copied::check(cx, expr, recv, span, &self.msrv),
|
||||
("cloned", []) => {
|
||||
cloned_instead_of_copied::check(cx, expr, recv, span, &self.msrv);
|
||||
option_as_ref_cloned::check(cx, recv, span);
|
||||
},
|
||||
("collect", []) if is_trait_method(cx, expr, sym::Iterator) => {
|
||||
needless_collect::check(cx, span, expr, recv, call_span);
|
||||
match method_call(recv) {
|
||||
|
|
|
|||
24
clippy_lints/src/methods/option_as_ref_cloned.rs
Normal file
24
clippy_lints/src/methods/option_as_ref_cloned.rs
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::Expr;
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_span::{sym, Span};
|
||||
|
||||
use super::{method_call, OPTION_AS_REF_CLONED};
|
||||
|
||||
pub(super) fn check(cx: &LateContext<'_>, cloned_recv: &Expr<'_>, cloned_ident_span: Span) {
|
||||
if let Some((method @ ("as_ref" | "as_mut"), as_ref_recv, [], as_ref_ident_span, _)) = method_call(cloned_recv)
|
||||
&& is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(as_ref_recv).peel_refs(), sym::Option)
|
||||
{
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
OPTION_AS_REF_CLONED,
|
||||
as_ref_ident_span.to(cloned_ident_span),
|
||||
&format!("cloning an `Option<_>` using `.{method}().cloned()`"),
|
||||
"this can be written more concisely by cloning the `Option<_>` directly",
|
||||
"clone".into(),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue