Merge commit '7f27e2e74ef957baa382dc05cf08df6368165c74' into clippyup

This commit is contained in:
Philipp Krones 2023-01-12 19:48:13 +01:00
parent 5f8686ec3b
commit d21616737b
85 changed files with 1892 additions and 863 deletions

7
.github/driver.sh vendored
View file

@ -17,6 +17,13 @@ test "$sysroot" = $desired_sysroot
sysroot=$(SYSROOT=$desired_sysroot ./target/debug/clippy-driver --print sysroot)
test "$sysroot" = $desired_sysroot
# Check that the --sysroot argument is only passed once (SYSROOT is ignored)
(
cd rustc_tools_util
touch src/lib.rs
SYSROOT=/tmp RUSTFLAGS="--sysroot=$(rustc --print sysroot)" ../target/debug/cargo-clippy clippy --verbose
)
# Make sure this isn't set - clippy-driver should cope without it
unset CARGO_MANIFEST_DIR

View file

@ -4137,6 +4137,7 @@ Released 2018-09-13
[`derive_hash_xor_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#derive_hash_xor_eq
[`derive_ord_xor_partial_ord`]: https://rust-lang.github.io/rust-clippy/master/index.html#derive_ord_xor_partial_ord
[`derive_partial_eq_without_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#derive_partial_eq_without_eq
[`derived_hash_with_manual_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#derived_hash_with_manual_eq
[`disallowed_macros`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_macros
[`disallowed_method`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_method
[`disallowed_methods`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_methods

View file

@ -1,6 +1,6 @@
# Installation
If you're using `rustup` to install and manage you're Rust toolchains, Clippy is
If you're using `rustup` to install and manage your Rust toolchains, Clippy is
usually **already installed**. In that case you can skip this chapter and go to
the [Usage] chapter.

View file

@ -5,6 +5,9 @@
// warn on lints, that are included in `rust-lang/rust`s bootstrap
#![warn(rust_2018_idioms, unused_lifetimes)]
// The `rustc_driver` crate seems to be required in order to use the `rust_lexer` crate.
#[allow(unused_extern_crates)]
extern crate rustc_driver;
extern crate rustc_lexer;
use std::path::PathBuf;

View file

@ -8,7 +8,7 @@ use rustc_hir::{
Block, Expr, ExprKind, Local, Node, QPath, TyKind,
};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_middle::{lint::in_external_macro, ty::print::with_forced_trimmed_paths};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::sym;
@ -59,7 +59,7 @@ impl LateLintPass<'_> for BoxDefault {
if is_plain_default(arg_path) || given_type(cx, expr) {
"Box::default()".into()
} else {
format!("Box::<{arg_ty}>::default()")
with_forced_trimmed_paths!(format!("Box::<{arg_ty}>::default()"))
},
Applicability::MachineApplicable
);

View file

@ -525,7 +525,11 @@ fn check_for_warn_of_moved_symbol(cx: &LateContext<'_>, symbols: &[(HirId, Symbo
.iter()
.filter(|&&(_, name)| !name.as_str().starts_with('_'))
.any(|&(_, name)| {
let mut walker = ContainsName { name, result: false };
let mut walker = ContainsName {
name,
result: false,
cx,
};
// Scan block
block

View file

@ -10,11 +10,11 @@ use rustc_span::sym;
declare_clippy_lint! {
/// ### What it does
/// Checks for usage of dbg!() macro.
/// Checks for usage of the [`dbg!`](https://doc.rust-lang.org/std/macro.dbg.html) macro.
///
/// ### Why is this bad?
/// `dbg!` macro is intended as a debugging tool. It
/// should not be in version control.
/// The `dbg!` macro is intended as a debugging tool. It should not be present in released
/// software or committed to a version control system.
///
/// ### Example
/// ```rust,ignore
@ -91,8 +91,8 @@ impl LateLintPass<'_> for DbgMacro {
cx,
DBG_MACRO,
macro_call.span,
"`dbg!` macro is intended as a debugging tool",
"ensure to avoid having uses of it in version control",
"the `dbg!` macro is intended as a debugging tool",
"remove the invocation before committing it to a version control system",
suggestion,
applicability,
);

View file

@ -111,7 +111,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
crate::dereference::NEEDLESS_BORROW_INFO,
crate::dereference::REF_BINDING_TO_REFERENCE_INFO,
crate::derivable_impls::DERIVABLE_IMPLS_INFO,
crate::derive::DERIVE_HASH_XOR_EQ_INFO,
crate::derive::DERIVED_HASH_WITH_MANUAL_EQ_INFO,
crate::derive::DERIVE_ORD_XOR_PARTIAL_ORD_INFO,
crate::derive::DERIVE_PARTIAL_EQ_WITHOUT_EQ_INFO,
crate::derive::EXPL_IMPL_CLONE_ON_COPY_INFO,

View file

@ -11,6 +11,7 @@ use rustc_hir::def::Res;
use rustc_hir::{Block, Expr, ExprKind, PatKind, QPath, Stmt, StmtKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
use rustc_middle::ty::print::with_forced_trimmed_paths;
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::symbol::{Ident, Symbol};
use rustc_span::Span;
@ -98,9 +99,7 @@ impl<'tcx> LateLintPass<'tcx> for Default {
if let ty::Adt(def, ..) = expr_ty.kind();
if !is_from_proc_macro(cx, expr);
then {
// TODO: Work out a way to put "whatever the imported way of referencing
// this type in this file" rather than a fully-qualified type.
let replacement = format!("{}::default()", cx.tcx.def_path_str(def.did()));
let replacement = with_forced_trimmed_paths!(format!("{}::default()", cx.tcx.def_path_str(def.did())));
span_lint_and_sugg(
cx,
DEFAULT_TRAIT_ACCESS,
@ -170,7 +169,7 @@ impl<'tcx> LateLintPass<'tcx> for Default {
// find out if and which field was set by this `consecutive_statement`
if let Some((field_ident, assign_rhs)) = field_reassigned_by_stmt(consecutive_statement, binding_name) {
// interrupt and cancel lint if assign_rhs references the original binding
if contains_name(binding_name, assign_rhs) {
if contains_name(binding_name, assign_rhs, cx) {
cancel_lint = true;
break;
}

View file

@ -1282,10 +1282,10 @@ fn referent_used_exactly_once<'tcx>(
possible_borrowers.push((body_owner_local_def_id, PossibleBorrowerMap::new(cx, mir)));
}
let possible_borrower = &mut possible_borrowers.last_mut().unwrap().1;
// If `place.local` were not included here, the `copyable_iterator::warn` test would fail. The
// reason is that `PossibleBorrowerVisitor::visit_terminator` considers `place.local` a possible
// borrower of itself. See the comment in that method for an explanation as to why.
possible_borrower.at_most_borrowers(cx, &[local, place.local], place.local, location)
// If `only_borrowers` were used here, the `copyable_iterator::warn` test would fail. The reason is
// that `PossibleBorrowerVisitor::visit_terminator` considers `place.local` a possible borrower of
// itself. See the comment in that method for an explanation as to why.
possible_borrower.bounded_borrowers(&[local], &[local, place.local], place.local, location)
&& used_exactly_once(mir, place.local).unwrap_or(false)
} else {
false

View file

@ -1,12 +1,15 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::indent_of;
use clippy_utils::{is_default_equivalent, peel_blocks};
use rustc_errors::Applicability;
use rustc_hir::{
def::{DefKind, Res},
Body, Expr, ExprKind, GenericArg, Impl, ImplItemKind, Item, ItemKind, Node, PathSegment, QPath, TyKind,
def::{CtorKind, CtorOf, DefKind, Res},
Body, Expr, ExprKind, GenericArg, Impl, ImplItemKind, Item, ItemKind, Node, PathSegment, QPath, Ty, TyKind,
};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_middle::ty::{AdtDef, DefIdTree};
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::sym;
declare_clippy_lint! {
@ -51,7 +54,18 @@ declare_clippy_lint! {
"manual implementation of the `Default` trait which is equal to a derive"
}
declare_lint_pass!(DerivableImpls => [DERIVABLE_IMPLS]);
pub struct DerivableImpls {
msrv: Msrv,
}
impl DerivableImpls {
#[must_use]
pub fn new(msrv: Msrv) -> Self {
DerivableImpls { msrv }
}
}
impl_lint_pass!(DerivableImpls => [DERIVABLE_IMPLS]);
fn is_path_self(e: &Expr<'_>) -> bool {
if let ExprKind::Path(QPath::Resolved(_, p)) = e.kind {
@ -61,6 +75,98 @@ fn is_path_self(e: &Expr<'_>) -> bool {
}
}
fn check_struct<'tcx>(
cx: &LateContext<'tcx>,
item: &'tcx Item<'_>,
self_ty: &Ty<'_>,
func_expr: &Expr<'_>,
adt_def: AdtDef<'_>,
) {
if let TyKind::Path(QPath::Resolved(_, p)) = self_ty.kind {
if let Some(PathSegment { args: Some(a), .. }) = p.segments.last() {
for arg in a.args {
if !matches!(arg, GenericArg::Lifetime(_)) {
return;
}
}
}
}
let should_emit = match peel_blocks(func_expr).kind {
ExprKind::Tup(fields) => fields.iter().all(|e| is_default_equivalent(cx, e)),
ExprKind::Call(callee, args) if is_path_self(callee) => args.iter().all(|e| is_default_equivalent(cx, e)),
ExprKind::Struct(_, fields, _) => fields.iter().all(|ef| is_default_equivalent(cx, ef.expr)),
_ => false,
};
if should_emit {
let struct_span = cx.tcx.def_span(adt_def.did());
span_lint_and_then(cx, DERIVABLE_IMPLS, item.span, "this `impl` can be derived", |diag| {
diag.span_suggestion_hidden(
item.span,
"remove the manual implementation...",
String::new(),
Applicability::MachineApplicable,
);
diag.span_suggestion(
struct_span.shrink_to_lo(),
"...and instead derive it",
"#[derive(Default)]\n".to_string(),
Applicability::MachineApplicable,
);
});
}
}
fn check_enum<'tcx>(cx: &LateContext<'tcx>, item: &'tcx Item<'_>, func_expr: &Expr<'_>, adt_def: AdtDef<'_>) {
if_chain! {
if let ExprKind::Path(QPath::Resolved(None, p)) = &peel_blocks(func_expr).kind;
if let Res::Def(DefKind::Ctor(CtorOf::Variant, CtorKind::Const), id) = p.res;
if let variant_id = cx.tcx.parent(id);
if let Some(variant_def) = adt_def.variants().iter().find(|v| v.def_id == variant_id);
if variant_def.fields.is_empty();
if !variant_def.is_field_list_non_exhaustive();
then {
let enum_span = cx.tcx.def_span(adt_def.did());
let indent_enum = indent_of(cx, enum_span).unwrap_or(0);
let variant_span = cx.tcx.def_span(variant_def.def_id);
let indent_variant = indent_of(cx, variant_span).unwrap_or(0);
span_lint_and_then(
cx,
DERIVABLE_IMPLS,
item.span,
"this `impl` can be derived",
|diag| {
diag.span_suggestion_hidden(
item.span,
"remove the manual implementation...",
String::new(),
Applicability::MachineApplicable
);
diag.span_suggestion(
enum_span.shrink_to_lo(),
"...and instead derive it...",
format!(
"#[derive(Default)]\n{indent}",
indent = " ".repeat(indent_enum),
),
Applicability::MachineApplicable
);
diag.span_suggestion(
variant_span.shrink_to_lo(),
"...and mark the default variant",
format!(
"#[default]\n{indent}",
indent = " ".repeat(indent_variant),
),
Applicability::MachineApplicable
);
}
);
}
}
}
impl<'tcx> LateLintPass<'tcx> for DerivableImpls {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
if_chain! {
@ -83,49 +189,16 @@ impl<'tcx> LateLintPass<'tcx> for DerivableImpls {
if !attrs.iter().any(|attr| attr.doc_str().is_some());
if let child_attrs = cx.tcx.hir().attrs(impl_item_hir);
if !child_attrs.iter().any(|attr| attr.doc_str().is_some());
if adt_def.is_struct();
then {
if let TyKind::Path(QPath::Resolved(_, p)) = self_ty.kind {
if let Some(PathSegment { args: Some(a), .. }) = p.segments.last() {
for arg in a.args {
if !matches!(arg, GenericArg::Lifetime(_)) {
return;
}
}
}
}
let should_emit = match peel_blocks(func_expr).kind {
ExprKind::Tup(fields) => fields.iter().all(|e| is_default_equivalent(cx, e)),
ExprKind::Call(callee, args)
if is_path_self(callee) => args.iter().all(|e| is_default_equivalent(cx, e)),
ExprKind::Struct(_, fields, _) => fields.iter().all(|ef| is_default_equivalent(cx, ef.expr)),
_ => false,
};
if should_emit {
let struct_span = cx.tcx.def_span(adt_def.did());
span_lint_and_then(
cx,
DERIVABLE_IMPLS,
item.span,
"this `impl` can be derived",
|diag| {
diag.span_suggestion_hidden(
item.span,
"remove the manual implementation...",
String::new(),
Applicability::MachineApplicable
);
diag.span_suggestion(
struct_span.shrink_to_lo(),
"...and instead derive it",
"#[derive(Default)]\n".to_string(),
Applicability::MachineApplicable
);
}
);
then {
if adt_def.is_struct() {
check_struct(cx, item, self_ty, func_expr, adt_def);
} else if adt_def.is_enum() && self.msrv.meets(msrvs::DEFAULT_ENUM_ATTRIBUTE) {
check_enum(cx, item, func_expr, adt_def);
}
}
}
}
extract_msrv_attr!(LateContext);
}

View file

@ -14,8 +14,8 @@ use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::hir::nested_filter;
use rustc_middle::traits::Reveal;
use rustc_middle::ty::{
self, Binder, BoundConstness, Clause, GenericParamDefKind, ImplPolarity, ParamEnv, PredicateKind, TraitPredicate,
Ty, TyCtxt,
self, Binder, BoundConstness, Clause, GenericArgKind, GenericParamDefKind, ImplPolarity, ParamEnv, PredicateKind,
TraitPredicate, Ty, TyCtxt,
};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::Span;
@ -46,7 +46,7 @@ declare_clippy_lint! {
/// }
/// ```
#[clippy::version = "pre 1.29.0"]
pub DERIVE_HASH_XOR_EQ,
pub DERIVED_HASH_WITH_MANUAL_EQ,
correctness,
"deriving `Hash` but implementing `PartialEq` explicitly"
}
@ -197,7 +197,7 @@ declare_clippy_lint! {
declare_lint_pass!(Derive => [
EXPL_IMPL_CLONE_ON_COPY,
DERIVE_HASH_XOR_EQ,
DERIVED_HASH_WITH_MANUAL_EQ,
DERIVE_ORD_XOR_PARTIAL_ORD,
UNSAFE_DERIVE_DESERIALIZE,
DERIVE_PARTIAL_EQ_WITHOUT_EQ
@ -226,7 +226,7 @@ impl<'tcx> LateLintPass<'tcx> for Derive {
}
}
/// Implementation of the `DERIVE_HASH_XOR_EQ` lint.
/// Implementation of the `DERIVED_HASH_WITH_MANUAL_EQ` lint.
fn check_hash_peq<'tcx>(
cx: &LateContext<'tcx>,
span: Span,
@ -243,7 +243,7 @@ fn check_hash_peq<'tcx>(
cx.tcx.for_each_relevant_impl(peq_trait_def_id, ty, |impl_id| {
let peq_is_automatically_derived = cx.tcx.has_attr(impl_id, sym::automatically_derived);
if peq_is_automatically_derived == hash_is_automatically_derived {
if !hash_is_automatically_derived || peq_is_automatically_derived {
return;
}
@ -252,17 +252,11 @@ fn check_hash_peq<'tcx>(
// Only care about `impl PartialEq<Foo> for Foo`
// For `impl PartialEq<B> for A, input_types is [A, B]
if trait_ref.substs.type_at(1) == ty {
let mess = if peq_is_automatically_derived {
"you are implementing `Hash` explicitly but have derived `PartialEq`"
} else {
"you are deriving `Hash` but have implemented `PartialEq` explicitly"
};
span_lint_and_then(
cx,
DERIVE_HASH_XOR_EQ,
DERIVED_HASH_WITH_MANUAL_EQ,
span,
mess,
"you are deriving `Hash` but have implemented `PartialEq` explicitly",
|diag| {
if let Some(local_def_id) = impl_id.as_local() {
let hir_id = cx.tcx.hir().local_def_id_to_hir_id(local_def_id);
@ -366,6 +360,15 @@ fn check_copy_clone<'tcx>(cx: &LateContext<'tcx>, item: &Item<'_>, trait_ref: &h
if ty_subs.types().any(|ty| !implements_trait(cx, ty, clone_id, &[])) {
return;
}
// `#[repr(packed)]` structs with type/const parameters can't derive `Clone`.
// https://github.com/rust-lang/rust-clippy/issues/10188
if ty_adt.repr().packed()
&& ty_subs
.iter()
.any(|arg| matches!(arg.unpack(), GenericArgKind::Type(_) | GenericArgKind::Const(_)))
{
return;
}
span_lint_and_note(
cx,

View file

@ -206,7 +206,7 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetRef {
let is_copy = is_copy(cx, arg_ty);
let drop_is_single_call_in_arm = is_single_call_in_arm(cx, arg, expr);
let (lint, msg) = match fn_name {
sym::mem_drop if arg_ty.is_ref() => (DROP_REF, DROP_REF_SUMMARY),
sym::mem_drop if arg_ty.is_ref() && !drop_is_single_call_in_arm => (DROP_REF, DROP_REF_SUMMARY),
sym::mem_forget if arg_ty.is_ref() => (FORGET_REF, FORGET_REF_SUMMARY),
sym::mem_drop if is_copy && !drop_is_single_call_in_arm => (DROP_COPY, DROP_COPY_SUMMARY),
sym::mem_forget if is_copy => (FORGET_COPY, FORGET_COPY_SUMMARY),

View file

@ -45,7 +45,7 @@ impl EarlyLintPass for EmptyStructsWithBrackets {
span_after_ident,
"remove the brackets",
";",
Applicability::MachineApplicable);
Applicability::Unspecified);
},
);
}

View file

@ -639,7 +639,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(|_| Box::new(panic_unimplemented::PanicUnimplemented));
store.register_late_pass(|_| Box::new(strings::StringLitAsBytes));
store.register_late_pass(|_| Box::new(derive::Derive));
store.register_late_pass(|_| Box::new(derivable_impls::DerivableImpls));
store.register_late_pass(move |_| Box::new(derivable_impls::DerivableImpls::new(msrv())));
store.register_late_pass(|_| Box::new(drop_forget_ref::DropForgetRef));
store.register_late_pass(|_| Box::new(empty_enum::EmptyEnum));
store.register_late_pass(|_| Box::new(invalid_upcast_comparisons::InvalidUpcastComparisons));

View file

@ -81,7 +81,7 @@ pub(super) fn check<'tcx>(
let skip = if starts_at_zero {
String::new()
} else if visitor.indexed_mut.contains(&indexed) && contains_name(indexed, start) {
} else if visitor.indexed_mut.contains(&indexed) && contains_name(indexed, start, cx) {
return;
} else {
format!(".skip({})", snippet(cx, start.span, ".."))
@ -109,7 +109,7 @@ pub(super) fn check<'tcx>(
if is_len_call(end, indexed) || is_end_eq_array_len(cx, end, limits, indexed_ty) {
String::new()
} else if visitor.indexed_mut.contains(&indexed) && contains_name(indexed, take_expr) {
} else if visitor.indexed_mut.contains(&indexed) && contains_name(indexed, take_expr, cx) {
return;
} else {
match limits {

View file

@ -1,6 +1,7 @@
use super::SINGLE_ELEMENT_LOOP;
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::{indent_of, snippet_with_applicability};
use clippy_utils::visitors::contains_break_or_continue;
use if_chain::if_chain;
use rustc_ast::util::parser::PREC_PREFIX;
use rustc_ast::Mutability;
@ -67,6 +68,7 @@ pub(super) fn check<'tcx>(
if_chain! {
if let ExprKind::Block(block, _) = body.kind;
if !block.stmts.is_empty();
if !contains_break_or_continue(body);
then {
let mut applicability = Applicability::MachineApplicable;
let pat_snip = snippet_with_applicability(cx, pat.span, "..", &mut applicability);

View file

@ -1,7 +1,10 @@
use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::source::snippet_opt;
use clippy_utils::source::{indent_of, reindent_multiline};
use clippy_utils::ty::is_type_lang_item;
use if_chain::if_chain;
use rustc_ast::ast::LitKind;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind, LangItem};
use rustc_lint::LateContext;
use rustc_span::{source_map::Spanned, Span};
@ -15,6 +18,15 @@ pub(super) fn check<'tcx>(
recv: &'tcx Expr<'_>,
arg: &'tcx Expr<'_>,
) {
if let ExprKind::MethodCall(path_segment, ..) = recv.kind {
if matches!(
path_segment.ident.name.as_str(),
"to_lowercase" | "to_uppercase" | "to_ascii_lowercase" | "to_ascii_uppercase"
) {
return;
}
}
if_chain! {
if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
if let Some(impl_id) = cx.tcx.impl_of_method(method_id);
@ -28,13 +40,37 @@ pub(super) fn check<'tcx>(
let recv_ty = cx.typeck_results().expr_ty(recv).peel_refs();
if recv_ty.is_str() || is_type_lang_item(cx, recv_ty, LangItem::String);
then {
span_lint_and_help(
span_lint_and_then(
cx,
CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS,
call_span,
recv.span.to(call_span),
"case-sensitive file extension comparison",
None,
"consider using a case-insensitive comparison instead",
|diag| {
diag.help("consider using a case-insensitive comparison instead");
if let Some(mut recv_source) = snippet_opt(cx, recv.span) {
if !cx.typeck_results().expr_ty(recv).is_ref() {
recv_source = format!("&{recv_source}");
}
let suggestion_source = reindent_multiline(
format!(
"std::path::Path::new({})
.extension()
.map_or(false, |ext| ext.eq_ignore_ascii_case(\"{}\"))",
recv_source, ext_str.strip_prefix('.').unwrap()).into(),
true,
Some(indent_of(cx, call_span).unwrap_or(0) + 4)
);
diag.span_suggestion(
recv.span.to(call_span),
"use std::path::Path",
suggestion_source,
Applicability::MaybeIncorrect,
);
}
}
);
}
}

View file

@ -6,7 +6,7 @@ use clippy_utils::ty::is_copy;
use rustc_errors::Applicability;
use rustc_hir::{BindingAnnotation, ByRef, Expr, ExprKind, MatchSource, Node, PatKind, QPath};
use rustc_lint::LateContext;
use rustc_middle::ty::{self, adjustment::Adjust};
use rustc_middle::ty::{self, adjustment::Adjust, print::with_forced_trimmed_paths};
use rustc_span::symbol::{sym, Symbol};
use super::CLONE_DOUBLE_REF;
@ -47,10 +47,10 @@ pub(super) fn check(
cx,
CLONE_DOUBLE_REF,
expr.span,
&format!(
&with_forced_trimmed_paths!(format!(
"using `clone` on a double-reference; \
this will copy the reference of type `{ty}` instead of cloning the inner type"
),
)),
|diag| {
if let Some(snip) = sugg::Sugg::hir_opt(cx, arg) {
let mut ty = innermost;
@ -61,11 +61,11 @@ pub(super) fn check(
}
let refs = "&".repeat(n + 1);
let derefs = "*".repeat(n);
let explicit = format!("<{refs}{ty}>::clone({snip})");
let explicit = with_forced_trimmed_paths!(format!("<{refs}{ty}>::clone({snip})"));
diag.span_suggestion(
expr.span,
"try dereferencing it",
format!("{refs}({derefs}{}).clone()", snip.deref()),
with_forced_trimmed_paths!(format!("{refs}({derefs}{}).clone()", snip.deref())),
Applicability::MaybeIncorrect,
);
diag.span_suggestion(
@ -129,7 +129,9 @@ pub(super) fn check(
cx,
CLONE_ON_COPY,
expr.span,
&format!("using `clone` on type `{ty}` which implements the `Copy` trait"),
&with_forced_trimmed_paths!(format!(
"using `clone` on type `{ty}` which implements the `Copy` trait"
)),
help,
sugg,
app,

View file

@ -30,12 +30,12 @@ fn is_method(cx: &LateContext<'_>, expr: &hir::Expr<'_>, method_name: Symbol) ->
match closure_expr.kind {
hir::ExprKind::MethodCall(hir::PathSegment { ident, .. }, receiver, ..) => {
if_chain! {
if ident.name == method_name;
if let hir::ExprKind::Path(path) = &receiver.kind;
if let Res::Local(ref local) = cx.qpath_res(path, receiver.hir_id);
then {
return arg_id == *local
}
if ident.name == method_name;
if let hir::ExprKind::Path(path) = &receiver.kind;
if let Res::Local(ref local) = cx.qpath_res(path, receiver.hir_id);
then {
return arg_id == *local
}
}
false
},
@ -92,92 +92,92 @@ pub(super) fn check(
}
if_chain! {
if is_trait_method(cx, map_recv, sym::Iterator);
if is_trait_method(cx, map_recv, sym::Iterator);
// filter(|x| ...is_some())...
if let ExprKind::Closure(&Closure { body: filter_body_id, .. }) = filter_arg.kind;
let filter_body = cx.tcx.hir().body(filter_body_id);
if let [filter_param] = filter_body.params;
// optional ref pattern: `filter(|&x| ..)`
let (filter_pat, is_filter_param_ref) = if let PatKind::Ref(ref_pat, _) = filter_param.pat.kind {
(ref_pat, true)
// filter(|x| ...is_some())...
if let ExprKind::Closure(&Closure { body: filter_body_id, .. }) = filter_arg.kind;
let filter_body = cx.tcx.hir().body(filter_body_id);
if let [filter_param] = filter_body.params;
// optional ref pattern: `filter(|&x| ..)`
let (filter_pat, is_filter_param_ref) = if let PatKind::Ref(ref_pat, _) = filter_param.pat.kind {
(ref_pat, true)
} else {
(filter_param.pat, false)
};
// closure ends with is_some() or is_ok()
if let PatKind::Binding(_, filter_param_id, _, None) = filter_pat.kind;
if let ExprKind::MethodCall(path, filter_arg, [], _) = filter_body.value.kind;
if let Some(opt_ty) = cx.typeck_results().expr_ty(filter_arg).peel_refs().ty_adt_def();
if let Some(is_result) = if cx.tcx.is_diagnostic_item(sym::Option, opt_ty.did()) {
Some(false)
} else if cx.tcx.is_diagnostic_item(sym::Result, opt_ty.did()) {
Some(true)
} else {
None
};
if path.ident.name.as_str() == if is_result { "is_ok" } else { "is_some" };
// ...map(|x| ...unwrap())
if let ExprKind::Closure(&Closure { body: map_body_id, .. }) = map_arg.kind;
let map_body = cx.tcx.hir().body(map_body_id);
if let [map_param] = map_body.params;
if let PatKind::Binding(_, map_param_id, map_param_ident, None) = map_param.pat.kind;
// closure ends with expect() or unwrap()
if let ExprKind::MethodCall(seg, map_arg, ..) = map_body.value.kind;
if matches!(seg.ident.name, sym::expect | sym::unwrap | sym::unwrap_or);
// .filter(..).map(|y| f(y).copied().unwrap())
// ~~~~
let map_arg_peeled = match map_arg.kind {
ExprKind::MethodCall(method, original_arg, [], _) if acceptable_methods(method) => {
original_arg
},
_ => map_arg,
};
// .filter(|x| x.is_some()).map(|y| y[.acceptable_method()].unwrap())
let simple_equal = path_to_local_id(filter_arg, filter_param_id)
&& path_to_local_id(map_arg_peeled, map_param_id);
let eq_fallback = |a: &Expr<'_>, b: &Expr<'_>| {
// in `filter(|x| ..)`, replace `*x` with `x`
let a_path = if_chain! {
if !is_filter_param_ref;
if let ExprKind::Unary(UnOp::Deref, expr_path) = a.kind;
then { expr_path } else { a }
};
// let the filter closure arg and the map closure arg be equal
path_to_local_id(a_path, filter_param_id)
&& path_to_local_id(b, map_param_id)
&& cx.typeck_results().expr_ty_adjusted(a) == cx.typeck_results().expr_ty_adjusted(b)
};
if simple_equal || SpanlessEq::new(cx).expr_fallback(eq_fallback).eq_expr(filter_arg, map_arg_peeled);
then {
let span = filter_span.with_hi(expr.span.hi());
let (filter_name, lint) = if is_find {
("find", MANUAL_FIND_MAP)
} else {
(filter_param.pat, false)
("filter", MANUAL_FILTER_MAP)
};
// closure ends with is_some() or is_ok()
if let PatKind::Binding(_, filter_param_id, _, None) = filter_pat.kind;
if let ExprKind::MethodCall(path, filter_arg, [], _) = filter_body.value.kind;
if let Some(opt_ty) = cx.typeck_results().expr_ty(filter_arg).peel_refs().ty_adt_def();
if let Some(is_result) = if cx.tcx.is_diagnostic_item(sym::Option, opt_ty.did()) {
Some(false)
} else if cx.tcx.is_diagnostic_item(sym::Result, opt_ty.did()) {
Some(true)
let msg = format!("`{filter_name}(..).map(..)` can be simplified as `{filter_name}_map(..)`");
let (to_opt, deref) = if is_result {
(".ok()", String::new())
} else {
None
let derefs = cx.typeck_results()
.expr_adjustments(map_arg)
.iter()
.filter(|adj| matches!(adj.kind, Adjust::Deref(_)))
.count();
("", "*".repeat(derefs))
};
if path.ident.name.as_str() == if is_result { "is_ok" } else { "is_some" };
// ...map(|x| ...unwrap())
if let ExprKind::Closure(&Closure { body: map_body_id, .. }) = map_arg.kind;
let map_body = cx.tcx.hir().body(map_body_id);
if let [map_param] = map_body.params;
if let PatKind::Binding(_, map_param_id, map_param_ident, None) = map_param.pat.kind;
// closure ends with expect() or unwrap()
if let ExprKind::MethodCall(seg, map_arg, ..) = map_body.value.kind;
if matches!(seg.ident.name, sym::expect | sym::unwrap | sym::unwrap_or);
// .filter(..).map(|y| f(y).copied().unwrap())
// ~~~~
let map_arg_peeled = match map_arg.kind {
ExprKind::MethodCall(method, original_arg, [], _) if acceptable_methods(method) => {
original_arg
},
_ => map_arg,
};
// .filter(|x| x.is_some()).map(|y| y[.acceptable_method()].unwrap())
let simple_equal = path_to_local_id(filter_arg, filter_param_id)
&& path_to_local_id(map_arg_peeled, map_param_id);
let eq_fallback = |a: &Expr<'_>, b: &Expr<'_>| {
// in `filter(|x| ..)`, replace `*x` with `x`
let a_path = if_chain! {
if !is_filter_param_ref;
if let ExprKind::Unary(UnOp::Deref, expr_path) = a.kind;
then { expr_path } else { a }
};
// let the filter closure arg and the map closure arg be equal
path_to_local_id(a_path, filter_param_id)
&& path_to_local_id(b, map_param_id)
&& cx.typeck_results().expr_ty_adjusted(a) == cx.typeck_results().expr_ty_adjusted(b)
};
if simple_equal || SpanlessEq::new(cx).expr_fallback(eq_fallback).eq_expr(filter_arg, map_arg_peeled);
then {
let span = filter_span.with_hi(expr.span.hi());
let (filter_name, lint) = if is_find {
("find", MANUAL_FIND_MAP)
} else {
("filter", MANUAL_FILTER_MAP)
};
let msg = format!("`{filter_name}(..).map(..)` can be simplified as `{filter_name}_map(..)`");
let (to_opt, deref) = if is_result {
(".ok()", String::new())
} else {
let derefs = cx.typeck_results()
.expr_adjustments(map_arg)
.iter()
.filter(|adj| matches!(adj.kind, Adjust::Deref(_)))
.count();
("", "*".repeat(derefs))
};
let sugg = format!(
"{filter_name}_map(|{map_param_ident}| {deref}{}{to_opt})",
snippet(cx, map_arg.span, ".."),
);
span_lint_and_sugg(cx, lint, span, &msg, "try", sugg, Applicability::MachineApplicable);
}
let sugg = format!(
"{filter_name}_map(|{map_param_ident}| {deref}{}{to_opt})",
snippet(cx, map_arg.span, ".."),
);
span_lint_and_sugg(cx, lint, span, &msg, "try", sugg, Applicability::MachineApplicable);
}
}
}

View file

@ -6,7 +6,7 @@ use clippy_utils::source::{snippet, snippet_with_applicability};
use clippy_utils::sugg;
use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::visitors::is_local_used;
use rustc_hir::{BindingAnnotation, Body, BorrowKind, Expr, ExprKind, Mutability, Pat, PatKind};
use rustc_hir::{BindingAnnotation, Body, BorrowKind, ByRef, Expr, ExprKind, Mutability, Pat, PatKind};
use rustc_lint::{LateContext, LintContext};
use rustc_middle::ty;
use rustc_span::sym;
@ -30,9 +30,9 @@ pub(super) fn check<'tcx>(
if let Body {params: [p], value: body_expr, generator_kind: _ } = cx.tcx.hir().body(c.body);
if let PatKind::Tuple([key_pat, val_pat], _) = p.pat.kind;
let (replacement_kind, binded_ident) = match (&key_pat.kind, &val_pat.kind) {
(key, PatKind::Binding(_, _, value, _)) if pat_is_wild(cx, key, m_arg) => ("value", value),
(PatKind::Binding(_, _, key, _), value) if pat_is_wild(cx, value, m_arg) => ("key", key),
let (replacement_kind, annotation, bound_ident) = match (&key_pat.kind, &val_pat.kind) {
(key, PatKind::Binding(ann, _, value, _)) if pat_is_wild(cx, key, m_arg) => ("value", ann, value),
(PatKind::Binding(ann, _, key, _), value) if pat_is_wild(cx, value, m_arg) => ("key", ann, key),
_ => return,
};
@ -47,7 +47,7 @@ pub(super) fn check<'tcx>(
if_chain! {
if let ExprKind::Path(rustc_hir::QPath::Resolved(_, path)) = body_expr.kind;
if let [local_ident] = path.segments;
if local_ident.ident.as_str() == binded_ident.as_str();
if local_ident.ident.as_str() == bound_ident.as_str();
then {
span_lint_and_sugg(
@ -60,13 +60,23 @@ pub(super) fn check<'tcx>(
applicability,
);
} else {
let ref_annotation = if annotation.0 == ByRef::Yes {
"ref "
} else {
""
};
let mut_annotation = if annotation.1 == Mutability::Mut {
"mut "
} else {
""
};
span_lint_and_sugg(
cx,
ITER_KV_MAP,
expr.span,
&format!("iterating on a map's {replacement_kind}s"),
"try",
format!("{recv_snippet}.{into_prefix}{replacement_kind}s().map(|{binded_ident}| {})",
format!("{recv_snippet}.{into_prefix}{replacement_kind}s().map(|{ref_annotation}{mut_annotation}{bound_ident}| {})",
snippet_with_applicability(cx, body_expr.span, "/* body */", &mut applicability)),
applicability,
);

View file

@ -5,7 +5,7 @@ use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::LateContext;
use rustc_middle::ty;
use rustc_middle::ty::{self, print::with_forced_trimmed_paths};
use rustc_span::sym;
use super::SUSPICIOUS_TO_OWNED;
@ -24,7 +24,9 @@ pub fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) -
cx,
SUSPICIOUS_TO_OWNED,
expr.span,
&format!("this `to_owned` call clones the {input_type} itself and does not cause the {input_type} contents to become owned"),
&with_forced_trimmed_paths!(format!(
"this `to_owned` call clones the {input_type} itself and does not cause the {input_type} contents to become owned"
)),
"consider using, depending on intent",
format!("{recv_snip}.clone()` or `{recv_snip}.into_owned()"),
app,

View file

@ -1,6 +1,6 @@
//! Checks for uses of mutex where an atomic value could be used
//!
//! This lint is **warn** by default
//! This lint is **allow** by default
use clippy_utils::diagnostics::span_lint;
use clippy_utils::ty::is_type_diagnostic_item;
@ -20,6 +20,10 @@ declare_clippy_lint! {
/// `std::sync::atomic::AtomicBool` and `std::sync::atomic::AtomicPtr` are leaner and
/// faster.
///
/// On the other hand, `Mutex`es are, in general, easier to
/// verify correctness. An atomic does not behave the same as
/// an equivalent mutex. See [this issue](https://github.com/rust-lang/rust-clippy/issues/4295)'s commentary for more details.
///
/// ### Known problems
/// This lint cannot detect if the mutex is actually used
/// for waiting before a critical section.
@ -39,8 +43,8 @@ declare_clippy_lint! {
/// ```
#[clippy::version = "pre 1.29.0"]
pub MUTEX_ATOMIC,
nursery,
"using a mutex where an atomic value could be used instead"
restriction,
"using a mutex where an atomic value could be used instead."
}
declare_clippy_lint! {

View file

@ -2,7 +2,7 @@ use super::ARITHMETIC_SIDE_EFFECTS;
use clippy_utils::{
consts::{constant, constant_simple},
diagnostics::span_lint,
peel_hir_expr_refs,
peel_hir_expr_refs, peel_hir_expr_unary,
};
use rustc_ast as ast;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
@ -98,8 +98,11 @@ impl ArithmeticSideEffects {
}
/// If `expr` is not a literal integer like `1`, returns `None`.
///
/// Returns the absolute value of the expression, if this is an integer literal.
fn literal_integer(expr: &hir::Expr<'_>) -> Option<u128> {
if let hir::ExprKind::Lit(ref lit) = expr.kind && let ast::LitKind::Int(n, _) = lit.node {
let actual = peel_hir_expr_unary(expr).0;
if let hir::ExprKind::Lit(ref lit) = actual.kind && let ast::LitKind::Int(n, _) = lit.node {
Some(n)
}
else {
@ -123,12 +126,12 @@ impl ArithmeticSideEffects {
if !matches!(
op.node,
hir::BinOpKind::Add
| hir::BinOpKind::Sub
| hir::BinOpKind::Mul
| hir::BinOpKind::Div
| hir::BinOpKind::Mul
| hir::BinOpKind::Rem
| hir::BinOpKind::Shl
| hir::BinOpKind::Shr
| hir::BinOpKind::Sub
) {
return;
};

View file

@ -103,7 +103,7 @@ declare_clippy_lint! {
declare_clippy_lint! {
/// ### What it does
/// Checks for range expressions `x..y` where both `x` and `y`
/// are constant and `x` is greater or equal to `y`.
/// are constant and `x` is greater to `y`. Also triggers if `x` is equal to `y` when they are conditions to a `for` loop.
///
/// ### Why is this bad?
/// Empty ranges yield no values so iterating them is a no-op.

View file

@ -131,7 +131,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone {
// `res = clone(arg)` can be turned into `res = move arg;`
// if `arg` is the only borrow of `cloned` at this point.
if cannot_move_out || !possible_borrower.at_most_borrowers(cx, &[arg], cloned, loc) {
if cannot_move_out || !possible_borrower.only_borrowers(&[arg], cloned, loc) {
continue;
}
@ -178,7 +178,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone {
// StorageDead(pred_arg);
// res = to_path_buf(cloned);
// ```
if cannot_move_out || !possible_borrower.at_most_borrowers(cx, &[arg, cloned], local, loc) {
if cannot_move_out || !possible_borrower.only_borrowers(&[arg, cloned], local, loc) {
continue;
}

View file

@ -9,6 +9,7 @@ pub static RENAMED_LINTS: &[(&str, &str)] = &[
("clippy::box_vec", "clippy::box_collection"),
("clippy::const_static_lifetime", "clippy::redundant_static_lifetimes"),
("clippy::cyclomatic_complexity", "clippy::cognitive_complexity"),
("clippy::derive_hash_xor_eq", "clippy::derived_hash_with_manual_eq"),
("clippy::disallowed_method", "clippy::disallowed_methods"),
("clippy::disallowed_type", "clippy::disallowed_types"),
("clippy::eval_order_dependence", "clippy::mixed_read_write_in_expression"),

View file

@ -210,22 +210,25 @@ fn check_final_expr<'tcx>(
// if desugar of `do yeet`, don't lint
if let Some(inner_expr) = inner
&& let ExprKind::Call(path_expr, _) = inner_expr.kind
&& let ExprKind::Path(QPath::LangItem(LangItem::TryTraitFromYeet, _, _)) = path_expr.kind {
return;
&& let ExprKind::Path(QPath::LangItem(LangItem::TryTraitFromYeet, _, _)) = path_expr.kind
{
return;
}
if cx.tcx.hir().attrs(expr.hir_id).is_empty() {
let borrows = inner.map_or(false, |inner| last_statement_borrows(cx, inner));
if !borrows {
// check if expr return nothing
let ret_span = if inner.is_none() && replacement == RetReplacement::Empty {
extend_span_to_previous_non_ws(cx, peeled_drop_expr.span)
} else {
peeled_drop_expr.span
};
if !cx.tcx.hir().attrs(expr.hir_id).is_empty() {
return;
}
let borrows = inner.map_or(false, |inner| last_statement_borrows(cx, inner));
if borrows {
return;
}
// check if expr return nothing
let ret_span = if inner.is_none() && replacement == RetReplacement::Empty {
extend_span_to_previous_non_ws(cx, peeled_drop_expr.span)
} else {
peeled_drop_expr.span
};
emit_return_lint(cx, ret_span, semi_spans, inner.as_ref().map(|i| i.span), replacement);
}
}
emit_return_lint(cx, ret_span, semi_spans, inner.as_ref().map(|i| i.span), replacement);
},
ExprKind::If(_, then, else_clause_opt) => {
check_block_return(cx, &then.kind, semi_spans.clone());
@ -292,7 +295,7 @@ fn last_statement_borrows<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>)
{
ControlFlow::Break(())
} else {
ControlFlow::Continue(Descend::from(!expr.span.from_expansion()))
ControlFlow::Continue(Descend::from(!e.span.from_expansion()))
}
})
.is_some()

View file

@ -127,7 +127,7 @@ declare_clippy_lint! {
/// `Vec` or a `VecDeque` (formerly called `RingBuf`).
///
/// ### Why is this bad?
/// Gankro says:
/// Gankra says:
///
/// > The TL;DR of `LinkedList` is that it's built on a massive amount of
/// pointers and indirection.

View file

@ -1,9 +1,11 @@
use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::macros::root_macro_call_first_node;
use clippy_utils::visitors::is_local_used;
use if_chain::if_chain;
use rustc_hir::{Impl, ImplItem, ImplItemKind, ItemKind};
use rustc_hir::{Body, Impl, ImplItem, ImplItemKind, ItemKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_tool_lint, impl_lint_pass};
use std::ops::ControlFlow;
declare_clippy_lint! {
/// ### What it does
@ -57,6 +59,20 @@ impl<'tcx> LateLintPass<'tcx> for UnusedSelf {
let parent = cx.tcx.hir().get_parent_item(impl_item.hir_id()).def_id;
let parent_item = cx.tcx.hir().expect_item(parent);
let assoc_item = cx.tcx.associated_item(impl_item.owner_id);
let contains_todo = |cx, body: &'_ Body<'_>| -> bool {
clippy_utils::visitors::for_each_expr(body.value, |e| {
if let Some(macro_call) = root_macro_call_first_node(cx, e) {
if cx.tcx.item_name(macro_call.def_id).as_str() == "todo" {
ControlFlow::Break(())
} else {
ControlFlow::Continue(())
}
} else {
ControlFlow::Continue(())
}
})
.is_some()
};
if_chain! {
if let ItemKind::Impl(Impl { of_trait: None, .. }) = parent_item.kind;
if assoc_item.fn_has_self_parameter;
@ -65,6 +81,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedSelf {
let body = cx.tcx.hir().body(*body_id);
if let [self_param, ..] = body.params;
if !is_local_used(cx, body, self_param.pat.hir_id);
if !contains_todo(cx, body);
then {
span_lint_and_help(
cx,
@ -72,7 +89,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedSelf {
self_param.span,
"unused `self` argument",
None,
"consider refactoring to a associated function",
"consider refactoring to an associated function",
);
}
}

View file

@ -1058,7 +1058,7 @@ fn get_parent_local<'hir>(cx: &LateContext<'hir>, expr: &'hir hir::Expr<'hir>) -
fn get_parent_local_hir_id<'hir>(cx: &LateContext<'hir>, hir_id: hir::HirId) -> Option<&'hir hir::Local<'hir>> {
let map = cx.tcx.hir();
match map.find_parent((hir_id)) {
match map.find_parent(hir_id) {
Some(hir::Node::Local(local)) => Some(local),
Some(hir::Node::Pat(pattern)) => get_parent_local_hir_id(cx, pattern.hir_id),
_ => None,

View file

@ -22,6 +22,9 @@ extern crate rustc_ast;
extern crate rustc_ast_pretty;
extern crate rustc_attr;
extern crate rustc_data_structures;
// The `rustc_driver` crate seems to be required in order to use the `rust_ast` crate.
#[allow(unused_extern_crates)]
extern crate rustc_driver;
extern crate rustc_errors;
extern crate rustc_hir;
extern crate rustc_hir_typeck;
@ -116,6 +119,8 @@ use crate::consts::{constant, Constant};
use crate::ty::{can_partially_move_ty, expr_sig, is_copy, is_recursively_primitive_type, ty_is_fn_once_param};
use crate::visitors::for_each_expr;
use rustc_middle::hir::nested_filter;
#[macro_export]
macro_rules! extract_msrv_attr {
($context:ident) => {
@ -1253,22 +1258,33 @@ pub fn get_item_name(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<Symbol> {
}
}
pub struct ContainsName {
pub struct ContainsName<'a, 'tcx> {
pub cx: &'a LateContext<'tcx>,
pub name: Symbol,
pub result: bool,
}
impl<'tcx> Visitor<'tcx> for ContainsName {
impl<'a, 'tcx> Visitor<'tcx> for ContainsName<'a, 'tcx> {
type NestedFilter = nested_filter::OnlyBodies;
fn visit_name(&mut self, name: Symbol) {
if self.name == name {
self.result = true;
}
}
fn nested_visit_map(&mut self) -> Self::Map {
self.cx.tcx.hir()
}
}
/// Checks if an `Expr` contains a certain name.
pub fn contains_name(name: Symbol, expr: &Expr<'_>) -> bool {
let mut cn = ContainsName { name, result: false };
pub fn contains_name<'tcx>(name: Symbol, expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) -> bool {
let mut cn = ContainsName {
name,
result: false,
cx,
};
cn.visit_expr(expr);
cn.result
}
@ -1304,6 +1320,7 @@ pub fn get_parent_expr_for_hir<'tcx>(cx: &LateContext<'tcx>, hir_id: hir::HirId)
}
}
/// Gets the enclosing block, if any.
pub fn get_enclosing_block<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<&'tcx Block<'tcx>> {
let map = &cx.tcx.hir();
let enclosing_node = map
@ -2244,6 +2261,18 @@ pub fn peel_n_hir_expr_refs<'a>(expr: &'a Expr<'a>, count: usize) -> (&'a Expr<'
(e, count - remaining)
}
/// Peels off all unary operators of an expression. Returns the underlying expression and the number
/// of operators removed.
pub fn peel_hir_expr_unary<'a>(expr: &'a Expr<'a>) -> (&'a Expr<'a>, usize) {
let mut count: usize = 0;
let mut curr_expr = expr;
while let ExprKind::Unary(_, local_expr) = curr_expr.kind {
count = count.wrapping_add(1);
curr_expr = local_expr;
}
(curr_expr, count)
}
/// Peels off all references on the expression. Returns the underlying expression and the number of
/// references removed.
pub fn peel_hir_expr_refs<'a>(expr: &'a Expr<'a>) -> (&'a Expr<'a>, usize) {

View file

@ -1,16 +1,11 @@
use super::possible_origin::PossibleOriginVisitor;
use super::{possible_origin::PossibleOriginVisitor, transitive_relation::TransitiveRelation};
use crate::ty::is_copy;
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
use rustc_data_structures::fx::FxHashMap;
use rustc_index::bit_set::{BitSet, HybridBitSet};
use rustc_lint::LateContext;
use rustc_middle::mir::{
self, visit::Visitor as _, BasicBlock, Local, Location, Mutability, Statement, StatementKind, Terminator,
};
use rustc_middle::ty::{self, visit::TypeVisitor, TyCtxt};
use rustc_mir_dataflow::{
fmt::DebugWithContext, impls::MaybeStorageLive, lattice::JoinSemiLattice, Analysis, AnalysisDomain,
CallReturnPlaces, ResultsCursor,
};
use rustc_middle::mir::{self, visit::Visitor as _, Mutability};
use rustc_middle::ty::{self, visit::TypeVisitor};
use rustc_mir_dataflow::{impls::MaybeStorageLive, Analysis, ResultsCursor};
use std::borrow::Cow;
use std::ops::ControlFlow;
@ -18,120 +13,78 @@ use std::ops::ControlFlow;
/// For example, `b = &a; c = &a;` will make `b` and (transitively) `c`
/// possible borrowers of `a`.
#[allow(clippy::module_name_repetitions)]
struct PossibleBorrowerAnalysis<'b, 'tcx> {
tcx: TyCtxt<'tcx>,
struct PossibleBorrowerVisitor<'a, 'b, 'tcx> {
possible_borrower: TransitiveRelation,
body: &'b mir::Body<'tcx>,
cx: &'a LateContext<'tcx>,
possible_origin: FxHashMap<mir::Local, HybridBitSet<mir::Local>>,
}
#[derive(Clone, Debug, Eq, PartialEq)]
struct PossibleBorrowerState {
map: FxIndexMap<Local, BitSet<Local>>,
domain_size: usize,
}
impl PossibleBorrowerState {
fn new(domain_size: usize) -> Self {
Self {
map: FxIndexMap::default(),
domain_size,
}
}
#[allow(clippy::similar_names)]
fn add(&mut self, borrowed: Local, borrower: Local) {
self.map
.entry(borrowed)
.or_insert(BitSet::new_empty(self.domain_size))
.insert(borrower);
}
}
impl<C> DebugWithContext<C> for PossibleBorrowerState {
fn fmt_with(&self, _ctxt: &C, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
<_ as std::fmt::Debug>::fmt(self, f)
}
fn fmt_diff_with(&self, _old: &Self, _ctxt: &C, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
unimplemented!()
}
}
impl JoinSemiLattice for PossibleBorrowerState {
fn join(&mut self, other: &Self) -> bool {
let mut changed = false;
for (&borrowed, borrowers) in other.map.iter() {
if !borrowers.is_empty() {
changed |= self
.map
.entry(borrowed)
.or_insert(BitSet::new_empty(self.domain_size))
.union(borrowers);
}
}
changed
}
}
impl<'b, 'tcx> AnalysisDomain<'tcx> for PossibleBorrowerAnalysis<'b, 'tcx> {
type Domain = PossibleBorrowerState;
const NAME: &'static str = "possible_borrower";
fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain {
PossibleBorrowerState::new(body.local_decls.len())
}
fn initialize_start_block(&self, _body: &mir::Body<'tcx>, _entry_set: &mut Self::Domain) {}
}
impl<'b, 'tcx> PossibleBorrowerAnalysis<'b, 'tcx> {
impl<'a, 'b, 'tcx> PossibleBorrowerVisitor<'a, 'b, 'tcx> {
fn new(
tcx: TyCtxt<'tcx>,
cx: &'a LateContext<'tcx>,
body: &'b mir::Body<'tcx>,
possible_origin: FxHashMap<mir::Local, HybridBitSet<mir::Local>>,
) -> Self {
Self {
tcx,
possible_borrower: TransitiveRelation::default(),
cx,
body,
possible_origin,
}
}
fn into_map(
self,
cx: &'a LateContext<'tcx>,
maybe_live: ResultsCursor<'b, 'tcx, MaybeStorageLive<'tcx>>,
) -> PossibleBorrowerMap<'b, 'tcx> {
let mut map = FxHashMap::default();
for row in (1..self.body.local_decls.len()).map(mir::Local::from_usize) {
if is_copy(cx, self.body.local_decls[row].ty) {
continue;
}
let mut borrowers = self.possible_borrower.reachable_from(row, self.body.local_decls.len());
borrowers.remove(mir::Local::from_usize(0));
if !borrowers.is_empty() {
map.insert(row, borrowers);
}
}
let bs = BitSet::new_empty(self.body.local_decls.len());
PossibleBorrowerMap {
map,
maybe_live,
bitset: (bs.clone(), bs),
}
}
}
impl<'b, 'tcx> Analysis<'tcx> for PossibleBorrowerAnalysis<'b, 'tcx> {
fn apply_call_return_effect(
&self,
_state: &mut Self::Domain,
_block: BasicBlock,
_return_places: CallReturnPlaces<'_, 'tcx>,
) {
}
fn apply_statement_effect(&self, state: &mut Self::Domain, statement: &Statement<'tcx>, _location: Location) {
if let StatementKind::Assign(box (place, rvalue)) = &statement.kind {
let lhs = place.local;
match rvalue {
mir::Rvalue::Ref(_, _, borrowed) => {
state.add(borrowed.local, lhs);
},
other => {
if ContainsRegion
.visit_ty(place.ty(&self.body.local_decls, self.tcx).ty)
.is_continue()
{
return;
impl<'a, 'b, 'tcx> mir::visit::Visitor<'tcx> for PossibleBorrowerVisitor<'a, 'b, 'tcx> {
fn visit_assign(&mut self, place: &mir::Place<'tcx>, rvalue: &mir::Rvalue<'_>, _location: mir::Location) {
let lhs = place.local;
match rvalue {
mir::Rvalue::Ref(_, _, borrowed) => {
self.possible_borrower.add(borrowed.local, lhs);
},
other => {
if ContainsRegion
.visit_ty(place.ty(&self.body.local_decls, self.cx.tcx).ty)
.is_continue()
{
return;
}
rvalue_locals(other, |rhs| {
if lhs != rhs {
self.possible_borrower.add(rhs, lhs);
}
rvalue_locals(other, |rhs| {
if lhs != rhs {
state.add(rhs, lhs);
}
});
},
}
});
},
}
}
fn apply_terminator_effect(&self, state: &mut Self::Domain, terminator: &Terminator<'tcx>, _location: Location) {
fn visit_terminator(&mut self, terminator: &mir::Terminator<'_>, _loc: mir::Location) {
if let mir::TerminatorKind::Call {
args,
destination: mir::Place { local: dest, .. },
@ -171,10 +124,10 @@ impl<'b, 'tcx> Analysis<'tcx> for PossibleBorrowerAnalysis<'b, 'tcx> {
for y in mutable_variables {
for x in &immutable_borrowers {
state.add(*x, y);
self.possible_borrower.add(*x, y);
}
for x in &mutable_borrowers {
state.add(*x, y);
self.possible_borrower.add(*x, y);
}
}
}
@ -210,98 +163,73 @@ fn rvalue_locals(rvalue: &mir::Rvalue<'_>, mut visit: impl FnMut(mir::Local)) {
}
}
/// Result of `PossibleBorrowerAnalysis`.
/// Result of `PossibleBorrowerVisitor`.
#[allow(clippy::module_name_repetitions)]
pub struct PossibleBorrowerMap<'b, 'tcx> {
body: &'b mir::Body<'tcx>,
possible_borrower: ResultsCursor<'b, 'tcx, PossibleBorrowerAnalysis<'b, 'tcx>>,
maybe_live: ResultsCursor<'b, 'tcx, MaybeStorageLive<'b>>,
pushed: BitSet<Local>,
stack: Vec<Local>,
/// Mapping `Local -> its possible borrowers`
pub map: FxHashMap<mir::Local, HybridBitSet<mir::Local>>,
maybe_live: ResultsCursor<'b, 'tcx, MaybeStorageLive<'tcx>>,
// Caches to avoid allocation of `BitSet` on every query
pub bitset: (BitSet<mir::Local>, BitSet<mir::Local>),
}
impl<'b, 'tcx> PossibleBorrowerMap<'b, 'tcx> {
pub fn new(cx: &LateContext<'tcx>, mir: &'b mir::Body<'tcx>) -> Self {
impl<'a, 'b, 'tcx> PossibleBorrowerMap<'b, 'tcx> {
pub fn new(cx: &'a LateContext<'tcx>, mir: &'b mir::Body<'tcx>) -> Self {
let possible_origin = {
let mut vis = PossibleOriginVisitor::new(mir);
vis.visit_body(mir);
vis.into_map(cx)
};
let possible_borrower = PossibleBorrowerAnalysis::new(cx.tcx, mir, possible_origin)
let maybe_storage_live_result = MaybeStorageLive::new(Cow::Owned(BitSet::new_empty(mir.local_decls.len())))
.into_engine(cx.tcx, mir)
.pass_name("possible_borrower")
.pass_name("redundant_clone")
.iterate_to_fixpoint()
.into_results_cursor(mir);
let maybe_live = MaybeStorageLive::new(Cow::Owned(BitSet::new_empty(mir.local_decls.len())))
.into_engine(cx.tcx, mir)
.pass_name("possible_borrower")
.iterate_to_fixpoint()
.into_results_cursor(mir);
PossibleBorrowerMap {
body: mir,
possible_borrower,
maybe_live,
pushed: BitSet::new_empty(mir.local_decls.len()),
stack: Vec::with_capacity(mir.local_decls.len()),
}
let mut vis = PossibleBorrowerVisitor::new(cx, mir, possible_origin);
vis.visit_body(mir);
vis.into_map(cx, maybe_storage_live_result)
}
/// Returns true if the set of borrowers of `borrowed` living at `at` includes no more than
/// `borrowers`.
/// Notes:
/// 1. It would be nice if `PossibleBorrowerMap` could store `cx` so that `at_most_borrowers`
/// would not require it to be passed in. But a `PossibleBorrowerMap` is stored in `LintPass`
/// `Dereferencing`, which outlives any `LateContext`.
/// 2. In all current uses of `at_most_borrowers`, `borrowers` is a slice of at most two
/// elements. Thus, `borrowers.contains(...)` is effectively a constant-time operation. If
/// `at_most_borrowers`'s uses were to expand beyond this, its implementation might have to be
/// adjusted.
pub fn at_most_borrowers(
/// Returns true if the set of borrowers of `borrowed` living at `at` matches with `borrowers`.
pub fn only_borrowers(&mut self, borrowers: &[mir::Local], borrowed: mir::Local, at: mir::Location) -> bool {
self.bounded_borrowers(borrowers, borrowers, borrowed, at)
}
/// Returns true if the set of borrowers of `borrowed` living at `at` includes at least `below`
/// but no more than `above`.
pub fn bounded_borrowers(
&mut self,
cx: &LateContext<'tcx>,
borrowers: &[mir::Local],
below: &[mir::Local],
above: &[mir::Local],
borrowed: mir::Local,
at: mir::Location,
) -> bool {
if is_copy(cx, self.body.local_decls[borrowed].ty) {
return true;
}
self.maybe_live.seek_after_primary_effect(at);
self.possible_borrower.seek_before_primary_effect(at);
self.maybe_live.seek_before_primary_effect(at);
let possible_borrower = &self.possible_borrower.get().map;
let maybe_live = &self.maybe_live;
self.pushed.clear();
self.stack.clear();
if let Some(borrowers) = possible_borrower.get(&borrowed) {
for b in borrowers.iter() {
if self.pushed.insert(b) {
self.stack.push(b);
}
self.bitset.0.clear();
let maybe_live = &mut self.maybe_live;
if let Some(bitset) = self.map.get(&borrowed) {
for b in bitset.iter().filter(move |b| maybe_live.contains(*b)) {
self.bitset.0.insert(b);
}
} else {
// Nothing borrows `borrowed` at `at`.
return true;
return false;
}
while let Some(borrower) = self.stack.pop() {
if maybe_live.contains(borrower) && !borrowers.contains(&borrower) {
return false;
}
if let Some(borrowers) = possible_borrower.get(&borrower) {
for b in borrowers.iter() {
if self.pushed.insert(b) {
self.stack.push(b);
}
}
}
self.bitset.1.clear();
for b in below {
self.bitset.1.insert(*b);
}
true
if !self.bitset.0.superset(&self.bitset.1) {
return false;
}
for b in above {
self.bitset.0.remove(*b);
}
self.bitset.0.is_empty()
}
pub fn local_is_alive_at(&mut self, local: mir::Local, at: mir::Location) -> bool {

View file

@ -20,8 +20,9 @@ macro_rules! msrv_aliases {
// names may refer to stabilized feature flags or library items
msrv_aliases! {
1,65,0 { LET_ELSE }
1,62,0 { BOOL_THEN_SOME }
1,62,0 { BOOL_THEN_SOME, DEFAULT_ENUM_ATTRIBUTE }
1,58,0 { FORMAT_ARGS_CAPTURE, PATTERN_TRAIT_CHAR_ARRAY }
1,55,0 { SEEK_REWIND }
1,53,0 { OR_PATTERNS, MANUAL_BITS, BTREE_MAP_RETAIN, BTREE_SET_RETAIN, ARRAY_INTO_ITERATOR }
1,52,0 { STR_SPLIT_ONCE, REM_EUCLID_CONST }
1,51,0 { BORROW_AS_PTR, SEEK_FROM_CURRENT, UNSIGNED_ABS }
@ -45,7 +46,6 @@ msrv_aliases! {
1,18,0 { HASH_MAP_RETAIN, HASH_SET_RETAIN }
1,17,0 { FIELD_INIT_SHORTHAND, STATIC_IN_CONST, EXPECT_ERR }
1,16,0 { STR_REPEAT }
1,55,0 { SEEK_REWIND }
}
fn parse_msrv(msrv: &str, sess: Option<&Session>, span: Option<Span>) -> Option<RustcVersion> {

View file

@ -47,7 +47,6 @@ pub const IDENT: [&str; 3] = ["rustc_span", "symbol", "Ident"];
#[cfg(feature = "internal")]
pub const IDENT_AS_STR: [&str; 4] = ["rustc_span", "symbol", "Ident", "as_str"];
pub const INSERT_STR: [&str; 4] = ["alloc", "string", "String", "insert_str"];
pub const ITER_COUNT: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "count"];
pub const ITER_EMPTY: [&str; 5] = ["core", "iter", "sources", "empty", "Empty"];
pub const ITERTOOLS_NEXT_TUPLE: [&str; 3] = ["itertools", "Itertools", "next_tuple"];
#[cfg(feature = "internal")]

View file

@ -724,3 +724,14 @@ pub fn for_each_local_assignment<'tcx, B>(
ControlFlow::Continue(())
}
}
pub fn contains_break_or_continue(expr: &Expr<'_>) -> bool {
for_each_expr(expr, |e| {
if matches!(e.kind, ExprKind::Break(..) | ExprKind::Continue(..)) {
ControlFlow::Break(())
} else {
ControlFlow::Continue(())
}
})
.is_some()
}

View file

@ -1,3 +1,3 @@
[toolchain]
channel = "nightly-2022-12-29"
channel = "nightly-2023-01-12"
components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]

View file

@ -256,11 +256,14 @@ pub fn main() {
LazyLock::force(&ICE_HOOK);
exit(rustc_driver::catch_with_exit_code(move || {
let mut orig_args: Vec<String> = env::args().collect();
let has_sysroot_arg = arg_value(&orig_args, "--sysroot", |_| true).is_some();
let sys_root_env = std::env::var("SYSROOT").ok();
let pass_sysroot_env_if_given = |args: &mut Vec<String>, sys_root_env| {
if let Some(sys_root) = sys_root_env {
args.extend(vec!["--sysroot".into(), sys_root]);
if !has_sysroot_arg {
args.extend(vec!["--sysroot".into(), sys_root]);
}
};
};

View file

@ -1,3 +1,12 @@
//! This test is meant to only be run in CI. To run it locally use:
//!
//! `env INTEGRATION=rust-lang/log cargo test --test integration --features=integration`
//!
//! You can use a different `INTEGRATION` value to test different repositories.
//!
//! This test will clone the specified repository and run Clippy on it. The test succeeds, if
//! Clippy doesn't produce an ICE. Lint warnings are ignored by this test.
#![cfg(feature = "integration")]
#![cfg_attr(feature = "deny-warnings", deny(warnings))]
#![warn(rust_2018_idioms, unused_lifetimes)]

View file

@ -107,7 +107,7 @@ fn rhs_is_different() {
fn unary() {
// is explicitly on the list
let _ = -OutOfNames;
// is specifically on the list
// is explicitly on the list
let _ = -Foo;
// not on the list
let _ = -Bar;

View file

@ -1,99 +1,99 @@
error: `dbg!` macro is intended as a debugging tool
error: the `dbg!` macro is intended as a debugging tool
--> $DIR/dbg_macro.rs:5:22
|
LL | if let Some(n) = dbg!(n.checked_sub(4)) { n } else { n }
| ^^^^^^^^^^^^^^^^^^^^^^
|
= note: `-D clippy::dbg-macro` implied by `-D warnings`
help: ensure to avoid having uses of it in version control
help: remove the invocation before committing it to a version control system
|
LL | if let Some(n) = n.checked_sub(4) { n } else { n }
| ~~~~~~~~~~~~~~~~
error: `dbg!` macro is intended as a debugging tool
error: the `dbg!` macro is intended as a debugging tool
--> $DIR/dbg_macro.rs:9:8
|
LL | if dbg!(n <= 1) {
| ^^^^^^^^^^^^
|
help: ensure to avoid having uses of it in version control
help: remove the invocation before committing it to a version control system
|
LL | if n <= 1 {
| ~~~~~~
error: `dbg!` macro is intended as a debugging tool
error: the `dbg!` macro is intended as a debugging tool
--> $DIR/dbg_macro.rs:10:9
|
LL | dbg!(1)
| ^^^^^^^
|
help: ensure to avoid having uses of it in version control
help: remove the invocation before committing it to a version control system
|
LL | 1
|
error: `dbg!` macro is intended as a debugging tool
error: the `dbg!` macro is intended as a debugging tool
--> $DIR/dbg_macro.rs:12:9
|
LL | dbg!(n * factorial(n - 1))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: ensure to avoid having uses of it in version control
help: remove the invocation before committing it to a version control system
|
LL | n * factorial(n - 1)
|
error: `dbg!` macro is intended as a debugging tool
error: the `dbg!` macro is intended as a debugging tool
--> $DIR/dbg_macro.rs:17:5
|
LL | dbg!(42);
| ^^^^^^^^
|
help: ensure to avoid having uses of it in version control
help: remove the invocation before committing it to a version control system
|
LL | 42;
| ~~
error: `dbg!` macro is intended as a debugging tool
error: the `dbg!` macro is intended as a debugging tool
--> $DIR/dbg_macro.rs:18:5
|
LL | dbg!(dbg!(dbg!(42)));
| ^^^^^^^^^^^^^^^^^^^^
|
help: ensure to avoid having uses of it in version control
help: remove the invocation before committing it to a version control system
|
LL | dbg!(dbg!(42));
| ~~~~~~~~~~~~~~
error: `dbg!` macro is intended as a debugging tool
error: the `dbg!` macro is intended as a debugging tool
--> $DIR/dbg_macro.rs:19:14
|
LL | foo(3) + dbg!(factorial(4));
| ^^^^^^^^^^^^^^^^^^
|
help: ensure to avoid having uses of it in version control
help: remove the invocation before committing it to a version control system
|
LL | foo(3) + factorial(4);
| ~~~~~~~~~~~~
error: `dbg!` macro is intended as a debugging tool
error: the `dbg!` macro is intended as a debugging tool
--> $DIR/dbg_macro.rs:20:5
|
LL | dbg!(1, 2, dbg!(3, 4));
| ^^^^^^^^^^^^^^^^^^^^^^
|
help: ensure to avoid having uses of it in version control
help: remove the invocation before committing it to a version control system
|
LL | (1, 2, dbg!(3, 4));
| ~~~~~~~~~~~~~~~~~~
error: `dbg!` macro is intended as a debugging tool
error: the `dbg!` macro is intended as a debugging tool
--> $DIR/dbg_macro.rs:21:5
|
LL | dbg!(1, 2, 3, 4, 5);
| ^^^^^^^^^^^^^^^^^^^
|
help: ensure to avoid having uses of it in version control
help: remove the invocation before committing it to a version control system
|
LL | (1, 2, 3, 4, 5);
| ~~~~~~~~~~~~~~~

View file

@ -2,6 +2,7 @@
clippy::assign_op_pattern,
clippy::erasing_op,
clippy::identity_op,
clippy::no_effect,
clippy::op_ref,
clippy::unnecessary_owned_empty_strings,
arithmetic_overflow,
@ -12,31 +13,95 @@
use core::num::{Saturating, Wrapping};
#[derive(Clone, Copy)]
pub struct Custom;
macro_rules! impl_arith {
( $( $_trait:ident, $ty:ty, $method:ident; )* ) => {
( $( $_trait:ident, $lhs:ty, $rhs:ty, $method:ident; )* ) => {
$(
impl core::ops::$_trait<$ty> for Custom {
type Output = Self;
fn $method(self, _: $ty) -> Self::Output { Self }
impl core::ops::$_trait<$lhs> for $rhs {
type Output = Custom;
fn $method(self, _: $lhs) -> Self::Output { todo!() }
}
)*
}
}
macro_rules! impl_assign_arith {
( $( $_trait:ident, $lhs:ty, $rhs:ty, $method:ident; )* ) => {
$(
impl core::ops::$_trait<$lhs> for $rhs {
fn $method(&mut self, _: $lhs) {}
}
)*
}
}
impl_arith!(
Add, i32, add;
Div, i32, div;
Mul, i32, mul;
Sub, i32, sub;
Add, Custom, Custom, add;
Div, Custom, Custom, div;
Mul, Custom, Custom, mul;
Rem, Custom, Custom, rem;
Sub, Custom, Custom, sub;
Add, f64, add;
Div, f64, div;
Mul, f64, mul;
Sub, f64, sub;
Add, Custom, &Custom, add;
Div, Custom, &Custom, div;
Mul, Custom, &Custom, mul;
Rem, Custom, &Custom, rem;
Sub, Custom, &Custom, sub;
Add, &Custom, Custom, add;
Div, &Custom, Custom, div;
Mul, &Custom, Custom, mul;
Rem, &Custom, Custom, rem;
Sub, &Custom, Custom, sub;
Add, &Custom, &Custom, add;
Div, &Custom, &Custom, div;
Mul, &Custom, &Custom, mul;
Rem, &Custom, &Custom, rem;
Sub, &Custom, &Custom, sub;
);
impl_assign_arith!(
AddAssign, Custom, Custom, add_assign;
DivAssign, Custom, Custom, div_assign;
MulAssign, Custom, Custom, mul_assign;
RemAssign, Custom, Custom, rem_assign;
SubAssign, Custom, Custom, sub_assign;
AddAssign, Custom, &Custom, add_assign;
DivAssign, Custom, &Custom, div_assign;
MulAssign, Custom, &Custom, mul_assign;
RemAssign, Custom, &Custom, rem_assign;
SubAssign, Custom, &Custom, sub_assign;
AddAssign, &Custom, Custom, add_assign;
DivAssign, &Custom, Custom, div_assign;
MulAssign, &Custom, Custom, mul_assign;
RemAssign, &Custom, Custom, rem_assign;
SubAssign, &Custom, Custom, sub_assign;
AddAssign, &Custom, &Custom, add_assign;
DivAssign, &Custom, &Custom, div_assign;
MulAssign, &Custom, &Custom, mul_assign;
RemAssign, &Custom, &Custom, rem_assign;
SubAssign, &Custom, &Custom, sub_assign;
);
impl core::ops::Neg for Custom {
type Output = Custom;
fn neg(self) -> Self::Output {
todo!()
}
}
impl core::ops::Neg for &Custom {
type Output = Custom;
fn neg(self) -> Self::Output {
todo!()
}
}
pub fn association_with_structures_should_not_trigger_the_lint() {
enum Foo {
Bar = -2,
@ -125,6 +190,18 @@ pub fn non_overflowing_ops_or_ops_already_handled_by_the_compiler_should_not_tri
_n *= &0;
_n *= 1;
_n *= &1;
_n += -0;
_n += &-0;
_n -= -0;
_n -= &-0;
_n /= -99;
_n /= &-99;
_n %= -99;
_n %= &-99;
_n *= -0;
_n *= &-0;
_n *= -1;
_n *= &-1;
// Binary
_n = _n + 0;
@ -158,8 +235,9 @@ pub fn non_overflowing_ops_or_ops_already_handled_by_the_compiler_should_not_tri
_n = -&i32::MIN;
}
pub fn runtime_ops() {
pub fn unknown_ops_or_runtime_ops_that_can_overflow() {
let mut _n = i32::MAX;
let mut _custom = Custom;
// Assign
_n += 1;
@ -172,6 +250,36 @@ pub fn runtime_ops() {
_n %= &0;
_n *= 2;
_n *= &2;
_n += -1;
_n += &-1;
_n -= -1;
_n -= &-1;
_n /= -0;
_n /= &-0;
_n %= -0;
_n %= &-0;
_n *= -2;
_n *= &-2;
_custom += Custom;
_custom += &Custom;
_custom -= Custom;
_custom -= &Custom;
_custom /= Custom;
_custom /= &Custom;
_custom %= Custom;
_custom %= &Custom;
_custom *= Custom;
_custom *= &Custom;
_custom += -Custom;
_custom += &-Custom;
_custom -= -Custom;
_custom -= &-Custom;
_custom /= -Custom;
_custom /= &-Custom;
_custom %= -Custom;
_custom %= &-Custom;
_custom *= -Custom;
_custom *= &-Custom;
// Binary
_n = _n + 1;
@ -193,36 +301,73 @@ pub fn runtime_ops() {
_n = 23 + &85;
_n = &23 + 85;
_n = &23 + &85;
// Custom
let _ = Custom + 0;
let _ = Custom + 1;
let _ = Custom + 2;
let _ = Custom + 0.0;
let _ = Custom + 1.0;
let _ = Custom + 2.0;
let _ = Custom - 0;
let _ = Custom - 1;
let _ = Custom - 2;
let _ = Custom - 0.0;
let _ = Custom - 1.0;
let _ = Custom - 2.0;
let _ = Custom / 0;
let _ = Custom / 1;
let _ = Custom / 2;
let _ = Custom / 0.0;
let _ = Custom / 1.0;
let _ = Custom / 2.0;
let _ = Custom * 0;
let _ = Custom * 1;
let _ = Custom * 2;
let _ = Custom * 0.0;
let _ = Custom * 1.0;
let _ = Custom * 2.0;
_custom = _custom + _custom;
_custom = _custom + &_custom;
_custom = Custom + _custom;
_custom = &Custom + _custom;
_custom = _custom - Custom;
_custom = _custom - &Custom;
_custom = Custom - _custom;
_custom = &Custom - _custom;
_custom = _custom / Custom;
_custom = _custom / &Custom;
_custom = _custom % Custom;
_custom = _custom % &Custom;
_custom = _custom * Custom;
_custom = _custom * &Custom;
_custom = Custom * _custom;
_custom = &Custom * _custom;
_custom = Custom + &Custom;
_custom = &Custom + Custom;
_custom = &Custom + &Custom;
// Unary
_n = -_n;
_n = -&_n;
_custom = -_custom;
_custom = -&_custom;
}
// Copied and pasted from the `integer_arithmetic` lint for comparison.
pub fn integer_arithmetic() {
let mut i = 1i32;
let mut var1 = 0i32;
let mut var2 = -1i32;
1 + i;
i * 2;
1 % i / 2;
i - 2 + 2 - i;
-i;
i >> 1;
i << 1;
-1;
-(-1);
i & 1;
i | 1;
i ^ 1;
i += 1;
i -= 1;
i *= 2;
i /= 2;
i /= 0;
i /= -1;
i /= var1;
i /= var2;
i %= 2;
i %= 0;
i %= -1;
i %= var1;
i %= var2;
i <<= 3;
i >>= 2;
i |= 1;
i &= 1;
i ^= i;
}
fn main() {}

View file

@ -1,5 +1,5 @@
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:165:5
--> $DIR/arithmetic_side_effects.rs:243:5
|
LL | _n += 1;
| ^^^^^^^
@ -7,328 +7,592 @@ LL | _n += 1;
= note: `-D clippy::arithmetic-side-effects` implied by `-D warnings`
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:166:5
--> $DIR/arithmetic_side_effects.rs:244:5
|
LL | _n += &1;
| ^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:167:5
--> $DIR/arithmetic_side_effects.rs:245:5
|
LL | _n -= 1;
| ^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:168:5
--> $DIR/arithmetic_side_effects.rs:246:5
|
LL | _n -= &1;
| ^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:169:5
--> $DIR/arithmetic_side_effects.rs:247:5
|
LL | _n /= 0;
| ^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:170:5
--> $DIR/arithmetic_side_effects.rs:248:5
|
LL | _n /= &0;
| ^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:171:5
--> $DIR/arithmetic_side_effects.rs:249:5
|
LL | _n %= 0;
| ^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:172:5
--> $DIR/arithmetic_side_effects.rs:250:5
|
LL | _n %= &0;
| ^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:173:5
--> $DIR/arithmetic_side_effects.rs:251:5
|
LL | _n *= 2;
| ^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:174:5
--> $DIR/arithmetic_side_effects.rs:252:5
|
LL | _n *= &2;
| ^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:177:10
--> $DIR/arithmetic_side_effects.rs:253:5
|
LL | _n += -1;
| ^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:254:5
|
LL | _n += &-1;
| ^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:255:5
|
LL | _n -= -1;
| ^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:256:5
|
LL | _n -= &-1;
| ^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:257:5
|
LL | _n /= -0;
| ^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:258:5
|
LL | _n /= &-0;
| ^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:259:5
|
LL | _n %= -0;
| ^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:260:5
|
LL | _n %= &-0;
| ^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:261:5
|
LL | _n *= -2;
| ^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:262:5
|
LL | _n *= &-2;
| ^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:263:5
|
LL | _custom += Custom;
| ^^^^^^^^^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:264:5
|
LL | _custom += &Custom;
| ^^^^^^^^^^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:265:5
|
LL | _custom -= Custom;
| ^^^^^^^^^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:266:5
|
LL | _custom -= &Custom;
| ^^^^^^^^^^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:267:5
|
LL | _custom /= Custom;
| ^^^^^^^^^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:268:5
|
LL | _custom /= &Custom;
| ^^^^^^^^^^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:269:5
|
LL | _custom %= Custom;
| ^^^^^^^^^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:270:5
|
LL | _custom %= &Custom;
| ^^^^^^^^^^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:271:5
|
LL | _custom *= Custom;
| ^^^^^^^^^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:272:5
|
LL | _custom *= &Custom;
| ^^^^^^^^^^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:273:5
|
LL | _custom += -Custom;
| ^^^^^^^^^^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:274:5
|
LL | _custom += &-Custom;
| ^^^^^^^^^^^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:275:5
|
LL | _custom -= -Custom;
| ^^^^^^^^^^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:276:5
|
LL | _custom -= &-Custom;
| ^^^^^^^^^^^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:277:5
|
LL | _custom /= -Custom;
| ^^^^^^^^^^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:278:5
|
LL | _custom /= &-Custom;
| ^^^^^^^^^^^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:279:5
|
LL | _custom %= -Custom;
| ^^^^^^^^^^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:280:5
|
LL | _custom %= &-Custom;
| ^^^^^^^^^^^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:281:5
|
LL | _custom *= -Custom;
| ^^^^^^^^^^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:282:5
|
LL | _custom *= &-Custom;
| ^^^^^^^^^^^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:285:10
|
LL | _n = _n + 1;
| ^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:178:10
--> $DIR/arithmetic_side_effects.rs:286:10
|
LL | _n = _n + &1;
| ^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:179:10
--> $DIR/arithmetic_side_effects.rs:287:10
|
LL | _n = 1 + _n;
| ^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:180:10
--> $DIR/arithmetic_side_effects.rs:288:10
|
LL | _n = &1 + _n;
| ^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:181:10
--> $DIR/arithmetic_side_effects.rs:289:10
|
LL | _n = _n - 1;
| ^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:182:10
--> $DIR/arithmetic_side_effects.rs:290:10
|
LL | _n = _n - &1;
| ^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:183:10
--> $DIR/arithmetic_side_effects.rs:291:10
|
LL | _n = 1 - _n;
| ^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:184:10
--> $DIR/arithmetic_side_effects.rs:292:10
|
LL | _n = &1 - _n;
| ^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:185:10
--> $DIR/arithmetic_side_effects.rs:293:10
|
LL | _n = _n / 0;
| ^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:186:10
--> $DIR/arithmetic_side_effects.rs:294:10
|
LL | _n = _n / &0;
| ^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:187:10
--> $DIR/arithmetic_side_effects.rs:295:10
|
LL | _n = _n % 0;
| ^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:188:10
--> $DIR/arithmetic_side_effects.rs:296:10
|
LL | _n = _n % &0;
| ^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:189:10
--> $DIR/arithmetic_side_effects.rs:297:10
|
LL | _n = _n * 2;
| ^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:190:10
--> $DIR/arithmetic_side_effects.rs:298:10
|
LL | _n = _n * &2;
| ^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:191:10
--> $DIR/arithmetic_side_effects.rs:299:10
|
LL | _n = 2 * _n;
| ^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:192:10
--> $DIR/arithmetic_side_effects.rs:300:10
|
LL | _n = &2 * _n;
| ^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:193:10
--> $DIR/arithmetic_side_effects.rs:301:10
|
LL | _n = 23 + &85;
| ^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:194:10
--> $DIR/arithmetic_side_effects.rs:302:10
|
LL | _n = &23 + 85;
| ^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:195:10
--> $DIR/arithmetic_side_effects.rs:303:10
|
LL | _n = &23 + &85;
| ^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:198:13
--> $DIR/arithmetic_side_effects.rs:304:15
|
LL | let _ = Custom + 0;
| ^^^^^^^^^^
LL | _custom = _custom + _custom;
| ^^^^^^^^^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:199:13
--> $DIR/arithmetic_side_effects.rs:305:15
|
LL | let _ = Custom + 1;
| ^^^^^^^^^^
LL | _custom = _custom + &_custom;
| ^^^^^^^^^^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:200:13
--> $DIR/arithmetic_side_effects.rs:306:15
|
LL | let _ = Custom + 2;
| ^^^^^^^^^^
LL | _custom = Custom + _custom;
| ^^^^^^^^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:201:13
--> $DIR/arithmetic_side_effects.rs:307:15
|
LL | let _ = Custom + 0.0;
| ^^^^^^^^^^^^
LL | _custom = &Custom + _custom;
| ^^^^^^^^^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:202:13
--> $DIR/arithmetic_side_effects.rs:308:15
|
LL | let _ = Custom + 1.0;
| ^^^^^^^^^^^^
LL | _custom = _custom - Custom;
| ^^^^^^^^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:203:13
--> $DIR/arithmetic_side_effects.rs:309:15
|
LL | let _ = Custom + 2.0;
| ^^^^^^^^^^^^
LL | _custom = _custom - &Custom;
| ^^^^^^^^^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:204:13
--> $DIR/arithmetic_side_effects.rs:310:15
|
LL | let _ = Custom - 0;
| ^^^^^^^^^^
LL | _custom = Custom - _custom;
| ^^^^^^^^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:205:13
--> $DIR/arithmetic_side_effects.rs:311:15
|
LL | let _ = Custom - 1;
| ^^^^^^^^^^
LL | _custom = &Custom - _custom;
| ^^^^^^^^^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:206:13
--> $DIR/arithmetic_side_effects.rs:312:15
|
LL | let _ = Custom - 2;
| ^^^^^^^^^^
LL | _custom = _custom / Custom;
| ^^^^^^^^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:207:13
--> $DIR/arithmetic_side_effects.rs:313:15
|
LL | let _ = Custom - 0.0;
| ^^^^^^^^^^^^
LL | _custom = _custom / &Custom;
| ^^^^^^^^^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:208:13
--> $DIR/arithmetic_side_effects.rs:314:15
|
LL | let _ = Custom - 1.0;
| ^^^^^^^^^^^^
LL | _custom = _custom % Custom;
| ^^^^^^^^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:209:13
--> $DIR/arithmetic_side_effects.rs:315:15
|
LL | let _ = Custom - 2.0;
| ^^^^^^^^^^^^
LL | _custom = _custom % &Custom;
| ^^^^^^^^^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:210:13
--> $DIR/arithmetic_side_effects.rs:316:15
|
LL | let _ = Custom / 0;
| ^^^^^^^^^^
LL | _custom = _custom * Custom;
| ^^^^^^^^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:211:13
--> $DIR/arithmetic_side_effects.rs:317:15
|
LL | let _ = Custom / 1;
| ^^^^^^^^^^
LL | _custom = _custom * &Custom;
| ^^^^^^^^^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:212:13
--> $DIR/arithmetic_side_effects.rs:318:15
|
LL | let _ = Custom / 2;
| ^^^^^^^^^^
LL | _custom = Custom * _custom;
| ^^^^^^^^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:213:13
--> $DIR/arithmetic_side_effects.rs:319:15
|
LL | let _ = Custom / 0.0;
| ^^^^^^^^^^^^
LL | _custom = &Custom * _custom;
| ^^^^^^^^^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:214:13
--> $DIR/arithmetic_side_effects.rs:320:15
|
LL | let _ = Custom / 1.0;
| ^^^^^^^^^^^^
LL | _custom = Custom + &Custom;
| ^^^^^^^^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:215:13
--> $DIR/arithmetic_side_effects.rs:321:15
|
LL | let _ = Custom / 2.0;
| ^^^^^^^^^^^^
LL | _custom = &Custom + Custom;
| ^^^^^^^^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:216:13
--> $DIR/arithmetic_side_effects.rs:322:15
|
LL | let _ = Custom * 0;
| ^^^^^^^^^^
LL | _custom = &Custom + &Custom;
| ^^^^^^^^^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:217:13
|
LL | let _ = Custom * 1;
| ^^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:218:13
|
LL | let _ = Custom * 2;
| ^^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:219:13
|
LL | let _ = Custom * 0.0;
| ^^^^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:220:13
|
LL | let _ = Custom * 1.0;
| ^^^^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:221:13
|
LL | let _ = Custom * 2.0;
| ^^^^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:224:10
--> $DIR/arithmetic_side_effects.rs:325:10
|
LL | _n = -_n;
| ^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:225:10
--> $DIR/arithmetic_side_effects.rs:326:10
|
LL | _n = -&_n;
| ^^^^
error: aborting due to 55 previous errors
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:327:15
|
LL | _custom = -_custom;
| ^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:328:15
|
LL | _custom = -&_custom;
| ^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:337:5
|
LL | 1 + i;
| ^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:338:5
|
LL | i * 2;
| ^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:340:5
|
LL | i - 2 + 2 - i;
| ^^^^^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:341:5
|
LL | -i;
| ^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:342:5
|
LL | i >> 1;
| ^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:343:5
|
LL | i << 1;
| ^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:352:5
|
LL | i += 1;
| ^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:353:5
|
LL | i -= 1;
| ^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:354:5
|
LL | i *= 2;
| ^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:356:5
|
LL | i /= 0;
| ^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:358:5
|
LL | i /= var1;
| ^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:359:5
|
LL | i /= var2;
| ^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:361:5
|
LL | i %= 0;
| ^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:363:5
|
LL | i %= var1;
| ^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:364:5
|
LL | i %= var2;
| ^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:365:5
|
LL | i <<= 3;
| ^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
--> $DIR/arithmetic_side_effects.rs:366:5
|
LL | i >>= 2;
| ^^^^^^^
error: aborting due to 99 previous errors

View file

@ -21,16 +21,16 @@ macro_rules! outer {
fn main() {
let _string: Box<String> = Box::default();
let _byte = Box::<u8>::default();
let _vec = Box::<std::vec::Vec<u8>>::default();
let _vec = Box::<Vec<u8>>::default();
let _impl = Box::<ImplementsDefault>::default();
let _impl2 = Box::<ImplementsDefault>::default();
let _impl3: Box<ImplementsDefault> = Box::default();
let _own = Box::new(OwnDefault::default()); // should not lint
let _in_macro = outer!(Box::<std::string::String>::default());
let _string_default = outer!(Box::<std::string::String>::default());
let _in_macro = outer!(Box::<String>::default());
let _string_default = outer!(Box::<String>::default());
let _vec2: Box<Vec<ImplementsDefault>> = Box::default();
let _vec3: Box<Vec<bool>> = Box::default();
let _vec4: Box<_> = Box::<std::vec::Vec<bool>>::default();
let _vec4: Box<_> = Box::<Vec<bool>>::default();
let _more = ret_ty_fn();
call_ty_fn(Box::default());
}
@ -54,4 +54,14 @@ impl Read for ImplementsDefault {
fn issue_9621_dyn_trait() {
let _: Box<dyn Read> = Box::<ImplementsDefault>::default();
issue_10089();
}
fn issue_10089() {
let _closure = || {
#[derive(Default)]
struct WeirdPathed;
let _ = Box::<WeirdPathed>::default();
};
}

View file

@ -54,4 +54,14 @@ impl Read for ImplementsDefault {
fn issue_9621_dyn_trait() {
let _: Box<dyn Read> = Box::new(ImplementsDefault::default());
issue_10089();
}
fn issue_10089() {
let _closure = || {
#[derive(Default)]
struct WeirdPathed;
let _ = Box::new(WeirdPathed::default());
};
}

View file

@ -16,7 +16,7 @@ error: `Box::new(_)` of default value
--> $DIR/box_default.rs:24:16
|
LL | let _vec = Box::new(Vec::<u8>::new());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<std::vec::Vec<u8>>::default()`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<Vec<u8>>::default()`
error: `Box::new(_)` of default value
--> $DIR/box_default.rs:25:17
@ -40,13 +40,13 @@ error: `Box::new(_)` of default value
--> $DIR/box_default.rs:29:28
|
LL | let _in_macro = outer!(Box::new(String::new()));
| ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<std::string::String>::default()`
| ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<String>::default()`
error: `Box::new(_)` of default value
--> $DIR/box_default.rs:30:34
|
LL | let _string_default = outer!(Box::new(String::from("")));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<std::string::String>::default()`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<String>::default()`
error: `Box::new(_)` of default value
--> $DIR/box_default.rs:31:46
@ -64,7 +64,7 @@ error: `Box::new(_)` of default value
--> $DIR/box_default.rs:33:25
|
LL | let _vec4: Box<_> = Box::new(Vec::from([false; 0]));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<std::vec::Vec<bool>>::default()`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<Vec<bool>>::default()`
error: `Box::new(_)` of default value
--> $DIR/box_default.rs:35:16
@ -84,5 +84,11 @@ error: `Box::new(_)` of default value
LL | let _: Box<dyn Read> = Box::new(ImplementsDefault::default());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<ImplementsDefault>::default()`
error: aborting due to 14 previous errors
error: `Box::new(_)` of default value
--> $DIR/box_default.rs:65:17
|
LL | let _ = Box::new(WeirdPathed::default());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<WeirdPathed>::default()`
error: aborting due to 15 previous errors

View file

@ -0,0 +1,67 @@
// run-rustfix
#![warn(clippy::case_sensitive_file_extension_comparisons)]
use std::string::String;
struct TestStruct;
impl TestStruct {
fn ends_with(self, _arg: &str) {}
}
#[allow(dead_code)]
fn is_rust_file(filename: &str) -> bool {
std::path::Path::new(filename)
.extension()
.map_or(false, |ext| ext.eq_ignore_ascii_case("rs"))
}
fn main() {
// std::string::String and &str should trigger the lint failure with .ext12
let _ = std::path::Path::new(&String::new())
.extension()
.map_or(false, |ext| ext.eq_ignore_ascii_case("ext12"));
let _ = std::path::Path::new("str")
.extension()
.map_or(false, |ext| ext.eq_ignore_ascii_case("ext12"));
// The fixup should preserve the indentation level
{
let _ = std::path::Path::new("str")
.extension()
.map_or(false, |ext| ext.eq_ignore_ascii_case("ext12"));
}
// The test struct should not trigger the lint failure with .ext12
TestStruct {}.ends_with(".ext12");
// std::string::String and &str should trigger the lint failure with .EXT12
let _ = std::path::Path::new(&String::new())
.extension()
.map_or(false, |ext| ext.eq_ignore_ascii_case("EXT12"));
let _ = std::path::Path::new("str")
.extension()
.map_or(false, |ext| ext.eq_ignore_ascii_case("EXT12"));
// Should not trigger the lint failure because of the calls to to_lowercase and to_uppercase
let _ = String::new().to_lowercase().ends_with(".EXT12");
let _ = String::new().to_uppercase().ends_with(".EXT12");
// The test struct should not trigger the lint failure with .EXT12
TestStruct {}.ends_with(".EXT12");
// Should not trigger the lint failure with .eXT12
let _ = String::new().ends_with(".eXT12");
let _ = "str".ends_with(".eXT12");
TestStruct {}.ends_with(".eXT12");
// Should not trigger the lint failure with .EXT123 (too long)
let _ = String::new().ends_with(".EXT123");
let _ = "str".ends_with(".EXT123");
TestStruct {}.ends_with(".EXT123");
// Shouldn't fail if it doesn't start with a dot
let _ = String::new().ends_with("a.ext");
let _ = "str".ends_with("a.extA");
TestStruct {}.ends_with("a.ext");
}

View file

@ -1,3 +1,4 @@
// run-rustfix
#![warn(clippy::case_sensitive_file_extension_comparisons)]
use std::string::String;
@ -5,9 +6,10 @@ use std::string::String;
struct TestStruct;
impl TestStruct {
fn ends_with(self, arg: &str) {}
fn ends_with(self, _arg: &str) {}
}
#[allow(dead_code)]
fn is_rust_file(filename: &str) -> bool {
filename.ends_with(".rs")
}
@ -17,6 +19,11 @@ fn main() {
let _ = String::new().ends_with(".ext12");
let _ = "str".ends_with(".ext12");
// The fixup should preserve the indentation level
{
let _ = "str".ends_with(".ext12");
}
// The test struct should not trigger the lint failure with .ext12
TestStruct {}.ends_with(".ext12");
@ -24,6 +31,10 @@ fn main() {
let _ = String::new().ends_with(".EXT12");
let _ = "str".ends_with(".EXT12");
// Should not trigger the lint failure because of the calls to to_lowercase and to_uppercase
let _ = String::new().to_lowercase().ends_with(".EXT12");
let _ = String::new().to_uppercase().ends_with(".EXT12");
// The test struct should not trigger the lint failure with .EXT12
TestStruct {}.ends_with(".EXT12");

View file

@ -1,43 +1,87 @@
error: case-sensitive file extension comparison
--> $DIR/case_sensitive_file_extension_comparisons.rs:12:14
--> $DIR/case_sensitive_file_extension_comparisons.rs:14:5
|
LL | filename.ends_with(".rs")
| ^^^^^^^^^^^^^^^^
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: consider using a case-insensitive comparison instead
= note: `-D clippy::case-sensitive-file-extension-comparisons` implied by `-D warnings`
help: use std::path::Path
|
LL ~ std::path::Path::new(filename)
LL + .extension()
LL + .map_or(false, |ext| ext.eq_ignore_ascii_case("rs"))
|
error: case-sensitive file extension comparison
--> $DIR/case_sensitive_file_extension_comparisons.rs:17:27
--> $DIR/case_sensitive_file_extension_comparisons.rs:19:13
|
LL | let _ = String::new().ends_with(".ext12");
| ^^^^^^^^^^^^^^^^^^^
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: consider using a case-insensitive comparison instead
help: use std::path::Path
|
LL ~ let _ = std::path::Path::new(&String::new())
LL + .extension()
LL ~ .map_or(false, |ext| ext.eq_ignore_ascii_case("ext12"));
|
error: case-sensitive file extension comparison
--> $DIR/case_sensitive_file_extension_comparisons.rs:18:19
--> $DIR/case_sensitive_file_extension_comparisons.rs:20:13
|
LL | let _ = "str".ends_with(".ext12");
| ^^^^^^^^^^^^^^^^^^^
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: consider using a case-insensitive comparison instead
help: use std::path::Path
|
LL ~ let _ = std::path::Path::new("str")
LL + .extension()
LL ~ .map_or(false, |ext| ext.eq_ignore_ascii_case("ext12"));
|
error: case-sensitive file extension comparison
--> $DIR/case_sensitive_file_extension_comparisons.rs:24:27
--> $DIR/case_sensitive_file_extension_comparisons.rs:24:17
|
LL | let _ = "str".ends_with(".ext12");
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: consider using a case-insensitive comparison instead
help: use std::path::Path
|
LL ~ let _ = std::path::Path::new("str")
LL + .extension()
LL ~ .map_or(false, |ext| ext.eq_ignore_ascii_case("ext12"));
|
error: case-sensitive file extension comparison
--> $DIR/case_sensitive_file_extension_comparisons.rs:31:13
|
LL | let _ = String::new().ends_with(".EXT12");
| ^^^^^^^^^^^^^^^^^^^
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: consider using a case-insensitive comparison instead
help: use std::path::Path
|
LL ~ let _ = std::path::Path::new(&String::new())
LL + .extension()
LL ~ .map_or(false, |ext| ext.eq_ignore_ascii_case("EXT12"));
|
error: case-sensitive file extension comparison
--> $DIR/case_sensitive_file_extension_comparisons.rs:25:19
--> $DIR/case_sensitive_file_extension_comparisons.rs:32:13
|
LL | let _ = "str".ends_with(".EXT12");
| ^^^^^^^^^^^^^^^^^^^
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: consider using a case-insensitive comparison instead
help: use std::path::Path
|
LL ~ let _ = std::path::Path::new("str")
LL + .extension()
LL ~ .map_or(false, |ext| ext.eq_ignore_ascii_case("EXT12"));
|
error: aborting due to 5 previous errors
error: aborting due to 6 previous errors

View file

@ -48,7 +48,7 @@ error: using `clone` on type `i32` which implements the `Copy` trait
LL | vec.push(42.clone());
| ^^^^^^^^^^ help: try removing the `clone` call: `42`
error: using `clone` on type `std::option::Option<i32>` which implements the `Copy` trait
error: using `clone` on type `Option<i32>` which implements the `Copy` trait
--> $DIR/clone_on_copy.rs:77:17
|
LL | let value = opt.clone()?; // operator precedence needed (*opt)?

View file

@ -1,143 +1,143 @@
error: `dbg!` macro is intended as a debugging tool
error: the `dbg!` macro is intended as a debugging tool
--> $DIR/dbg_macro.rs:5:22
|
LL | if let Some(n) = dbg!(n.checked_sub(4)) { n } else { n }
| ^^^^^^^^^^^^^^^^^^^^^^
|
= note: `-D clippy::dbg-macro` implied by `-D warnings`
help: ensure to avoid having uses of it in version control
help: remove the invocation before committing it to a version control system
|
LL | if let Some(n) = n.checked_sub(4) { n } else { n }
| ~~~~~~~~~~~~~~~~
error: `dbg!` macro is intended as a debugging tool
error: the `dbg!` macro is intended as a debugging tool
--> $DIR/dbg_macro.rs:9:8
|
LL | if dbg!(n <= 1) {
| ^^^^^^^^^^^^
|
help: ensure to avoid having uses of it in version control
help: remove the invocation before committing it to a version control system
|
LL | if n <= 1 {
| ~~~~~~
error: `dbg!` macro is intended as a debugging tool
error: the `dbg!` macro is intended as a debugging tool
--> $DIR/dbg_macro.rs:10:9
|
LL | dbg!(1)
| ^^^^^^^
|
help: ensure to avoid having uses of it in version control
help: remove the invocation before committing it to a version control system
|
LL | 1
|
error: `dbg!` macro is intended as a debugging tool
error: the `dbg!` macro is intended as a debugging tool
--> $DIR/dbg_macro.rs:12:9
|
LL | dbg!(n * factorial(n - 1))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: ensure to avoid having uses of it in version control
help: remove the invocation before committing it to a version control system
|
LL | n * factorial(n - 1)
|
error: `dbg!` macro is intended as a debugging tool
error: the `dbg!` macro is intended as a debugging tool
--> $DIR/dbg_macro.rs:17:5
|
LL | dbg!(42);
| ^^^^^^^^
|
help: ensure to avoid having uses of it in version control
help: remove the invocation before committing it to a version control system
|
LL | 42;
| ~~
error: `dbg!` macro is intended as a debugging tool
error: the `dbg!` macro is intended as a debugging tool
--> $DIR/dbg_macro.rs:18:5
|
LL | dbg!(dbg!(dbg!(42)));
| ^^^^^^^^^^^^^^^^^^^^
|
help: ensure to avoid having uses of it in version control
help: remove the invocation before committing it to a version control system
|
LL | dbg!(dbg!(42));
| ~~~~~~~~~~~~~~
error: `dbg!` macro is intended as a debugging tool
error: the `dbg!` macro is intended as a debugging tool
--> $DIR/dbg_macro.rs:19:14
|
LL | foo(3) + dbg!(factorial(4));
| ^^^^^^^^^^^^^^^^^^
|
help: ensure to avoid having uses of it in version control
help: remove the invocation before committing it to a version control system
|
LL | foo(3) + factorial(4);
| ~~~~~~~~~~~~
error: `dbg!` macro is intended as a debugging tool
error: the `dbg!` macro is intended as a debugging tool
--> $DIR/dbg_macro.rs:20:5
|
LL | dbg!(1, 2, dbg!(3, 4));
| ^^^^^^^^^^^^^^^^^^^^^^
|
help: ensure to avoid having uses of it in version control
help: remove the invocation before committing it to a version control system
|
LL | (1, 2, dbg!(3, 4));
| ~~~~~~~~~~~~~~~~~~
error: `dbg!` macro is intended as a debugging tool
error: the `dbg!` macro is intended as a debugging tool
--> $DIR/dbg_macro.rs:21:5
|
LL | dbg!(1, 2, 3, 4, 5);
| ^^^^^^^^^^^^^^^^^^^
|
help: ensure to avoid having uses of it in version control
help: remove the invocation before committing it to a version control system
|
LL | (1, 2, 3, 4, 5);
| ~~~~~~~~~~~~~~~
error: `dbg!` macro is intended as a debugging tool
error: the `dbg!` macro is intended as a debugging tool
--> $DIR/dbg_macro.rs:41:9
|
LL | dbg!(2);
| ^^^^^^^
|
help: ensure to avoid having uses of it in version control
help: remove the invocation before committing it to a version control system
|
LL | 2;
| ~
error: `dbg!` macro is intended as a debugging tool
error: the `dbg!` macro is intended as a debugging tool
--> $DIR/dbg_macro.rs:47:5
|
LL | dbg!(1);
| ^^^^^^^
|
help: ensure to avoid having uses of it in version control
help: remove the invocation before committing it to a version control system
|
LL | 1;
| ~
error: `dbg!` macro is intended as a debugging tool
error: the `dbg!` macro is intended as a debugging tool
--> $DIR/dbg_macro.rs:52:5
|
LL | dbg!(1);
| ^^^^^^^
|
help: ensure to avoid having uses of it in version control
help: remove the invocation before committing it to a version control system
|
LL | 1;
| ~
error: `dbg!` macro is intended as a debugging tool
error: the `dbg!` macro is intended as a debugging tool
--> $DIR/dbg_macro.rs:58:9
|
LL | dbg!(1);
| ^^^^^^^
|
help: ensure to avoid having uses of it in version control
help: remove the invocation before committing it to a version control system
|
LL | 1;
| ~

View file

@ -12,17 +12,17 @@ use std::default::Default as D2;
use std::string;
fn main() {
let s1: String = std::string::String::default();
let s1: String = String::default();
let s2 = String::default();
let s3: String = std::string::String::default();
let s3: String = String::default();
let s4: String = std::string::String::default();
let s4: String = String::default();
let s5 = string::String::default();
let s6: String = std::string::String::default();
let s6: String = String::default();
let s7 = std::string::String::default();

View file

@ -1,8 +1,8 @@
error: calling `std::string::String::default()` is more clear than this expression
error: calling `String::default()` is more clear than this expression
--> $DIR/default_trait_access.rs:15:22
|
LL | let s1: String = Default::default();
| ^^^^^^^^^^^^^^^^^^ help: try: `std::string::String::default()`
| ^^^^^^^^^^^^^^^^^^ help: try: `String::default()`
|
note: the lint level is defined here
--> $DIR/default_trait_access.rs:3:9
@ -10,23 +10,23 @@ note: the lint level is defined here
LL | #![deny(clippy::default_trait_access)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: calling `std::string::String::default()` is more clear than this expression
error: calling `String::default()` is more clear than this expression
--> $DIR/default_trait_access.rs:19:22
|
LL | let s3: String = D2::default();
| ^^^^^^^^^^^^^ help: try: `std::string::String::default()`
| ^^^^^^^^^^^^^ help: try: `String::default()`
error: calling `std::string::String::default()` is more clear than this expression
error: calling `String::default()` is more clear than this expression
--> $DIR/default_trait_access.rs:21:22
|
LL | let s4: String = std::default::Default::default();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::string::String::default()`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `String::default()`
error: calling `std::string::String::default()` is more clear than this expression
error: calling `String::default()` is more clear than this expression
--> $DIR/default_trait_access.rs:25:22
|
LL | let s6: String = default::Default::default();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::string::String::default()`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `String::default()`
error: calling `GenericDerivedDefault::default()` is more clear than this expression
--> $DIR/default_trait_access.rs:35:46

View file

@ -210,4 +210,25 @@ impl Default for IntOrString {
}
}
#[derive(Default)]
pub enum SimpleEnum {
Foo,
#[default]
Bar,
}
pub enum NonExhaustiveEnum {
Foo,
#[non_exhaustive]
Bar,
}
impl Default for NonExhaustiveEnum {
fn default() -> Self {
NonExhaustiveEnum::Bar
}
}
fn main() {}

View file

@ -244,4 +244,27 @@ impl Default for IntOrString {
}
}
pub enum SimpleEnum {
Foo,
Bar,
}
impl Default for SimpleEnum {
fn default() -> Self {
SimpleEnum::Bar
}
}
pub enum NonExhaustiveEnum {
Foo,
#[non_exhaustive]
Bar,
}
impl Default for NonExhaustiveEnum {
fn default() -> Self {
NonExhaustiveEnum::Bar
}
}
fn main() {}

View file

@ -113,5 +113,26 @@ help: ...and instead derive it
LL | #[derive(Default)]
|
error: aborting due to 7 previous errors
error: this `impl` can be derived
--> $DIR/derivable_impls.rs:252:1
|
LL | / impl Default for SimpleEnum {
LL | | fn default() -> Self {
LL | | SimpleEnum::Bar
LL | | }
LL | | }
| |_^
|
= help: remove the manual implementation...
help: ...and instead derive it...
|
LL | #[derive(Default)]
|
help: ...and mark the default variant
|
LL ~ #[default]
LL ~ Bar,
|
error: aborting due to 8 previous errors

View file

@ -86,4 +86,15 @@ impl<T: Clone, U> Clone for GenericRef<'_, T, U> {
}
}
// https://github.com/rust-lang/rust-clippy/issues/10188
#[repr(packed)]
#[derive(Copy)]
struct Packed<T>(T);
impl<T: Copy> Clone for Packed<T> {
fn clone(&self) -> Self {
*self
}
}
fn main() {}

View file

@ -1,59 +0,0 @@
error: you are deriving `Hash` but have implemented `PartialEq` explicitly
--> $DIR/derive_hash_xor_eq.rs:12:10
|
LL | #[derive(Hash)]
| ^^^^
|
note: `PartialEq` implemented here
--> $DIR/derive_hash_xor_eq.rs:15:1
|
LL | impl PartialEq for Bar {
| ^^^^^^^^^^^^^^^^^^^^^^
= note: `#[deny(clippy::derive_hash_xor_eq)]` on by default
= note: this error originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info)
error: you are deriving `Hash` but have implemented `PartialEq` explicitly
--> $DIR/derive_hash_xor_eq.rs:21:10
|
LL | #[derive(Hash)]
| ^^^^
|
note: `PartialEq` implemented here
--> $DIR/derive_hash_xor_eq.rs:24:1
|
LL | impl PartialEq<Baz> for Baz {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: this error originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info)
error: you are implementing `Hash` explicitly but have derived `PartialEq`
--> $DIR/derive_hash_xor_eq.rs:33:1
|
LL | / impl std::hash::Hash for Bah {
LL | | fn hash<H: std::hash::Hasher>(&self, _: &mut H) {}
LL | | }
| |_^
|
note: `PartialEq` implemented here
--> $DIR/derive_hash_xor_eq.rs:30:10
|
LL | #[derive(PartialEq)]
| ^^^^^^^^^
= note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info)
error: you are implementing `Hash` explicitly but have derived `PartialEq`
--> $DIR/derive_hash_xor_eq.rs:51:5
|
LL | / impl Hash for Foo3 {
LL | | fn hash<H: std::hash::Hasher>(&self, _: &mut H) {}
LL | | }
| |_____^
|
note: `PartialEq` implemented here
--> $DIR/derive_hash_xor_eq.rs:48:14
|
LL | #[derive(PartialEq)]
| ^^^^^^^^^
= note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 4 previous errors

View file

@ -27,6 +27,8 @@ impl PartialEq<Baz> for Baz {
}
}
// Implementing `Hash` with a derived `PartialEq` is fine. See #2627
#[derive(PartialEq)]
struct Bah;
@ -34,23 +36,4 @@ impl std::hash::Hash for Bah {
fn hash<H: std::hash::Hasher>(&self, _: &mut H) {}
}
#[derive(PartialEq)]
struct Foo2;
trait Hash {}
// We don't want to lint on user-defined traits called `Hash`
impl Hash for Foo2 {}
mod use_hash {
use std::hash::{Hash, Hasher};
#[derive(PartialEq)]
struct Foo3;
impl Hash for Foo3 {
fn hash<H: std::hash::Hasher>(&self, _: &mut H) {}
}
}
fn main() {}

View file

@ -0,0 +1,29 @@
error: you are deriving `Hash` but have implemented `PartialEq` explicitly
--> $DIR/derived_hash_with_manual_eq.rs:12:10
|
LL | #[derive(Hash)]
| ^^^^
|
note: `PartialEq` implemented here
--> $DIR/derived_hash_with_manual_eq.rs:15:1
|
LL | impl PartialEq for Bar {
| ^^^^^^^^^^^^^^^^^^^^^^
= note: `#[deny(clippy::derived_hash_with_manual_eq)]` on by default
= note: this error originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info)
error: you are deriving `Hash` but have implemented `PartialEq` explicitly
--> $DIR/derived_hash_with_manual_eq.rs:21:10
|
LL | #[derive(Hash)]
| ^^^^
|
note: `PartialEq` implemented here
--> $DIR/derived_hash_with_manual_eq.rs:24:1
|
LL | impl PartialEq<Baz> for Baz {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: this error originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 2 previous errors

View file

@ -72,3 +72,26 @@ fn test_owl_result_2() -> Result<u8, ()> {
produce_half_owl_ok().map(drop)?;
Ok(1)
}
#[allow(unused)]
#[allow(clippy::unit_cmp)]
fn issue10122(x: u8) {
// This is a function which returns a reference and has a side-effect, which means
// that calling drop() on the function is considered an idiomatic way of achieving the side-effect
// in a match arm.
fn println_and<T>(t: &T) -> &T {
println!("foo");
t
}
match x {
0 => drop(println_and(&12)), // Don't lint (copy type), we only care about side-effects
1 => drop(println_and(&String::new())), // Don't lint (no copy type), we only care about side-effects
2 => {
drop(println_and(&13)); // Lint, even if we only care about the side-effect, it's already in a block
},
3 if drop(println_and(&14)) == () => (), // Lint, idiomatic use is only in body of `Arm`
4 => drop(&2), // Lint, not a fn/method call
_ => (),
}
}

View file

@ -107,5 +107,41 @@ note: argument has type `&SomeStruct`
LL | std::mem::drop(&SomeStruct);
| ^^^^^^^^^^^
error: aborting due to 9 previous errors
error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing
--> $DIR/drop_ref.rs:91:13
|
LL | drop(println_and(&13)); // Lint, even if we only care about the side-effect, it's already in a block
| ^^^^^^^^^^^^^^^^^^^^^^
|
note: argument has type `&i32`
--> $DIR/drop_ref.rs:91:18
|
LL | drop(println_and(&13)); // Lint, even if we only care about the side-effect, it's already in a block
| ^^^^^^^^^^^^^^^^
error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing
--> $DIR/drop_ref.rs:93:14
|
LL | 3 if drop(println_and(&14)) == () => (), // Lint, idiomatic use is only in body of `Arm`
| ^^^^^^^^^^^^^^^^^^^^^^
|
note: argument has type `&i32`
--> $DIR/drop_ref.rs:93:19
|
LL | 3 if drop(println_and(&14)) == () => (), // Lint, idiomatic use is only in body of `Arm`
| ^^^^^^^^^^^^^^^^
error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing
--> $DIR/drop_ref.rs:94:14
|
LL | 4 => drop(&2), // Lint, not a fn/method call
| ^^^^^^^^
|
note: argument has type `&i32`
--> $DIR/drop_ref.rs:94:19
|
LL | 4 => drop(&2), // Lint, not a fn/method call
| ^^
error: aborting due to 12 previous errors

View file

@ -247,3 +247,24 @@ mod issue6312 {
}
}
}
struct Collection {
items: Vec<i32>,
len: usize,
}
impl Default for Collection {
fn default() -> Self {
Self {
items: vec![1, 2, 3],
len: 0,
}
}
}
#[allow(clippy::redundant_closure_call)]
fn issue10136() {
let mut c = Collection::default();
// don't lint, since c.items was used to calculate this value
c.len = (|| c.items.len())();
}

View file

@ -1,14 +1,15 @@
// run-rustfix
#![warn(clippy::iter_kv_map)]
#![allow(clippy::redundant_clone)]
#![allow(clippy::suspicious_map)]
#![allow(clippy::map_identity)]
#![allow(unused_mut, clippy::redundant_clone, clippy::suspicious_map, clippy::map_identity)]
use std::collections::{BTreeMap, HashMap};
fn main() {
let get_key = |(key, _val)| key;
fn ref_acceptor(v: &u32) -> u32 {
*v
}
let map: HashMap<u32, u32> = HashMap::new();
@ -36,6 +37,20 @@ fn main() {
let _ = map.keys().map(|key| key * 9).count();
let _ = map.values().map(|value| value * 17).count();
// Preserve the ref in the fix.
let _ = map.clone().into_values().map(|ref val| ref_acceptor(val)).count();
// Preserve the mut in the fix.
let _ = map
.clone().into_values().map(|mut val| {
val += 2;
val
})
.count();
// Don't let a mut interfere.
let _ = map.clone().into_values().count();
let map: BTreeMap<u32, u32> = BTreeMap::new();
let _ = map.keys().collect::<Vec<_>>();
@ -61,4 +76,18 @@ fn main() {
// Lint
let _ = map.keys().map(|key| key * 9).count();
let _ = map.values().map(|value| value * 17).count();
// Preserve the ref in the fix.
let _ = map.clone().into_values().map(|ref val| ref_acceptor(val)).count();
// Preserve the mut in the fix.
let _ = map
.clone().into_values().map(|mut val| {
val += 2;
val
})
.count();
// Don't let a mut interfere.
let _ = map.clone().into_values().count();
}

View file

@ -1,14 +1,15 @@
// run-rustfix
#![warn(clippy::iter_kv_map)]
#![allow(clippy::redundant_clone)]
#![allow(clippy::suspicious_map)]
#![allow(clippy::map_identity)]
#![allow(unused_mut, clippy::redundant_clone, clippy::suspicious_map, clippy::map_identity)]
use std::collections::{BTreeMap, HashMap};
fn main() {
let get_key = |(key, _val)| key;
fn ref_acceptor(v: &u32) -> u32 {
*v
}
let map: HashMap<u32, u32> = HashMap::new();
@ -36,6 +37,22 @@ fn main() {
let _ = map.iter().map(|(key, _value)| key * 9).count();
let _ = map.iter().map(|(_key, value)| value * 17).count();
// Preserve the ref in the fix.
let _ = map.clone().into_iter().map(|(_, ref val)| ref_acceptor(val)).count();
// Preserve the mut in the fix.
let _ = map
.clone()
.into_iter()
.map(|(_, mut val)| {
val += 2;
val
})
.count();
// Don't let a mut interfere.
let _ = map.clone().into_iter().map(|(_, mut val)| val).count();
let map: BTreeMap<u32, u32> = BTreeMap::new();
let _ = map.iter().map(|(key, _)| key).collect::<Vec<_>>();
@ -61,4 +78,20 @@ fn main() {
// Lint
let _ = map.iter().map(|(key, _value)| key * 9).count();
let _ = map.iter().map(|(_key, value)| value * 17).count();
// Preserve the ref in the fix.
let _ = map.clone().into_iter().map(|(_, ref val)| ref_acceptor(val)).count();
// Preserve the mut in the fix.
let _ = map
.clone()
.into_iter()
.map(|(_, mut val)| {
val += 2;
val
})
.count();
// Don't let a mut interfere.
let _ = map.clone().into_iter().map(|(_, mut val)| val).count();
}

View file

@ -1,5 +1,5 @@
error: iterating on a map's keys
--> $DIR/iter_kv_map.rs:15:13
--> $DIR/iter_kv_map.rs:16:13
|
LL | let _ = map.iter().map(|(key, _)| key).collect::<Vec<_>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys()`
@ -7,130 +7,198 @@ LL | let _ = map.iter().map(|(key, _)| key).collect::<Vec<_>>();
= note: `-D clippy::iter-kv-map` implied by `-D warnings`
error: iterating on a map's values
--> $DIR/iter_kv_map.rs:16:13
--> $DIR/iter_kv_map.rs:17:13
|
LL | let _ = map.iter().map(|(_, value)| value).collect::<Vec<_>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values()`
error: iterating on a map's values
--> $DIR/iter_kv_map.rs:17:13
--> $DIR/iter_kv_map.rs:18:13
|
LL | let _ = map.iter().map(|(_, v)| v + 2).collect::<Vec<_>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values().map(|v| v + 2)`
error: iterating on a map's keys
--> $DIR/iter_kv_map.rs:19:13
--> $DIR/iter_kv_map.rs:20:13
|
LL | let _ = map.clone().into_iter().map(|(key, _)| key).collect::<Vec<_>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_keys()`
error: iterating on a map's keys
--> $DIR/iter_kv_map.rs:20:13
--> $DIR/iter_kv_map.rs:21:13
|
LL | let _ = map.clone().into_iter().map(|(key, _)| key + 2).collect::<Vec<_>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_keys().map(|key| key + 2)`
error: iterating on a map's values
--> $DIR/iter_kv_map.rs:22:13
--> $DIR/iter_kv_map.rs:23:13
|
LL | let _ = map.clone().into_iter().map(|(_, val)| val).collect::<Vec<_>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values()`
error: iterating on a map's values
--> $DIR/iter_kv_map.rs:23:13
--> $DIR/iter_kv_map.rs:24:13
|
LL | let _ = map.clone().into_iter().map(|(_, val)| val + 2).collect::<Vec<_>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values().map(|val| val + 2)`
error: iterating on a map's values
--> $DIR/iter_kv_map.rs:25:13
--> $DIR/iter_kv_map.rs:26:13
|
LL | let _ = map.clone().iter().map(|(_, val)| val).collect::<Vec<_>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().values()`
error: iterating on a map's keys
--> $DIR/iter_kv_map.rs:26:13
--> $DIR/iter_kv_map.rs:27:13
|
LL | let _ = map.iter().map(|(key, _)| key).filter(|x| *x % 2 == 0).count();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys()`
error: iterating on a map's keys
--> $DIR/iter_kv_map.rs:36:13
--> $DIR/iter_kv_map.rs:37:13
|
LL | let _ = map.iter().map(|(key, _value)| key * 9).count();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys().map(|key| key * 9)`
error: iterating on a map's values
--> $DIR/iter_kv_map.rs:37:13
--> $DIR/iter_kv_map.rs:38:13
|
LL | let _ = map.iter().map(|(_key, value)| value * 17).count();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values().map(|value| value * 17)`
error: iterating on a map's keys
error: iterating on a map's values
--> $DIR/iter_kv_map.rs:41:13
|
LL | let _ = map.clone().into_iter().map(|(_, ref val)| ref_acceptor(val)).count();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values().map(|ref val| ref_acceptor(val))`
error: iterating on a map's values
--> $DIR/iter_kv_map.rs:44:13
|
LL | let _ = map
| _____________^
LL | | .clone()
LL | | .into_iter()
LL | | .map(|(_, mut val)| {
LL | | val += 2;
LL | | val
LL | | })
| |__________^
|
help: try
|
LL ~ let _ = map
LL + .clone().into_values().map(|mut val| {
LL + val += 2;
LL + val
LL + })
|
error: iterating on a map's values
--> $DIR/iter_kv_map.rs:54:13
|
LL | let _ = map.clone().into_iter().map(|(_, mut val)| val).count();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values()`
error: iterating on a map's keys
--> $DIR/iter_kv_map.rs:58:13
|
LL | let _ = map.iter().map(|(key, _)| key).collect::<Vec<_>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys()`
error: iterating on a map's values
--> $DIR/iter_kv_map.rs:42:13
--> $DIR/iter_kv_map.rs:59:13
|
LL | let _ = map.iter().map(|(_, value)| value).collect::<Vec<_>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values()`
error: iterating on a map's values
--> $DIR/iter_kv_map.rs:43:13
--> $DIR/iter_kv_map.rs:60:13
|
LL | let _ = map.iter().map(|(_, v)| v + 2).collect::<Vec<_>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values().map(|v| v + 2)`
error: iterating on a map's keys
--> $DIR/iter_kv_map.rs:45:13
--> $DIR/iter_kv_map.rs:62:13
|
LL | let _ = map.clone().into_iter().map(|(key, _)| key).collect::<Vec<_>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_keys()`
error: iterating on a map's keys
--> $DIR/iter_kv_map.rs:46:13
--> $DIR/iter_kv_map.rs:63:13
|
LL | let _ = map.clone().into_iter().map(|(key, _)| key + 2).collect::<Vec<_>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_keys().map(|key| key + 2)`
error: iterating on a map's values
--> $DIR/iter_kv_map.rs:48:13
--> $DIR/iter_kv_map.rs:65:13
|
LL | let _ = map.clone().into_iter().map(|(_, val)| val).collect::<Vec<_>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values()`
error: iterating on a map's values
--> $DIR/iter_kv_map.rs:49:13
--> $DIR/iter_kv_map.rs:66:13
|
LL | let _ = map.clone().into_iter().map(|(_, val)| val + 2).collect::<Vec<_>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values().map(|val| val + 2)`
error: iterating on a map's values
--> $DIR/iter_kv_map.rs:51:13
--> $DIR/iter_kv_map.rs:68:13
|
LL | let _ = map.clone().iter().map(|(_, val)| val).collect::<Vec<_>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().values()`
error: iterating on a map's keys
--> $DIR/iter_kv_map.rs:52:13
--> $DIR/iter_kv_map.rs:69:13
|
LL | let _ = map.iter().map(|(key, _)| key).filter(|x| *x % 2 == 0).count();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys()`
error: iterating on a map's keys
--> $DIR/iter_kv_map.rs:62:13
--> $DIR/iter_kv_map.rs:79:13
|
LL | let _ = map.iter().map(|(key, _value)| key * 9).count();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys().map(|key| key * 9)`
error: iterating on a map's values
--> $DIR/iter_kv_map.rs:63:13
--> $DIR/iter_kv_map.rs:80:13
|
LL | let _ = map.iter().map(|(_key, value)| value * 17).count();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values().map(|value| value * 17)`
error: aborting due to 22 previous errors
error: iterating on a map's values
--> $DIR/iter_kv_map.rs:83:13
|
LL | let _ = map.clone().into_iter().map(|(_, ref val)| ref_acceptor(val)).count();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values().map(|ref val| ref_acceptor(val))`
error: iterating on a map's values
--> $DIR/iter_kv_map.rs:86:13
|
LL | let _ = map
| _____________^
LL | | .clone()
LL | | .into_iter()
LL | | .map(|(_, mut val)| {
LL | | val += 2;
LL | | val
LL | | })
| |__________^
|
help: try
|
LL ~ let _ = map
LL + .clone().into_values().map(|mut val| {
LL + val += 2;
LL + val
LL + })
|
error: iterating on a map's values
--> $DIR/iter_kv_map.rs:96:13
|
LL | let _ = map.clone().into_iter().map(|(_, mut val)| val).count();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values()`
error: aborting due to 28 previous errors

View file

@ -1,5 +1,5 @@
// run-rustfix
#![feature(custom_inner_attributes, lint_reasons, rustc_private)]
#![feature(lint_reasons)]
#![allow(
unused,
clippy::uninlined_format_args,
@ -491,14 +491,3 @@ mod issue_9782_method_variant {
S.foo::<&[u8; 100]>(&a);
}
}
extern crate rustc_lint;
extern crate rustc_span;
#[allow(dead_code)]
mod span_lint {
use rustc_lint::{LateContext, Lint, LintContext};
fn foo(cx: &LateContext<'_>, lint: &'static Lint) {
cx.struct_span_lint(lint, rustc_span::Span::default(), "", |diag| diag.note(String::new()));
}
}

View file

@ -1,5 +1,5 @@
// run-rustfix
#![feature(custom_inner_attributes, lint_reasons, rustc_private)]
#![feature(lint_reasons)]
#![allow(
unused,
clippy::uninlined_format_args,
@ -491,14 +491,3 @@ mod issue_9782_method_variant {
S.foo::<&[u8; 100]>(&a);
}
}
extern crate rustc_lint;
extern crate rustc_span;
#[allow(dead_code)]
mod span_lint {
use rustc_lint::{LateContext, Lint, LintContext};
fn foo(cx: &LateContext<'_>, lint: &'static Lint) {
cx.struct_span_lint(lint, rustc_span::Span::default(), "", |diag| diag.note(&String::new()));
}
}

View file

@ -216,11 +216,5 @@ error: the borrowed expression implements the required traits
LL | foo(&a);
| ^^ help: change this to: `a`
error: the borrowed expression implements the required traits
--> $DIR/needless_borrow.rs:502:85
|
LL | cx.struct_span_lint(lint, rustc_span::Span::default(), "", |diag| diag.note(&String::new()));
| ^^^^^^^^^^^^^^ help: change this to: `String::new()`
error: aborting due to 37 previous errors
error: aborting due to 36 previous errors

View file

@ -277,4 +277,14 @@ fn issue9947() -> Result<(), String> {
do yeet "hello";
}
// without anyhow, but triggers the same bug I believe
#[expect(clippy::useless_format)]
fn issue10051() -> Result<String, String> {
if true {
Ok(format!("ok!"))
} else {
Err(format!("err!"))
}
}
fn main() {}

View file

@ -287,4 +287,14 @@ fn issue9947() -> Result<(), String> {
do yeet "hello";
}
// without anyhow, but triggers the same bug I believe
#[expect(clippy::useless_format)]
fn issue10051() -> Result<String, String> {
if true {
return Ok(format!("ok!"));
} else {
return Err(format!("err!"));
}
}
fn main() {}

View file

@ -386,5 +386,21 @@ LL | let _ = 42; return;
|
= help: remove `return`
error: aborting due to 46 previous errors
error: unneeded `return` statement
--> $DIR/needless_return.rs:294:9
|
LL | return Ok(format!("ok!"));
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: remove `return`
error: unneeded `return` statement
--> $DIR/needless_return.rs:296:9
|
LL | return Err(format!("err!"));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: remove `return`
error: aborting due to 48 previous errors

View file

@ -239,9 +239,3 @@ fn false_negative_5707() {
let _z = x.clone(); // pr 7346 can't lint on `x`
drop(y);
}
#[allow(unused, clippy::manual_retain)]
fn possible_borrower_improvements() {
let mut s = String::from("foobar");
s = s.chars().filter(|&c| c != 'o').collect();
}

View file

@ -239,9 +239,3 @@ fn false_negative_5707() {
let _z = x.clone(); // pr 7346 can't lint on `x`
drop(y);
}
#[allow(unused, clippy::manual_retain)]
fn possible_borrower_improvements() {
let mut s = String::from("foobar");
s = s.chars().filter(|&c| c != 'o').to_owned().collect();
}

View file

@ -179,17 +179,5 @@ note: this value is dropped without further use
LL | foo(&x.clone(), move || {
| ^
error: redundant clone
--> $DIR/redundant_clone.rs:246:40
|
LL | s = s.chars().filter(|&c| c != 'o').to_owned().collect();
| ^^^^^^^^^^^ help: remove this
|
note: this value is dropped without further use
--> $DIR/redundant_clone.rs:246:9
|
LL | s = s.chars().filter(|&c| c != 'o').to_owned().collect();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 16 previous errors
error: aborting due to 15 previous errors

View file

@ -10,6 +10,7 @@
#![allow(clippy::box_collection)]
#![allow(clippy::redundant_static_lifetimes)]
#![allow(clippy::cognitive_complexity)]
#![allow(clippy::derived_hash_with_manual_eq)]
#![allow(clippy::disallowed_methods)]
#![allow(clippy::disallowed_types)]
#![allow(clippy::mixed_read_write_in_expression)]
@ -45,6 +46,7 @@
#![warn(clippy::box_collection)]
#![warn(clippy::redundant_static_lifetimes)]
#![warn(clippy::cognitive_complexity)]
#![warn(clippy::derived_hash_with_manual_eq)]
#![warn(clippy::disallowed_methods)]
#![warn(clippy::disallowed_types)]
#![warn(clippy::mixed_read_write_in_expression)]

View file

@ -10,6 +10,7 @@
#![allow(clippy::box_collection)]
#![allow(clippy::redundant_static_lifetimes)]
#![allow(clippy::cognitive_complexity)]
#![allow(clippy::derived_hash_with_manual_eq)]
#![allow(clippy::disallowed_methods)]
#![allow(clippy::disallowed_types)]
#![allow(clippy::mixed_read_write_in_expression)]
@ -45,6 +46,7 @@
#![warn(clippy::box_vec)]
#![warn(clippy::const_static_lifetime)]
#![warn(clippy::cyclomatic_complexity)]
#![warn(clippy::derive_hash_xor_eq)]
#![warn(clippy::disallowed_method)]
#![warn(clippy::disallowed_type)]
#![warn(clippy::eval_order_dependence)]

View file

@ -1,5 +1,5 @@
error: lint `clippy::almost_complete_letter_range` has been renamed to `clippy::almost_complete_range`
--> $DIR/rename.rs:41:9
--> $DIR/rename.rs:42:9
|
LL | #![warn(clippy::almost_complete_letter_range)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::almost_complete_range`
@ -7,244 +7,250 @@ LL | #![warn(clippy::almost_complete_letter_range)]
= note: `-D renamed-and-removed-lints` implied by `-D warnings`
error: lint `clippy::blacklisted_name` has been renamed to `clippy::disallowed_names`
--> $DIR/rename.rs:42:9
--> $DIR/rename.rs:43:9
|
LL | #![warn(clippy::blacklisted_name)]
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_names`
error: lint `clippy::block_in_if_condition_expr` has been renamed to `clippy::blocks_in_if_conditions`
--> $DIR/rename.rs:43:9
--> $DIR/rename.rs:44:9
|
LL | #![warn(clippy::block_in_if_condition_expr)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions`
error: lint `clippy::block_in_if_condition_stmt` has been renamed to `clippy::blocks_in_if_conditions`
--> $DIR/rename.rs:44:9
--> $DIR/rename.rs:45:9
|
LL | #![warn(clippy::block_in_if_condition_stmt)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions`
error: lint `clippy::box_vec` has been renamed to `clippy::box_collection`
--> $DIR/rename.rs:45:9
--> $DIR/rename.rs:46:9
|
LL | #![warn(clippy::box_vec)]
| ^^^^^^^^^^^^^^^ help: use the new name: `clippy::box_collection`
error: lint `clippy::const_static_lifetime` has been renamed to `clippy::redundant_static_lifetimes`
--> $DIR/rename.rs:46:9
--> $DIR/rename.rs:47:9
|
LL | #![warn(clippy::const_static_lifetime)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_static_lifetimes`
error: lint `clippy::cyclomatic_complexity` has been renamed to `clippy::cognitive_complexity`
--> $DIR/rename.rs:47:9
--> $DIR/rename.rs:48:9
|
LL | #![warn(clippy::cyclomatic_complexity)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::cognitive_complexity`
error: lint `clippy::derive_hash_xor_eq` has been renamed to `clippy::derived_hash_with_manual_eq`
--> $DIR/rename.rs:49:9
|
LL | #![warn(clippy::derive_hash_xor_eq)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::derived_hash_with_manual_eq`
error: lint `clippy::disallowed_method` has been renamed to `clippy::disallowed_methods`
--> $DIR/rename.rs:48:9
--> $DIR/rename.rs:50:9
|
LL | #![warn(clippy::disallowed_method)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_methods`
error: lint `clippy::disallowed_type` has been renamed to `clippy::disallowed_types`
--> $DIR/rename.rs:49:9
--> $DIR/rename.rs:51:9
|
LL | #![warn(clippy::disallowed_type)]
| ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_types`
error: lint `clippy::eval_order_dependence` has been renamed to `clippy::mixed_read_write_in_expression`
--> $DIR/rename.rs:50:9
--> $DIR/rename.rs:52:9
|
LL | #![warn(clippy::eval_order_dependence)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::mixed_read_write_in_expression`
error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion`
--> $DIR/rename.rs:51:9
--> $DIR/rename.rs:53:9
|
LL | #![warn(clippy::identity_conversion)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::useless_conversion`
error: lint `clippy::if_let_some_result` has been renamed to `clippy::match_result_ok`
--> $DIR/rename.rs:52:9
--> $DIR/rename.rs:54:9
|
LL | #![warn(clippy::if_let_some_result)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::match_result_ok`
error: lint `clippy::logic_bug` has been renamed to `clippy::overly_complex_bool_expr`
--> $DIR/rename.rs:53:9
--> $DIR/rename.rs:55:9
|
LL | #![warn(clippy::logic_bug)]
| ^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::overly_complex_bool_expr`
error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default`
--> $DIR/rename.rs:54:9
--> $DIR/rename.rs:56:9
|
LL | #![warn(clippy::new_without_default_derive)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default`
error: lint `clippy::option_and_then_some` has been renamed to `clippy::bind_instead_of_map`
--> $DIR/rename.rs:55:9
--> $DIR/rename.rs:57:9
|
LL | #![warn(clippy::option_and_then_some)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::bind_instead_of_map`
error: lint `clippy::option_expect_used` has been renamed to `clippy::expect_used`
--> $DIR/rename.rs:56:9
--> $DIR/rename.rs:58:9
|
LL | #![warn(clippy::option_expect_used)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
error: lint `clippy::option_map_unwrap_or` has been renamed to `clippy::map_unwrap_or`
--> $DIR/rename.rs:57:9
--> $DIR/rename.rs:59:9
|
LL | #![warn(clippy::option_map_unwrap_or)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
error: lint `clippy::option_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or`
--> $DIR/rename.rs:58:9
--> $DIR/rename.rs:60:9
|
LL | #![warn(clippy::option_map_unwrap_or_else)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
error: lint `clippy::option_unwrap_used` has been renamed to `clippy::unwrap_used`
--> $DIR/rename.rs:59:9
--> $DIR/rename.rs:61:9
|
LL | #![warn(clippy::option_unwrap_used)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
error: lint `clippy::ref_in_deref` has been renamed to `clippy::needless_borrow`
--> $DIR/rename.rs:60:9
--> $DIR/rename.rs:62:9
|
LL | #![warn(clippy::ref_in_deref)]
| ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::needless_borrow`
error: lint `clippy::result_expect_used` has been renamed to `clippy::expect_used`
--> $DIR/rename.rs:61:9
--> $DIR/rename.rs:63:9
|
LL | #![warn(clippy::result_expect_used)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
error: lint `clippy::result_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or`
--> $DIR/rename.rs:62:9
--> $DIR/rename.rs:64:9
|
LL | #![warn(clippy::result_map_unwrap_or_else)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
error: lint `clippy::result_unwrap_used` has been renamed to `clippy::unwrap_used`
--> $DIR/rename.rs:63:9
--> $DIR/rename.rs:65:9
|
LL | #![warn(clippy::result_unwrap_used)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
error: lint `clippy::single_char_push_str` has been renamed to `clippy::single_char_add_str`
--> $DIR/rename.rs:64:9
--> $DIR/rename.rs:66:9
|
LL | #![warn(clippy::single_char_push_str)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::single_char_add_str`
error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions`
--> $DIR/rename.rs:65:9
--> $DIR/rename.rs:67:9
|
LL | #![warn(clippy::stutter)]
| ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions`
error: lint `clippy::to_string_in_display` has been renamed to `clippy::recursive_format_impl`
--> $DIR/rename.rs:66:9
--> $DIR/rename.rs:68:9
|
LL | #![warn(clippy::to_string_in_display)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::recursive_format_impl`
error: lint `clippy::zero_width_space` has been renamed to `clippy::invisible_characters`
--> $DIR/rename.rs:67:9
--> $DIR/rename.rs:69:9
|
LL | #![warn(clippy::zero_width_space)]
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::invisible_characters`
error: lint `clippy::drop_bounds` has been renamed to `drop_bounds`
--> $DIR/rename.rs:68:9
--> $DIR/rename.rs:70:9
|
LL | #![warn(clippy::drop_bounds)]
| ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds`
error: lint `clippy::for_loop_over_option` has been renamed to `for_loops_over_fallibles`
--> $DIR/rename.rs:69:9
--> $DIR/rename.rs:71:9
|
LL | #![warn(clippy::for_loop_over_option)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
error: lint `clippy::for_loop_over_result` has been renamed to `for_loops_over_fallibles`
--> $DIR/rename.rs:70:9
--> $DIR/rename.rs:72:9
|
LL | #![warn(clippy::for_loop_over_result)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
error: lint `clippy::for_loops_over_fallibles` has been renamed to `for_loops_over_fallibles`
--> $DIR/rename.rs:71:9
--> $DIR/rename.rs:73:9
|
LL | #![warn(clippy::for_loops_over_fallibles)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter`
--> $DIR/rename.rs:72:9
--> $DIR/rename.rs:74:9
|
LL | #![warn(clippy::into_iter_on_array)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter`
error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering`
--> $DIR/rename.rs:73:9
--> $DIR/rename.rs:75:9
|
LL | #![warn(clippy::invalid_atomic_ordering)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering`
error: lint `clippy::invalid_ref` has been renamed to `invalid_value`
--> $DIR/rename.rs:74:9
--> $DIR/rename.rs:76:9
|
LL | #![warn(clippy::invalid_ref)]
| ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value`
error: lint `clippy::let_underscore_drop` has been renamed to `let_underscore_drop`
--> $DIR/rename.rs:75:9
--> $DIR/rename.rs:77:9
|
LL | #![warn(clippy::let_underscore_drop)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `let_underscore_drop`
error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums`
--> $DIR/rename.rs:76:9
--> $DIR/rename.rs:78:9
|
LL | #![warn(clippy::mem_discriminant_non_enum)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums`
error: lint `clippy::panic_params` has been renamed to `non_fmt_panics`
--> $DIR/rename.rs:77:9
--> $DIR/rename.rs:79:9
|
LL | #![warn(clippy::panic_params)]
| ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics`
error: lint `clippy::positional_named_format_parameters` has been renamed to `named_arguments_used_positionally`
--> $DIR/rename.rs:78:9
--> $DIR/rename.rs:80:9
|
LL | #![warn(clippy::positional_named_format_parameters)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `named_arguments_used_positionally`
error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr`
--> $DIR/rename.rs:79:9
--> $DIR/rename.rs:81:9
|
LL | #![warn(clippy::temporary_cstring_as_ptr)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr`
error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints`
--> $DIR/rename.rs:80:9
--> $DIR/rename.rs:82:9
|
LL | #![warn(clippy::unknown_clippy_lints)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints`
error: lint `clippy::unused_label` has been renamed to `unused_labels`
--> $DIR/rename.rs:81:9
--> $DIR/rename.rs:83:9
|
LL | #![warn(clippy::unused_label)]
| ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels`
error: aborting due to 41 previous errors
error: aborting due to 42 previous errors

View file

@ -33,4 +33,31 @@ fn main() {
let item = 0..5;
dbg!(item);
}
// should not lint (issue #10018)
for e in [42] {
if e > 0 {
continue;
}
}
// should not lint (issue #10018)
for e in [42] {
if e > 0 {
break;
}
}
// should lint (issue #10018)
{
let _ = 42;
let _f = |n: u32| {
for i in 0..n {
if i > 10 {
dbg!(i);
break;
}
}
};
}
}

View file

@ -27,4 +27,30 @@ fn main() {
for item in [0..5].into_iter() {
dbg!(item);
}
// should not lint (issue #10018)
for e in [42] {
if e > 0 {
continue;
}
}
// should not lint (issue #10018)
for e in [42] {
if e > 0 {
break;
}
}
// should lint (issue #10018)
for _ in [42] {
let _f = |n: u32| {
for i in 0..n {
if i > 10 {
dbg!(i);
break;
}
}
};
}
}

View file

@ -95,5 +95,32 @@ LL + dbg!(item);
LL + }
|
error: aborting due to 6 previous errors
error: for loop over a single element
--> $DIR/single_element_loop.rs:46:5
|
LL | / for _ in [42] {
LL | | let _f = |n: u32| {
LL | | for i in 0..n {
LL | | if i > 10 {
... |
LL | | };
LL | | }
| |_____^
|
help: try
|
LL ~ {
LL + let _ = 42;
LL + let _f = |n: u32| {
LL + for i in 0..n {
LL + if i > 10 {
LL + dbg!(i);
LL + break;
LL + }
LL + }
LL + };
LL + }
|
error: aborting due to 7 previous errors

View file

@ -1,4 +1,4 @@
error: this `to_owned` call clones the std::borrow::Cow<'_, str> itself and does not cause the std::borrow::Cow<'_, str> contents to become owned
error: this `to_owned` call clones the Cow<'_, str> itself and does not cause the Cow<'_, str> contents to become owned
--> $DIR/suspicious_to_owned.rs:16:13
|
LL | let _ = cow.to_owned();
@ -6,19 +6,19 @@ LL | let _ = cow.to_owned();
|
= note: `-D clippy::suspicious-to-owned` implied by `-D warnings`
error: this `to_owned` call clones the std::borrow::Cow<'_, [char; 3]> itself and does not cause the std::borrow::Cow<'_, [char; 3]> contents to become owned
error: this `to_owned` call clones the Cow<'_, [char; 3]> itself and does not cause the Cow<'_, [char; 3]> contents to become owned
--> $DIR/suspicious_to_owned.rs:26:13
|
LL | let _ = cow.to_owned();
| ^^^^^^^^^^^^^^ help: consider using, depending on intent: `cow.clone()` or `cow.into_owned()`
error: this `to_owned` call clones the std::borrow::Cow<'_, std::vec::Vec<char>> itself and does not cause the std::borrow::Cow<'_, std::vec::Vec<char>> contents to become owned
error: this `to_owned` call clones the Cow<'_, Vec<char>> itself and does not cause the Cow<'_, Vec<char>> contents to become owned
--> $DIR/suspicious_to_owned.rs:36:13
|
LL | let _ = cow.to_owned();
| ^^^^^^^^^^^^^^ help: consider using, depending on intent: `cow.clone()` or `cow.into_owned()`
error: this `to_owned` call clones the std::borrow::Cow<'_, str> itself and does not cause the std::borrow::Cow<'_, str> contents to become owned
error: this `to_owned` call clones the Cow<'_, str> itself and does not cause the Cow<'_, str> contents to become owned
--> $DIR/suspicious_to_owned.rs:46:13
|
LL | let _ = cow.to_owned();

View file

@ -38,13 +38,13 @@ LL | t.clone();
|
= note: `-D clippy::clone-on-copy` implied by `-D warnings`
error: using `clone` on type `std::option::Option<T>` which implements the `Copy` trait
error: using `clone` on type `Option<T>` which implements the `Copy` trait
--> $DIR/unnecessary_clone.rs:42:5
|
LL | Some(t).clone();
| ^^^^^^^^^^^^^^^ help: try removing the `clone` call: `Some(t)`
error: using `clone` on a double-reference; this will copy the reference of type `&std::vec::Vec<i32>` instead of cloning the inner type
error: using `clone` on a double-reference; this will copy the reference of type `&Vec<i32>` instead of cloning the inner type
--> $DIR/unnecessary_clone.rs:48:22
|
LL | let z: &Vec<_> = y.clone();
@ -57,10 +57,10 @@ LL | let z: &Vec<_> = &(*y).clone();
| ~~~~~~~~~~~~~
help: or try being explicit if you are sure, that you want to clone a reference
|
LL | let z: &Vec<_> = <&std::vec::Vec<i32>>::clone(y);
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
LL | let z: &Vec<_> = <&Vec<i32>>::clone(y);
| ~~~~~~~~~~~~~~~~~~~~~
error: using `clone` on type `many_derefs::E` which implements the `Copy` trait
error: using `clone` on type `E` which implements the `Copy` trait
--> $DIR/unnecessary_clone.rs:84:20
|
LL | let _: E = a.clone();

View file

@ -60,6 +60,16 @@ mod unused_self_allow {
// shouldn't trigger for public methods
pub fn unused_self_move(self) {}
}
pub struct E;
impl E {
// shouldn't trigger if body contains todo!()
pub fn unused_self_todo(self) {
let x = 42;
todo!()
}
}
}
pub use unused_self_allow::D;

View file

@ -4,7 +4,7 @@ error: unused `self` argument
LL | fn unused_self_move(self) {}
| ^^^^
|
= help: consider refactoring to a associated function
= help: consider refactoring to an associated function
= note: `-D clippy::unused-self` implied by `-D warnings`
error: unused `self` argument
@ -13,7 +13,7 @@ error: unused `self` argument
LL | fn unused_self_ref(&self) {}
| ^^^^^
|
= help: consider refactoring to a associated function
= help: consider refactoring to an associated function
error: unused `self` argument
--> $DIR/unused_self.rs:13:32
@ -21,7 +21,7 @@ error: unused `self` argument
LL | fn unused_self_mut_ref(&mut self) {}
| ^^^^^^^^^
|
= help: consider refactoring to a associated function
= help: consider refactoring to an associated function
error: unused `self` argument
--> $DIR/unused_self.rs:14:32
@ -29,7 +29,7 @@ error: unused `self` argument
LL | fn unused_self_pin_ref(self: Pin<&Self>) {}
| ^^^^
|
= help: consider refactoring to a associated function
= help: consider refactoring to an associated function
error: unused `self` argument
--> $DIR/unused_self.rs:15:36
@ -37,7 +37,7 @@ error: unused `self` argument
LL | fn unused_self_pin_mut_ref(self: Pin<&mut Self>) {}
| ^^^^
|
= help: consider refactoring to a associated function
= help: consider refactoring to an associated function
error: unused `self` argument
--> $DIR/unused_self.rs:16:35
@ -45,7 +45,7 @@ error: unused `self` argument
LL | fn unused_self_pin_nested(self: Pin<Arc<Self>>) {}
| ^^^^
|
= help: consider refactoring to a associated function
= help: consider refactoring to an associated function
error: unused `self` argument
--> $DIR/unused_self.rs:17:28
@ -53,7 +53,7 @@ error: unused `self` argument
LL | fn unused_self_box(self: Box<Self>) {}
| ^^^^
|
= help: consider refactoring to a associated function
= help: consider refactoring to an associated function
error: unused `self` argument
--> $DIR/unused_self.rs:18:40
@ -61,7 +61,7 @@ error: unused `self` argument
LL | fn unused_with_other_used_args(&self, x: u8, y: u8) -> u8 {
| ^^^^^
|
= help: consider refactoring to a associated function
= help: consider refactoring to an associated function
error: unused `self` argument
--> $DIR/unused_self.rs:21:37
@ -69,7 +69,7 @@ error: unused `self` argument
LL | fn unused_self_class_method(&self) {
| ^^^^^
|
= help: consider refactoring to a associated function
= help: consider refactoring to an associated function
error: aborting due to 9 previous errors