From faacd55741785b17d6bdbe3f3319ee6e3079ccab Mon Sep 17 00:00:00 2001 From: Ikko Eltociear Ashimine Date: Thu, 5 Oct 2023 00:03:04 +0900 Subject: [PATCH 01/14] Fix typo in attrs.rs documenation -> documentation --- clippy_lints/src/attrs.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs index 0546807bac4fb..db01ddbde04e3 100644 --- a/clippy_lints/src/attrs.rs +++ b/clippy_lints/src/attrs.rs @@ -183,7 +183,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for empty lines after documenation comments. + /// Checks for empty lines after documentation comments. /// /// ### Why is this bad? /// The documentation comment was most likely meant to be an inner attribute or regular comment. @@ -795,7 +795,7 @@ impl EarlyLintPass for EarlyAttributes { /// Check for empty lines after outer attributes. /// -/// Attributes and documenation comments are both considered outer attributes +/// Attributes and documentation comments are both considered outer attributes /// by the AST. However, the average user likely considers them to be different. /// Checking for empty lines after each of these attributes is split into two different /// lints but can share the same logic. From 010a9b1e6056970ad9b50618f485568f49cf962b Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 5 Oct 2023 16:08:07 +1100 Subject: [PATCH 02/14] Rename `Features::active_features`. The word "active" is currently used in two different and confusing ways: - `ACTIVE_FEATURES` actually means "available unstable features" - `Features::active_features` actually means "features declared in the crate's code", which can include feature within `ACTIVE_FEATURES` but also others. (This is also distinct from "enabled" features which includes declared features but also some edition-specific features automatically enabled depending on the edition in use.) This commit changes the `Features::active_features` to `Features::declared_features` which actually matches its meaning. Likewise, `Features::active` becomes `Features::declared`. --- clippy_lints/src/manual_float_methods.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/manual_float_methods.rs b/clippy_lints/src/manual_float_methods.rs index 88db7ae6aece0..15c8417e70284 100644 --- a/clippy_lints/src/manual_float_methods.rs +++ b/clippy_lints/src/manual_float_methods.rs @@ -85,7 +85,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualFloatMethods { if !in_external_macro(cx.sess(), expr.span) && ( matches!(cx.tcx.constness(cx.tcx.hir().enclosing_body_owner(expr.hir_id)), Constness::NotConst) - || cx.tcx.features().active(sym!(const_float_classify)) + || cx.tcx.features().declared(sym!(const_float_classify)) ) && let ExprKind::Binary(kind, lhs, rhs) = expr.kind && let ExprKind::Binary(lhs_kind, lhs_lhs, lhs_rhs) = lhs.kind && let ExprKind::Binary(rhs_kind, rhs_lhs, rhs_rhs) = rhs.kind From 9de3e6c9281e284f81515345330fb74b0c4ad312 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Tue, 26 Sep 2023 23:56:38 -0400 Subject: [PATCH 03/14] Add more diagnostic items for clippy --- clippy_lints/src/await_holding_invalid.rs | 2 +- clippy_lints/src/box_default.rs | 14 +-- clippy_lints/src/casts/cast_ptr_alignment.rs | 19 ++-- .../src/casts/cast_slice_from_raw_parts.rs | 12 +-- clippy_lints/src/create_dir.rs | 4 +- clippy_lints/src/default.rs | 10 +- .../src/default_constructed_unit_structs.rs | 5 +- .../src/default_instead_of_iter_empty.rs | 6 +- clippy_lints/src/exit.rs | 5 +- clippy_lints/src/explicit_write.rs | 28 +++--- clippy_lints/src/from_raw_with_void_ptr.rs | 4 +- clippy_lints/src/instant_subtraction.rs | 6 +- clippy_lints/src/lines_filter_map_ok.rs | 4 +- clippy_lints/src/manual_retain.rs | 2 +- clippy_lints/src/methods/bytecount.rs | 8 +- clippy_lints/src/methods/clone_on_ref_ptr.rs | 19 ++-- .../methods/from_iter_instead_of_collect.rs | 4 +- .../src/methods/inefficient_to_string.rs | 3 +- .../src/methods/iter_out_of_bounds.rs | 10 +- clippy_lints/src/methods/open_options.rs | 8 +- .../src/methods/option_as_ref_deref.rs | 5 +- clippy_lints/src/methods/seek_from_current.rs | 5 +- .../seek_to_start_instead_of_rewind.rs | 6 +- .../methods/suspicious_command_arg_space.rs | 7 +- clippy_lints/src/missing_fields_in_debug.rs | 12 ++- clippy_lints/src/needless_pass_by_value.rs | 4 +- clippy_lints/src/non_canonical_impls.rs | 7 +- .../src/non_octal_unix_permissions.rs | 10 +- .../src/non_send_fields_in_send_ty.rs | 4 +- clippy_lints/src/operators/cmp_owned.rs | 4 +- .../src/permissions_set_readonly_false.rs | 6 +- clippy_lints/src/ptr.rs | 94 ++++++++----------- clippy_lints/src/rc_clone_in_vec_init.rs | 9 +- clippy_lints/src/redundant_clone.rs | 4 +- clippy_lints/src/size_of_in_element_count.rs | 22 ++--- clippy_lints/src/swap_ptr_to_ref.rs | 6 +- clippy_lints/src/unnamed_address.rs | 4 +- clippy_lints/src/unused_peekable.rs | 10 +- clippy_lints/src/useless_conversion.rs | 4 +- clippy_utils/src/higher.rs | 2 +- clippy_utils/src/lib.rs | 2 +- clippy_utils/src/paths.rs | 48 ---------- clippy_utils/src/ty.rs | 6 +- .../unnecessary_def_path_hardcoded_path.rs | 4 +- ...unnecessary_def_path_hardcoded_path.stderr | 4 +- 45 files changed, 191 insertions(+), 271 deletions(-) diff --git a/clippy_lints/src/await_holding_invalid.rs b/clippy_lints/src/await_holding_invalid.rs index 7dd808a7b3b73..accff9b0a34c6 100644 --- a/clippy_lints/src/await_holding_invalid.rs +++ b/clippy_lints/src/await_holding_invalid.rs @@ -287,5 +287,5 @@ fn is_mutex_guard(cx: &LateContext<'_>, def_id: DefId) -> bool { } fn is_refcell_ref(cx: &LateContext<'_>, def_id: DefId) -> bool { - match_def_path(cx, def_id, &paths::REFCELL_REF) || match_def_path(cx, def_id, &paths::REFCELL_REFMUT) + matches!(cx.tcx.get_diagnostic_name(def_id), Some(sym::RefCellRef | sym::RefCellRefMut)) } diff --git a/clippy_lints/src/box_default.rs b/clippy_lints/src/box_default.rs index fa9c525fc08d9..3f1ff66b8cf60 100644 --- a/clippy_lints/src/box_default.rs +++ b/clippy_lints/src/box_default.rs @@ -1,10 +1,10 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::macros::macro_backtrace; use clippy_utils::ty::expr_sig; -use clippy_utils::{get_parent_node, is_default_equivalent, match_path, path_def_id, paths}; +use clippy_utils::{get_parent_node, is_default_equivalent, path_def_id}; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_ty, Visitor}; -use rustc_hir::{Block, Expr, ExprKind, Local, Node, QPath, TyKind}; +use rustc_hir::{def::Res, Block, Expr, ExprKind, Local, Node, QPath, TyKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::print::with_forced_trimmed_paths; @@ -55,7 +55,7 @@ impl LateLintPass<'_> for BoxDefault { expr.span, "`Box::new(_)` of default value", "try", - if is_plain_default(arg_path) || given_type(cx, expr) { + if is_plain_default(cx, arg_path) || given_type(cx, expr) { "Box::default()".into() } else if let Some(arg_ty) = cx.typeck_results().expr_ty(arg).make_suggestable(cx.tcx, true) { with_forced_trimmed_paths!(format!("Box::<{arg_ty}>::default()")) @@ -68,11 +68,13 @@ impl LateLintPass<'_> for BoxDefault { } } -fn is_plain_default(arg_path: &Expr<'_>) -> bool { +fn is_plain_default(cx: &LateContext<'_>, arg_path: &Expr<'_>) -> bool { // we need to match the actual path so we don't match e.g. "u8::default" - if let ExprKind::Path(QPath::Resolved(None, path)) = &arg_path.kind { + if let ExprKind::Path(QPath::Resolved(None, path)) = &arg_path.kind + && let Res::Def(_, def_id) = path.res + { // avoid generic parameters - match_path(path, &paths::DEFAULT_TRAIT_METHOD) && path.segments.iter().all(|seg| seg.args.is_none()) + cx.tcx.is_diagnostic_item(sym::default_fn, def_id) && path.segments.iter().all(|seg| seg.args.is_none()) } else { false } diff --git a/clippy_lints/src/casts/cast_ptr_alignment.rs b/clippy_lints/src/casts/cast_ptr_alignment.rs index 1de69122101c5..9e8ef28253741 100644 --- a/clippy_lints/src/casts/cast_ptr_alignment.rs +++ b/clippy_lints/src/casts/cast_ptr_alignment.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::ty::is_c_void; -use clippy_utils::{get_parent_expr, is_hir_ty_cfg_dependant, match_any_def_paths, paths}; +use clippy_utils::{get_parent_expr, is_hir_ty_cfg_dependant}; use rustc_hir::{Expr, ExprKind, GenericArg}; use rustc_lint::LateContext; use rustc_middle::ty::layout::LayoutOf; @@ -75,16 +75,17 @@ fn is_used_as_unaligned(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { } }, ExprKind::Call(func, [arg, ..]) if arg.hir_id == e.hir_id => { - static PATHS: &[&[&str]] = &[ - paths::PTR_READ_UNALIGNED.as_slice(), - paths::PTR_UNALIGNED_VOLATILE_LOAD.as_slice(), - paths::PTR_UNALIGNED_VOLATILE_STORE.as_slice(), - ]; - if let ExprKind::Path(path) = &func.kind && let Some(def_id) = cx.qpath_res(path, func.hir_id).opt_def_id() - && (match_any_def_paths(cx, def_id, PATHS).is_some() - || cx.tcx.is_diagnostic_item(sym::ptr_write_unaligned, def_id)) + && matches!( + cx.tcx.get_diagnostic_name(def_id), + Some( + sym::ptr_write_unaligned + | sym::ptr_read_unaligned + | sym::intrinsics_unaligned_volatile_load + | sym::intrinsics_unaligned_volatile_store + ) + ) { true } else { diff --git a/clippy_lints/src/casts/cast_slice_from_raw_parts.rs b/clippy_lints/src/casts/cast_slice_from_raw_parts.rs index 5e0123842b041..eb0f75b2f605b 100644 --- a/clippy_lints/src/casts/cast_slice_from_raw_parts.rs +++ b/clippy_lints/src/casts/cast_slice_from_raw_parts.rs @@ -1,13 +1,13 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_context; -use clippy_utils::{match_def_path, paths}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::def_id::DefId; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; use rustc_middle::ty::{self, Ty}; +use rustc_span::sym; use super::CAST_SLICE_FROM_RAW_PARTS; @@ -17,12 +17,10 @@ enum RawPartsKind { } fn raw_parts_kind(cx: &LateContext<'_>, did: DefId) -> Option { - if match_def_path(cx, did, &paths::SLICE_FROM_RAW_PARTS) { - Some(RawPartsKind::Immutable) - } else if match_def_path(cx, did, &paths::SLICE_FROM_RAW_PARTS_MUT) { - Some(RawPartsKind::Mutable) - } else { - None + match cx.tcx.get_diagnostic_name(did)? { + sym::slice_from_raw_parts => Some(RawPartsKind::Immutable), + sym::slice_from_raw_parts_mut => Some(RawPartsKind::Mutable), + _ => None, } } diff --git a/clippy_lints/src/create_dir.rs b/clippy_lints/src/create_dir.rs index 878248a6bdc8c..2bca695c43b15 100644 --- a/clippy_lints/src/create_dir.rs +++ b/clippy_lints/src/create_dir.rs @@ -1,11 +1,11 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; -use clippy_utils::{match_def_path, paths}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::sym; declare_clippy_lint! { /// ### What it does @@ -37,7 +37,7 @@ impl LateLintPass<'_> for CreateDir { if let ExprKind::Call(func, [arg, ..]) = expr.kind; if let ExprKind::Path(ref path) = func.kind; if let Some(def_id) = cx.qpath_res(path, func.hir_id).opt_def_id(); - if match_def_path(cx, def_id, &paths::STD_FS_CREATE_DIR); + if cx.tcx.is_diagnostic_item(sym::fs_create_dir, def_id); then { span_lint_and_sugg( cx, diff --git a/clippy_lints/src/default.rs b/clippy_lints/src/default.rs index 763ad0264ad91..5787f19cc6cb1 100644 --- a/clippy_lints/src/default.rs +++ b/clippy_lints/src/default.rs @@ -1,9 +1,7 @@ use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_sugg}; use clippy_utils::source::snippet_with_context; use clippy_utils::ty::{has_drop, is_copy}; -use clippy_utils::{ - any_parent_is_automatically_derived, contains_name, get_parent_expr, is_from_proc_macro, match_def_path, paths, -}; +use clippy_utils::{any_parent_is_automatically_derived, contains_name, get_parent_expr, is_from_proc_macro}; use if_chain::if_chain; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; @@ -14,7 +12,7 @@ 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; +use rustc_span::{sym, Span}; declare_clippy_lint! { /// ### What it does @@ -91,7 +89,7 @@ impl<'tcx> LateLintPass<'tcx> for Default { if !any_parent_is_automatically_derived(cx.tcx, expr.hir_id); if let ExprKind::Path(ref qpath) = path.kind; if let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id(); - if match_def_path(cx, def_id, &paths::DEFAULT_TRAIT_METHOD); + if cx.tcx.is_diagnostic_item(sym::default_fn, def_id); if !is_update_syntax_base(cx, expr); // Detect and ignore ::default() because these calls do explicitly name the type. if let QPath::Resolved(None, _path) = qpath; @@ -268,7 +266,7 @@ fn is_expr_default<'tcx>(expr: &'tcx Expr<'tcx>, cx: &LateContext<'tcx>) -> bool if let Res::Def(_, def_id) = cx.qpath_res(qpath, fn_expr.hir_id); then { // right hand side of assignment is `Default::default` - match_def_path(cx, def_id, &paths::DEFAULT_TRAIT_METHOD) + cx.tcx.is_diagnostic_item(sym::default_fn, def_id) } else { false } diff --git a/clippy_lints/src/default_constructed_unit_structs.rs b/clippy_lints/src/default_constructed_unit_structs.rs index a294c69378774..0676777e79681 100644 --- a/clippy_lints/src/default_constructed_unit_structs.rs +++ b/clippy_lints/src/default_constructed_unit_structs.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::{is_ty_alias, match_def_path, paths}; +use clippy_utils::is_ty_alias; use hir::def::Res; use hir::ExprKind; use rustc_errors::Applicability; @@ -7,6 +7,7 @@ use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::sym; declare_clippy_lint! { /// ### What it does @@ -63,7 +64,7 @@ impl LateLintPass<'_> for DefaultConstructedUnitStructs { // `::Assoc` cannot be used as a constructor if !is_alias(*base); if let Res::Def(_, def_id) = cx.qpath_res(qpath, fn_expr.hir_id); - if match_def_path(cx, def_id, &paths::DEFAULT_TRAIT_METHOD); + if cx.tcx.is_diagnostic_item(sym::default_fn, def_id); // make sure we have a struct with no fields (unit struct) if let ty::Adt(def, ..) = cx.typeck_results().expr_ty(expr).kind(); if def.is_struct(); diff --git a/clippy_lints/src/default_instead_of_iter_empty.rs b/clippy_lints/src/default_instead_of_iter_empty.rs index 572990aaba109..3d6d257e386b5 100644 --- a/clippy_lints/src/default_instead_of_iter_empty.rs +++ b/clippy_lints/src/default_instead_of_iter_empty.rs @@ -1,11 +1,11 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_context; -use clippy_utils::{last_path_segment, match_def_path, paths}; +use clippy_utils::last_path_segment; use rustc_errors::Applicability; use rustc_hir::{def, Expr, ExprKind, GenericArg, QPath, TyKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::SyntaxContext; +use rustc_span::{sym, SyntaxContext}; declare_clippy_lint! { /// ### What it does @@ -37,7 +37,7 @@ impl<'tcx> LateLintPass<'tcx> for DefaultIterEmpty { && let TyKind::Path(ty_path) = &ty.kind && let QPath::Resolved(None, path) = ty_path && let def::Res::Def(_, def_id) = &path.res - && match_def_path(cx, *def_id, &paths::ITER_EMPTY) + && cx.tcx.is_diagnostic_item(sym::IterEmpty, *def_id) && let ctxt = expr.span.ctxt() && ty.span.ctxt() == ctxt { diff --git a/clippy_lints/src/exit.rs b/clippy_lints/src/exit.rs index 8ba6a9e48763f..5de79133c7dcc 100644 --- a/clippy_lints/src/exit.rs +++ b/clippy_lints/src/exit.rs @@ -1,9 +1,10 @@ use clippy_utils::diagnostics::span_lint; -use clippy_utils::{is_entrypoint_fn, match_def_path, paths}; +use clippy_utils::{is_entrypoint_fn}; use if_chain::if_chain; use rustc_hir::{Expr, ExprKind, Item, ItemKind, Node}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::sym; declare_clippy_lint! { /// ### What it does @@ -45,7 +46,7 @@ impl<'tcx> LateLintPass<'tcx> for Exit { if let ExprKind::Call(path_expr, _args) = e.kind; if let ExprKind::Path(ref path) = path_expr.kind; if let Some(def_id) = cx.qpath_res(path, path_expr.hir_id).opt_def_id(); - if match_def_path(cx, def_id, &paths::EXIT); + if cx.tcx.is_diagnostic_item(sym::process_exit, def_id); let parent = cx.tcx.hir().get_parent_item(e.hir_id).def_id; if let Some(Node::Item(Item{kind: ItemKind::Fn(..), ..})) = cx.tcx.hir().find_by_def_id(parent); // If the next item up is a function we check if it is an entry point diff --git a/clippy_lints/src/explicit_write.rs b/clippy_lints/src/explicit_write.rs index b612cc00bf97e..6f6177340f487 100644 --- a/clippy_lints/src/explicit_write.rs +++ b/clippy_lints/src/explicit_write.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::macros::{find_format_args, format_args_inputs_span}; use clippy_utils::source::snippet_with_applicability; -use clippy_utils::{is_expn_of, match_function_call, paths}; +use clippy_utils::{is_expn_of, path_def_id}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::def::Res; @@ -47,18 +47,19 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitWrite { if let ExprKind::MethodCall(unwrap_fun, write_call, [], _) = expr.kind && unwrap_fun.ident.name == sym::unwrap // match call to write_fmt - && let ExprKind::MethodCall(write_fun, write_recv, [write_arg], _) = look_in_block(cx, &write_call.kind) + && let ExprKind::MethodCall(write_fun, write_recv, [write_arg], _) = *look_in_block(cx, &write_call.kind) + && let ExprKind::Call(write_recv_path, _) = write_recv.kind && write_fun.ident.name == sym!(write_fmt) - // match calls to std::io::stdout() / std::io::stderr () - && let Some(dest_name) = if match_function_call(cx, write_recv, &paths::STDOUT).is_some() { - Some("stdout") - } else if match_function_call(cx, write_recv, &paths::STDERR).is_some() { - Some("stderr") - } else { - None - } - && let Some(format_args) = find_format_args(cx, write_arg, ExpnId::root()) + && let Some(def_id) = path_def_id(cx, write_recv_path) { + // match calls to std::io::stdout() / std::io::stderr () + let (dest_name, prefix) = match cx.tcx.get_diagnostic_name(def_id) { + Some(sym::io_stdout) => ("stdout", ""), + Some(sym::io_stderr) => ("stderr", "e"), + _ => return, + }; + let Some(format_args) = find_format_args(cx, write_arg, ExpnId::root()) else { return; }; + // ordering is important here, since `writeln!` uses `write!` internally let calling_macro = if is_expn_of(write_call.span, "writeln").is_some() { Some("writeln") @@ -67,11 +68,6 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitWrite { } else { None }; - let prefix = if dest_name == "stderr" { - "e" - } else { - "" - }; // We need to remove the last trailing newline from the string because the // underlying `fmt::write` function doesn't know whether `println!` or `print!` was diff --git a/clippy_lints/src/from_raw_with_void_ptr.rs b/clippy_lints/src/from_raw_with_void_ptr.rs index 5e859d97c6242..d82ea6d2fc80e 100644 --- a/clippy_lints/src/from_raw_with_void_ptr.rs +++ b/clippy_lints/src/from_raw_with_void_ptr.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::ty::is_c_void; -use clippy_utils::{match_def_path, path_def_id, paths}; +use clippy_utils::path_def_id; use rustc_hir::def_id::DefId; use rustc_hir::{Expr, ExprKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; @@ -68,7 +68,7 @@ fn def_id_matches_type(cx: &LateContext<'_>, def_id: DefId) -> Option<&'static s } } - if match_def_path(cx, def_id, &paths::WEAK_RC) || match_def_path(cx, def_id, &paths::WEAK_ARC) { + if matches!(cx.tcx.get_diagnostic_name(def_id), Some(sym::RcWeak | sym::ArcWeak)) { Some("Weak") } else { None diff --git a/clippy_lints/src/instant_subtraction.rs b/clippy_lints/src/instant_subtraction.rs index 8df7dfb8b9e5a..a1a115f6d79f6 100644 --- a/clippy_lints/src/instant_subtraction.rs +++ b/clippy_lints/src/instant_subtraction.rs @@ -130,11 +130,7 @@ fn is_instant_now_call(cx: &LateContext<'_>, expr_block: &'_ Expr<'_>) -> bool { fn is_an_instant(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { let expr_ty = cx.typeck_results().expr_ty(expr); - - match expr_ty.kind() { - rustc_middle::ty::Adt(def, _) => clippy_utils::match_def_path(cx, def.did(), &clippy_utils::paths::INSTANT), - _ => false, - } + ty::is_type_diagnostic_item(cx, expr_ty, sym::Instant) } fn is_a_duration(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { diff --git a/clippy_lints/src/lines_filter_map_ok.rs b/clippy_lints/src/lines_filter_map_ok.rs index 49425ff0a8e05..ac949b6726095 100644 --- a/clippy_lints/src/lines_filter_map_ok.rs +++ b/clippy_lints/src/lines_filter_map_ok.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::ty::match_type; +use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::{is_diag_item_method, is_trait_method, match_def_path, path_to_local_id, paths}; use rustc_errors::Applicability; use rustc_hir::{Body, Closure, Expr, ExprKind}; @@ -62,7 +62,7 @@ impl LateLintPass<'_> for LinesFilterMapOk { if let ExprKind::MethodCall(fm_method, fm_receiver, [fm_arg], fm_span) = expr.kind && is_trait_method(cx, expr, sym::Iterator) && (fm_method.ident.as_str() == "filter_map" || fm_method.ident.as_str() == "flat_map") && - match_type(cx, cx.typeck_results().expr_ty_adjusted(fm_receiver), &paths::STD_IO_LINES) + is_type_diagnostic_item(cx, cx.typeck_results().expr_ty_adjusted(fm_receiver), sym::IoLines) { let lint = match &fm_arg.kind { // Detect `Result::ok` diff --git a/clippy_lints/src/manual_retain.rs b/clippy_lints/src/manual_retain.rs index 1a69a48c582b0..f923413f4348b 100644 --- a/clippy_lints/src/manual_retain.rs +++ b/clippy_lints/src/manual_retain.rs @@ -135,7 +135,7 @@ fn check_to_owned( if msrv.meets(msrvs::STRING_RETAIN) && let hir::ExprKind::MethodCall(_, filter_expr, [], _) = &target_expr.kind && let Some(to_owned_def_id) = cx.typeck_results().type_dependent_def_id(target_expr.hir_id) - && match_def_path(cx, to_owned_def_id, &paths::TO_OWNED_METHOD) + && cx.tcx.is_diagnostic_item(sym::to_owned_method, to_owned_def_id) && let hir::ExprKind::MethodCall(_, chars_expr, [_], _) = &filter_expr.kind && let Some(filter_def_id) = cx.typeck_results().type_dependent_def_id(filter_expr.hir_id) && match_def_path(cx, filter_def_id, &paths::CORE_ITER_FILTER) diff --git a/clippy_lints/src/methods/bytecount.rs b/clippy_lints/src/methods/bytecount.rs index f490a71755407..35370355f8340 100644 --- a/clippy_lints/src/methods/bytecount.rs +++ b/clippy_lints/src/methods/bytecount.rs @@ -1,8 +1,8 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; -use clippy_utils::ty::match_type; +use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::visitors::is_local_used; -use clippy_utils::{path_to_local_id, paths, peel_blocks, peel_ref_operators, strip_pat_refs}; +use clippy_utils::{path_to_local_id, peel_blocks, peel_ref_operators, strip_pat_refs}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Closure, Expr, ExprKind, PatKind}; @@ -25,9 +25,9 @@ pub(super) fn check<'tcx>( if let PatKind::Binding(_, arg_id, _, _) = strip_pat_refs(param.pat).kind; if let ExprKind::Binary(ref op, l, r) = body.value.kind; if op.node == BinOpKind::Eq; - if match_type(cx, + if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(filter_recv).peel_refs(), - &paths::SLICE_ITER); + sym::SliceIter); let operand_is_arg = |expr| { let expr = peel_ref_operators(cx, peel_blocks(expr)); path_to_local_id(expr, arg_id) diff --git a/clippy_lints/src/methods/clone_on_ref_ptr.rs b/clippy_lints/src/methods/clone_on_ref_ptr.rs index ddf3c9f27df29..926bd06bacbd2 100644 --- a/clippy_lints/src/methods/clone_on_ref_ptr.rs +++ b/clippy_lints/src/methods/clone_on_ref_ptr.rs @@ -1,7 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::paths; use clippy_utils::source::snippet_with_context; -use clippy_utils::ty::{is_type_diagnostic_item, match_type}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; @@ -22,15 +20,14 @@ pub(super) fn check( } let obj_ty = cx.typeck_results().expr_ty(receiver).peel_refs(); - if let ty::Adt(_, subst) = obj_ty.kind() { - let caller_type = if is_type_diagnostic_item(cx, obj_ty, sym::Rc) { - "Rc" - } else if is_type_diagnostic_item(cx, obj_ty, sym::Arc) { - "Arc" - } else if match_type(cx, obj_ty, &paths::WEAK_RC) || match_type(cx, obj_ty, &paths::WEAK_ARC) { - "Weak" - } else { - return; + if let ty::Adt(adt, subst) = obj_ty.kind() + && let Some(name) = cx.tcx.get_diagnostic_name(adt.did()) + { + let caller_type = match name { + sym::Rc => "Rc", + sym::Arc => "Arc", + sym::RcWeak | sym::ArcWeak => "Weak", + _ => return, }; // Sometimes unnecessary ::<_> after Rc/Arc/Weak diff --git a/clippy_lints/src/methods/from_iter_instead_of_collect.rs b/clippy_lints/src/methods/from_iter_instead_of_collect.rs index 66dfce3682b59..4040d3a5fe13b 100644 --- a/clippy_lints/src/methods/from_iter_instead_of_collect.rs +++ b/clippy_lints/src/methods/from_iter_instead_of_collect.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_opt; use clippy_utils::ty::implements_trait; -use clippy_utils::{is_expr_path_def_path, paths, sugg}; +use clippy_utils::{is_path_diagnostic_item, sugg}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; @@ -13,7 +13,7 @@ use super::FROM_ITER_INSTEAD_OF_COLLECT; pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>], func: &hir::Expr<'_>) { if_chain! { - if is_expr_path_def_path(cx, func, &paths::FROM_ITERATOR_METHOD); + if is_path_diagnostic_item(cx, func, sym::from_iter_fn); let ty = cx.typeck_results().expr_ty(expr); let arg_ty = cx.typeck_results().expr_ty(&args[0]); if let Some(iter_id) = cx.tcx.get_diagnostic_item(sym::Iterator); diff --git a/clippy_lints/src/methods/inefficient_to_string.rs b/clippy_lints/src/methods/inefficient_to_string.rs index 631741d9290c8..6686d42c95f83 100644 --- a/clippy_lints/src/methods/inefficient_to_string.rs +++ b/clippy_lints/src/methods/inefficient_to_string.rs @@ -1,7 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::{is_type_lang_item, walk_ptrs_ty_depth}; -use clippy_utils::{match_def_path, paths}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; @@ -22,7 +21,7 @@ pub fn check( if_chain! { if args.is_empty() && method_name == sym::to_string; if let Some(to_string_meth_did) = cx.typeck_results().type_dependent_def_id(expr.hir_id); - if match_def_path(cx, to_string_meth_did, &paths::TO_STRING_METHOD); + if cx.tcx.is_diagnostic_item(sym::to_string_method, to_string_meth_did); if let Some(args) = cx.typeck_results().node_args_opt(expr.hir_id); let arg_ty = cx.typeck_results().expr_ty_adjusted(receiver); let self_ty = args.type_at(0); diff --git a/clippy_lints/src/methods/iter_out_of_bounds.rs b/clippy_lints/src/methods/iter_out_of_bounds.rs index 79c6d63254b28..99ea7f03df4e7 100644 --- a/clippy_lints/src/methods/iter_out_of_bounds.rs +++ b/clippy_lints/src/methods/iter_out_of_bounds.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_note; use clippy_utils::higher::VecArgs; -use clippy_utils::{expr_or_init, is_trait_method, match_def_path, paths}; +use clippy_utils::{expr_or_init, is_trait_method}; use rustc_ast::LitKind; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; @@ -26,14 +26,14 @@ fn get_iterator_length<'tcx>(cx: &LateContext<'tcx>, iter: &'tcx Expr<'tcx>) -> }; let did = adt.did(); - if match_def_path(cx, did, &paths::ARRAY_INTO_ITER) { + if cx.tcx.is_diagnostic_item(sym::ArrayIntoIter, did) { // For array::IntoIter, the length is the second generic // parameter. substs .const_at(1) .try_eval_target_usize(cx.tcx, cx.param_env) .map(u128::from) - } else if match_def_path(cx, did, &paths::SLICE_ITER) + } else if cx.tcx.is_diagnostic_item(sym::SliceIter, did) && let ExprKind::MethodCall(_, recv, ..) = iter.kind { if let ty::Array(_, len) = cx.typeck_results().expr_ty(recv).peel_refs().kind() { @@ -47,9 +47,9 @@ fn get_iterator_length<'tcx>(cx: &LateContext<'tcx>, iter: &'tcx Expr<'tcx>) -> } else { None } - } else if match_def_path(cx, did, &paths::ITER_EMPTY) { + } else if cx.tcx.is_diagnostic_item(sym::IterEmpty, did) { Some(0) - } else if match_def_path(cx, did, &paths::ITER_ONCE) { + } else if cx.tcx.is_diagnostic_item(sym::IterOnce, did) { Some(1) } else { None diff --git a/clippy_lints/src/methods/open_options.rs b/clippy_lints/src/methods/open_options.rs index 1c664e76d74f5..c0f5a27994515 100644 --- a/clippy_lints/src/methods/open_options.rs +++ b/clippy_lints/src/methods/open_options.rs @@ -1,17 +1,17 @@ use clippy_utils::diagnostics::span_lint; -use clippy_utils::paths; -use clippy_utils::ty::match_type; +use clippy_utils::ty::is_type_diagnostic_item; use rustc_ast::ast::LitKind; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; use rustc_span::source_map::{Span, Spanned}; +use rustc_span::sym; use super::NONSENSICAL_OPEN_OPTIONS; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, recv: &'tcx Expr<'_>) { if let Some(method_id) = cx.typeck_results().type_dependent_def_id(e.hir_id) && let Some(impl_id) = cx.tcx.impl_of_method(method_id) - && match_type(cx, cx.tcx.type_of(impl_id).instantiate_identity(), &paths::OPEN_OPTIONS) + && is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id).instantiate_identity(), sym::FsOpenOptions) { let mut options = Vec::new(); get_open_options(cx, recv, &mut options); @@ -40,7 +40,7 @@ fn get_open_options(cx: &LateContext<'_>, argument: &Expr<'_>, options: &mut Vec let obj_ty = cx.typeck_results().expr_ty(receiver).peel_refs(); // Only proceed if this is a call on some object of type std::fs::OpenOptions - if match_type(cx, obj_ty, &paths::OPEN_OPTIONS) && !arguments.is_empty() { + if is_type_diagnostic_item(cx, obj_ty, sym::FsOpenOptions) && !arguments.is_empty() { let argument_option = match arguments[0].kind { ExprKind::Lit(span) => { if let Spanned { diff --git a/clippy_lints/src/methods/option_as_ref_deref.rs b/clippy_lints/src/methods/option_as_ref_deref.rs index 3e33f9193374e..d0c27f9631f7a 100644 --- a/clippy_lints/src/methods/option_as_ref_deref.rs +++ b/clippy_lints/src/methods/option_as_ref_deref.rs @@ -32,8 +32,7 @@ pub(super) fn check( return; } - let deref_aliases: [&[&str]; 8] = [ - &paths::DEREF_MUT_TRAIT_METHOD, + let deref_aliases: [&[&str]; 7] = [ &paths::CSTRING_AS_C_STR, &paths::OS_STRING_AS_OS_STR, &paths::PATH_BUF_AS_PATH, @@ -49,6 +48,7 @@ pub(super) fn check( .opt_def_id() .map_or(false, |fun_def_id| { cx.tcx.is_diagnostic_item(sym::deref_method, fun_def_id) + || cx.tcx.is_diagnostic_item(sym::deref_mut_method, fun_def_id) || deref_aliases.iter().any(|path| match_def_path(cx, fun_def_id, path)) }) }, @@ -70,6 +70,7 @@ pub(super) fn check( then { let method_did = cx.typeck_results().type_dependent_def_id(closure_expr.hir_id).unwrap(); cx.tcx.is_diagnostic_item(sym::deref_method, method_did) + || cx.tcx.is_diagnostic_item(sym::deref_mut_method, method_did) || deref_aliases.iter().any(|path| match_def_path(cx, method_did, path)) } else { false diff --git a/clippy_lints/src/methods/seek_from_current.rs b/clippy_lints/src/methods/seek_from_current.rs index f3d6a15ede01b..4ea87027a9e6f 100644 --- a/clippy_lints/src/methods/seek_from_current.rs +++ b/clippy_lints/src/methods/seek_from_current.rs @@ -2,18 +2,19 @@ use rustc_ast::ast::{LitIntType, LitKind}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; +use rustc_span::sym; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::implements_trait; -use clippy_utils::{get_trait_def_id, match_def_path, paths}; +use clippy_utils::{match_def_path, paths}; use super::SEEK_FROM_CURRENT; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, recv: &'tcx Expr<'_>, arg: &'tcx Expr<'_>) { let ty = cx.typeck_results().expr_ty(recv); - if let Some(def_id) = get_trait_def_id(cx, &paths::STD_IO_SEEK) { + if let Some(def_id) = cx.tcx.get_diagnostic_item(sym::IoSeek) { if implements_trait(cx, ty, def_id, &[]) && arg_is_seek_from_current(cx, arg) { let mut applicability = Applicability::MachineApplicable; let snip = snippet_with_applicability(cx, recv.span, "..", &mut applicability); diff --git a/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs b/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs index 787e9e0ebd245..50d4de7a68007 100644 --- a/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs +++ b/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs @@ -1,11 +1,11 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::ty::implements_trait; -use clippy_utils::{get_trait_def_id, is_expr_used_or_unified, match_def_path, paths}; +use clippy_utils::{is_expr_used_or_unified, match_def_path, paths}; use rustc_ast::ast::{LitIntType, LitKind}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; -use rustc_span::Span; +use rustc_span::{sym, Span}; use super::SEEK_TO_START_INSTEAD_OF_REWIND; @@ -23,7 +23,7 @@ pub(super) fn check<'tcx>( return; } - if let Some(seek_trait_id) = get_trait_def_id(cx, &paths::STD_IO_SEEK) && + if let Some(seek_trait_id) = cx.tcx.get_diagnostic_item(sym::IoSeek) && implements_trait(cx, ty, seek_trait_id, &[]) && let ExprKind::Call(func, args1) = arg.kind && let ExprKind::Path(ref path) = func.kind && diff --git a/clippy_lints/src/methods/suspicious_command_arg_space.rs b/clippy_lints/src/methods/suspicious_command_arg_space.rs index bc8f017676415..8959e2c1d75f7 100644 --- a/clippy_lints/src/methods/suspicious_command_arg_space.rs +++ b/clippy_lints/src/methods/suspicious_command_arg_space.rs @@ -1,9 +1,8 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::paths; -use clippy_utils::ty::match_type; +use clippy_utils::ty::is_type_diagnostic_item; use rustc_errors::{Applicability, Diagnostic}; use rustc_lint::LateContext; -use rustc_span::Span; +use rustc_span::{sym, Span}; use {rustc_ast as ast, rustc_hir as hir}; use super::SUSPICIOUS_COMMAND_ARG_SPACE; @@ -11,7 +10,7 @@ use super::SUSPICIOUS_COMMAND_ARG_SPACE; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, recv: &'tcx hir::Expr<'_>, arg: &'tcx hir::Expr<'_>, span: Span) { let ty = cx.typeck_results().expr_ty(recv).peel_refs(); - if match_type(cx, ty, &paths::STD_PROCESS_COMMAND) + if is_type_diagnostic_item(cx, ty, sym::Command) && let hir::ExprKind::Lit(lit) = &arg.kind && let ast::LitKind::Str(s, _) = &lit.node && let Some((arg1, arg2)) = s.as_str().split_once(' ') diff --git a/clippy_lints/src/missing_fields_in_debug.rs b/clippy_lints/src/missing_fields_in_debug.rs index 2f63b9b9f0b8e..f0b865be8042d 100644 --- a/clippy_lints/src/missing_fields_in_debug.rs +++ b/clippy_lints/src/missing_fields_in_debug.rs @@ -1,9 +1,9 @@ use std::ops::ControlFlow; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::ty::match_type; +use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::visitors::{for_each_expr, Visitable}; -use clippy_utils::{is_path_lang_item, paths}; +use clippy_utils::is_path_lang_item; use rustc_ast::LitKind; use rustc_data_structures::fx::FxHashSet; use rustc_hir::def::{DefKind, Res}; @@ -114,9 +114,11 @@ fn should_lint<'tcx>( if let ExprKind::MethodCall(path, recv, ..) = &expr.kind { let recv_ty = typeck_results.expr_ty(recv).peel_refs(); - if path.ident.name == sym::debug_struct && match_type(cx, recv_ty, &paths::FORMATTER) { + if path.ident.name == sym::debug_struct && is_type_diagnostic_item(cx, recv_ty, sym::Formatter) { has_debug_struct = true; - } else if path.ident.name == sym!(finish_non_exhaustive) && match_type(cx, recv_ty, &paths::DEBUG_STRUCT) { + } else if path.ident.name == sym!(finish_non_exhaustive) + && is_type_diagnostic_item(cx, recv_ty, sym::DebugStruct) + { has_finish_non_exhaustive = true; } } @@ -137,7 +139,7 @@ fn as_field_call<'tcx>( ) -> Option { if let ExprKind::MethodCall(path, recv, [debug_field, _], _) = &expr.kind && let recv_ty = typeck_results.expr_ty(recv).peel_refs() - && match_type(cx, recv_ty, &paths::DEBUG_STRUCT) + && is_type_diagnostic_item(cx, recv_ty, sym::DebugStruct) && path.ident.name == sym::field && let ExprKind::Lit(lit) = &debug_field.kind && let LitKind::Str(sym, ..) = lit.node diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs index 5ee26966fa716..6d7df2eac6291 100644 --- a/clippy_lints/src/needless_pass_by_value.rs +++ b/clippy_lints/src/needless_pass_by_value.rs @@ -4,7 +4,7 @@ use clippy_utils::source::{snippet, snippet_opt}; use clippy_utils::ty::{ implements_trait, implements_trait_with_env_from_iter, is_copy, is_type_diagnostic_item, is_type_lang_item, }; -use clippy_utils::{get_trait_def_id, is_self, paths}; +use clippy_utils::is_self; use if_chain::if_chain; use rustc_ast::ast::Attribute; use rustc_errors::{Applicability, Diagnostic}; @@ -115,7 +115,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { need!(cx.tcx.lang_items().fn_trait()), need!(cx.tcx.lang_items().fn_once_trait()), need!(cx.tcx.lang_items().fn_mut_trait()), - need!(get_trait_def_id(cx, &paths::RANGE_ARGUMENT_TRAIT)), + need!(cx.tcx.get_diagnostic_item(sym::RangeBounds)), ]; let sized_trait = need!(cx.tcx.lang_items().sized_trait()); diff --git a/clippy_lints/src/non_canonical_impls.rs b/clippy_lints/src/non_canonical_impls.rs index 20b4b4f03ed47..4be140647fcc4 100644 --- a/clippy_lints/src/non_canonical_impls.rs +++ b/clippy_lints/src/non_canonical_impls.rs @@ -1,7 +1,6 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; -use clippy_utils::paths::ORD_CMP; use clippy_utils::ty::implements_trait; -use clippy_utils::{get_parent_node, is_res_lang_ctor, last_path_segment, match_def_path, path_res, std_or_core}; +use clippy_utils::{get_parent_node, is_res_lang_ctor, last_path_segment, path_res, std_or_core}; use rustc_errors::Applicability; use rustc_hir::def_id::LocalDefId; use rustc_hir::{Expr, ExprKind, ImplItem, ImplItemKind, LangItem, Node, UnOp}; @@ -261,7 +260,7 @@ fn self_cmp_call<'tcx>( match cmp_expr.kind { ExprKind::Call(path, [_self, _other]) => path_res(cx, path) .opt_def_id() - .is_some_and(|def_id| match_def_path(cx, def_id, &ORD_CMP)), + .is_some_and(|def_id| cx.tcx.is_diagnostic_item(sym::ord_cmp_method, def_id)), ExprKind::MethodCall(_, _, [_other], ..) => { // We can set this to true here no matter what as if it's a `MethodCall` and goes to the // `else` branch, it must be a method named `cmp` that isn't `Ord::cmp` @@ -273,7 +272,7 @@ fn self_cmp_call<'tcx>( cx.tcx .typeck(def_id) .type_dependent_def_id(cmp_expr.hir_id) - .is_some_and(|def_id| match_def_path(cx, def_id, &ORD_CMP)) + .is_some_and(|def_id| cx.tcx.is_diagnostic_item(sym::ord_cmp_method, def_id)) }, _ => false, } diff --git a/clippy_lints/src/non_octal_unix_permissions.rs b/clippy_lints/src/non_octal_unix_permissions.rs index e1de494eb41c0..d47728f190ab9 100644 --- a/clippy_lints/src/non_octal_unix_permissions.rs +++ b/clippy_lints/src/non_octal_unix_permissions.rs @@ -1,6 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::{snippet_opt, snippet_with_applicability}; -use clippy_utils::ty::{is_type_diagnostic_item, match_type}; use clippy_utils::{match_def_path, paths}; use if_chain::if_chain; use rustc_errors::Applicability; @@ -45,13 +44,12 @@ impl<'tcx> LateLintPass<'tcx> for NonOctalUnixPermissions { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { match &expr.kind { ExprKind::MethodCall(path, func, [param], _) => { - let obj_ty = cx.typeck_results().expr_ty(func).peel_refs(); - if_chain! { + if let Some(adt) = cx.typeck_results().expr_ty(func).peel_refs().ty_adt_def(); if (path.ident.name == sym!(mode) - && (match_type(cx, obj_ty, &paths::OPEN_OPTIONS) - || is_type_diagnostic_item(cx, obj_ty, sym::DirBuilder))) - || (path.ident.name == sym!(set_mode) && match_type(cx, obj_ty, &paths::PERMISSIONS)); + && matches!(cx.tcx.get_diagnostic_name(adt.did()), Some(sym::FsOpenOptions | sym::DirBuilder))) + || (path.ident.name == sym!(set_mode) + && cx.tcx.is_diagnostic_item(sym::FsPermissions, adt.did())); if let ExprKind::Lit(_) = param.kind; if param.span.ctxt() == expr.span.ctxt(); diff --git a/clippy_lints/src/non_send_fields_in_send_ty.rs b/clippy_lints/src/non_send_fields_in_send_ty.rs index c5e777c207028..d388dfc08f3b7 100644 --- a/clippy_lints/src/non_send_fields_in_send_ty.rs +++ b/clippy_lints/src/non_send_fields_in_send_ty.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet; use clippy_utils::ty::{implements_trait, is_copy}; -use clippy_utils::{is_lint_allowed, match_def_path, paths}; +use clippy_utils::is_lint_allowed; use rustc_ast::ImplPolarity; use rustc_hir::def_id::DefId; use rustc_hir::{FieldDef, Item, ItemKind, Node}; @@ -233,7 +233,7 @@ fn contains_pointer_like<'tcx>(cx: &LateContext<'tcx>, target_ty: Ty<'tcx>) -> b return true; }, ty::Adt(adt_def, _) => { - if match_def_path(cx, adt_def.did(), &paths::PTR_NON_NULL) { + if cx.tcx.is_diagnostic_item(sym::NonNull, adt_def.did()) { return true; } }, diff --git a/clippy_lints/src/operators/cmp_owned.rs b/clippy_lints/src/operators/cmp_owned.rs index d3de9699fe9d9..136642d69dcaa 100644 --- a/clippy_lints/src/operators/cmp_owned.rs +++ b/clippy_lints/src/operators/cmp_owned.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet; use clippy_utils::ty::{implements_trait, is_copy}; -use clippy_utils::{match_def_path, path_def_id, paths}; +use clippy_utils::path_def_id; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp}; use rustc_lint::LateContext; @@ -50,7 +50,7 @@ fn check_op(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left: bool) }, ExprKind::Call(path, [arg]) if path_def_id(cx, path).map_or(false, |did| { - if match_def_path(cx, did, &paths::FROM_STR_METHOD) { + if cx.tcx.is_diagnostic_item(sym::from_str_method, did) { true } else if cx.tcx.is_diagnostic_item(sym::from_fn, did) { !is_copy(cx, typeck.expr_ty(expr)) diff --git a/clippy_lints/src/permissions_set_readonly_false.rs b/clippy_lints/src/permissions_set_readonly_false.rs index 664d44d6504dc..f3089d716ff1c 100644 --- a/clippy_lints/src/permissions_set_readonly_false.rs +++ b/clippy_lints/src/permissions_set_readonly_false.rs @@ -1,10 +1,10 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::paths; -use clippy_utils::ty::match_type; +use clippy_utils::ty::is_type_diagnostic_item; use rustc_ast::ast::LitKind; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::sym; declare_clippy_lint! { /// ### What it does @@ -31,7 +31,7 @@ declare_lint_pass!(PermissionsSetReadonlyFalse => [PERMISSIONS_SET_READONLY_FALS impl<'tcx> LateLintPass<'tcx> for PermissionsSetReadonlyFalse { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { if let ExprKind::MethodCall(path, receiver, [arg], _) = &expr.kind - && match_type(cx, cx.typeck_results().expr_ty(receiver), &paths::PERMISSIONS) + && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(receiver), sym::FsPermissions) && path.ident.name == sym!(set_readonly) && let ExprKind::Lit(lit) = &arg.kind && LitKind::Bool(false) == lit.node diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs index 7dabdcd58ec2c..310051efc5088 100644 --- a/clippy_lints/src/ptr.rs +++ b/clippy_lints/src/ptr.rs @@ -4,9 +4,8 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_the use clippy_utils::source::snippet_opt; use clippy_utils::ty::expr_sig; use clippy_utils::visitors::contains_unsafe_block; -use clippy_utils::{get_expr_use_or_unification_node, is_lint_allowed, path_def_id, path_to_local, paths}; +use clippy_utils::{get_expr_use_or_unification_node, is_lint_allowed, path_def_id, path_to_local}; use hir::LifetimeName; -use if_chain::if_chain; use rustc_errors::{Applicability, MultiSpan}; use rustc_hir::def_id::DefId; use rustc_hir::hir_id::HirIdMap; @@ -271,60 +270,43 @@ impl<'tcx> LateLintPass<'tcx> for Ptr { } fn check_invalid_ptr_usage<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - // (fn_path, arg_indices) - `arg_indices` are the `arg` positions where null would cause U.B. - const INVALID_NULL_PTR_USAGE_TABLE: [(&[&str], &[usize]); 13] = [ - (&paths::SLICE_FROM_RAW_PARTS, &[0]), - (&paths::SLICE_FROM_RAW_PARTS_MUT, &[0]), - (&paths::PTR_COPY, &[0, 1]), - (&paths::PTR_COPY_NONOVERLAPPING, &[0, 1]), - (&paths::PTR_READ, &[0]), - (&paths::PTR_READ_UNALIGNED, &[0]), - (&paths::PTR_READ_VOLATILE, &[0]), - (&paths::PTR_REPLACE, &[0]), - (&paths::PTR_SLICE_FROM_RAW_PARTS, &[0]), - (&paths::PTR_SLICE_FROM_RAW_PARTS_MUT, &[0]), - (&paths::PTR_SWAP, &[0, 1]), - (&paths::PTR_SWAP_NONOVERLAPPING, &[0, 1]), - (&paths::PTR_WRITE_BYTES, &[0]), - ]; - let invalid_null_ptr_usage_table_diag_items: [(Option, &[usize]); 3] = [ - (cx.tcx.get_diagnostic_item(sym::ptr_write), &[0]), - (cx.tcx.get_diagnostic_item(sym::ptr_write_unaligned), &[0]), - (cx.tcx.get_diagnostic_item(sym::ptr_write_volatile), &[0]), - ]; - - if_chain! { - if let ExprKind::Call(fun, args) = expr.kind; - if let ExprKind::Path(ref qpath) = fun.kind; - if let Some(fun_def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id(); - let fun_def_path = cx.get_def_path(fun_def_id).into_iter().map(Symbol::to_ident_string).collect::>(); - if let Some(arg_indices) = INVALID_NULL_PTR_USAGE_TABLE - .iter() - .find_map(|&(fn_path, indices)| if fn_path == fun_def_path { Some(indices) } else { None }) - .or_else(|| { - invalid_null_ptr_usage_table_diag_items - .iter() - .find_map(|&(def_id, indices)| { - if def_id == Some(fun_def_id) { - Some(indices) - } else { - None - } - }) - }); - then { - for &arg_idx in arg_indices { - if let Some(arg) = args.get(arg_idx).filter(|arg| is_null_path(cx, arg)) { - span_lint_and_sugg( - cx, - INVALID_NULL_PTR_USAGE, - arg.span, - "pointer must be non-null", - "change this to", - "core::ptr::NonNull::dangling().as_ptr()".to_string(), - Applicability::MachineApplicable, - ); - } + if let ExprKind::Call(fun, args) = expr.kind + && let ExprKind::Path(ref qpath) = fun.kind + && let Some(fun_def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id() + && let Some(name) = cx.tcx.get_diagnostic_name(fun_def_id) + { + // `arg` positions where null would cause U.B. + let arg_indices: &[_] = match name { + sym::ptr_read + | sym::ptr_read_unaligned + | sym::ptr_read_volatile + | sym::ptr_replace + | sym::ptr_slice_from_raw_parts + | sym::ptr_slice_from_raw_parts_mut + | sym::ptr_write + | sym::ptr_write_bytes + | sym::ptr_write_unaligned + | sym::ptr_write_volatile + | sym::slice_from_raw_parts + | sym::slice_from_raw_parts_mut => &[0], + sym::ptr_copy + | sym::ptr_copy_nonoverlapping + | sym::ptr_swap + | sym::ptr_swap_nonoverlapping => &[0, 1], + _ => return, + }; + + for &arg_idx in arg_indices { + if let Some(arg) = args.get(arg_idx).filter(|arg| is_null_path(cx, arg)) { + span_lint_and_sugg( + cx, + INVALID_NULL_PTR_USAGE, + arg.span, + "pointer must be non-null", + "change this to", + "core::ptr::NonNull::dangling().as_ptr()".to_string(), + Applicability::MachineApplicable, + ); } } } diff --git a/clippy_lints/src/rc_clone_in_vec_init.rs b/clippy_lints/src/rc_clone_in_vec_init.rs index 8e85c55e7563f..1a127c2bcf68e 100644 --- a/clippy_lints/src/rc_clone_in_vec_init.rs +++ b/clippy_lints/src/rc_clone_in_vec_init.rs @@ -2,11 +2,11 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::higher::VecArgs; use clippy_utils::macros::root_macro_call_first_node; use clippy_utils::source::{indent_of, snippet}; -use clippy_utils::ty::match_type; -use clippy_utils::{last_path_segment, paths}; +use clippy_utils::last_path_segment; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, QPath, TyKind}; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::{sym, Span, Symbol}; @@ -133,8 +133,9 @@ fn ref_init(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<(Symbol, Span)> { return Some((symbol, func.span)); } - let ty_path = cx.typeck_results().expr_ty(expr); - if match_type(cx, ty_path, &paths::WEAK_RC) || match_type(cx, ty_path, &paths::WEAK_ARC) { + if let ty::Adt(adt, _) = *cx.typeck_results().expr_ty(expr).kind() + && matches!(cx.tcx.get_diagnostic_name(adt.did()), Some(sym::RcWeak | sym::ArcWeak)) + { return Some((Symbol::intern("Weak"), func.span)); } } diff --git a/clippy_lints/src/redundant_clone.rs b/clippy_lints/src/redundant_clone.rs index e36adef555e65..2c0086b09813c 100644 --- a/clippy_lints/src/redundant_clone.rs +++ b/clippy_lints/src/redundant_clone.rs @@ -99,8 +99,8 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone { unwrap_or_continue!(is_call_with_ref_arg(cx, mir, &terminator.kind)); let from_borrow = match_def_path(cx, fn_def_id, &paths::CLONE_TRAIT_METHOD) - || match_def_path(cx, fn_def_id, &paths::TO_OWNED_METHOD) - || (match_def_path(cx, fn_def_id, &paths::TO_STRING_METHOD) + || cx.tcx.is_diagnostic_item(sym::to_owned_method, fn_def_id) + || (cx.tcx.is_diagnostic_item(sym::to_string_method, fn_def_id) && is_type_lang_item(cx, arg_ty, LangItem::String)); let from_deref = !from_borrow diff --git a/clippy_lints/src/size_of_in_element_count.rs b/clippy_lints/src/size_of_in_element_count.rs index bd783b4e00541..b940cac6047be 100644 --- a/clippy_lints/src/size_of_in_element_count.rs +++ b/clippy_lints/src/size_of_in_element_count.rs @@ -2,7 +2,6 @@ //! expecting a count of T use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::{match_def_path, paths}; use if_chain::if_chain; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -67,16 +66,6 @@ fn get_pointee_ty_and_count_expr<'tcx>( cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, ) -> Option<(Ty<'tcx>, &'tcx Expr<'tcx>)> { - const FUNCTIONS: [&[&str]; 8] = [ - &paths::PTR_COPY_NONOVERLAPPING, - &paths::PTR_COPY, - &paths::PTR_WRITE_BYTES, - &paths::PTR_SWAP_NONOVERLAPPING, - &paths::PTR_SLICE_FROM_RAW_PARTS, - &paths::PTR_SLICE_FROM_RAW_PARTS_MUT, - &paths::SLICE_FROM_RAW_PARTS, - &paths::SLICE_FROM_RAW_PARTS_MUT, - ]; const METHODS: [&str; 11] = [ "write_bytes", "copy_to", @@ -97,7 +86,16 @@ fn get_pointee_ty_and_count_expr<'tcx>( if let ExprKind::Call(func, [.., count]) = expr.kind; if let ExprKind::Path(ref func_qpath) = func.kind; if let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id(); - if FUNCTIONS.iter().any(|func_path| match_def_path(cx, def_id, func_path)); + if matches!(cx.tcx.get_diagnostic_name(def_id), Some( + sym::ptr_copy + | sym::ptr_copy_nonoverlapping + | sym::ptr_slice_from_raw_parts + | sym::ptr_slice_from_raw_parts_mut + | sym::ptr_swap_nonoverlapping + | sym::ptr_write_bytes + | sym::slice_from_raw_parts + | sym::slice_from_raw_parts_mut + )); // Get the pointee type if let Some(pointee_ty) = cx.typeck_results().node_args(func.hir_id).types().next(); diff --git a/clippy_lints/src/swap_ptr_to_ref.rs b/clippy_lints/src/swap_ptr_to_ref.rs index d085dda3582be..3685432a25399 100644 --- a/clippy_lints/src/swap_ptr_to_ref.rs +++ b/clippy_lints/src/swap_ptr_to_ref.rs @@ -1,11 +1,11 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet_with_context; -use clippy_utils::{match_def_path, path_def_id, paths}; +use clippy_utils::path_def_id; use rustc_errors::Applicability; use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::{Span, SyntaxContext}; +use rustc_span::{sym, Span, SyntaxContext}; declare_clippy_lint! { /// ### What it does @@ -42,7 +42,7 @@ impl LateLintPass<'_> for SwapPtrToRef { fn check_expr(&mut self, cx: &LateContext<'_>, e: &Expr<'_>) { if let ExprKind::Call(fn_expr, [arg1, arg2]) = e.kind && let Some(fn_id) = path_def_id(cx, fn_expr) - && match_def_path(cx, fn_id, &paths::MEM_SWAP) + && cx.tcx.is_diagnostic_item(sym::mem_swap, fn_id) && let ctxt = e.span.ctxt() && let (from_ptr1, arg1_span) = is_ptr_to_ref(cx, arg1, ctxt) && let (from_ptr2, arg2_span) = is_ptr_to_ref(cx, arg2, ctxt) diff --git a/clippy_lints/src/unnamed_address.rs b/clippy_lints/src/unnamed_address.rs index dea8a1e35bbba..996e7edf5573d 100644 --- a/clippy_lints/src/unnamed_address.rs +++ b/clippy_lints/src/unnamed_address.rs @@ -1,10 +1,10 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; -use clippy_utils::{match_def_path, paths}; use if_chain::if_chain; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::sym; declare_clippy_lint! { /// ### What it does @@ -96,7 +96,7 @@ impl LateLintPass<'_> for UnnamedAddress { if let ExprKind::Call(func, [ref _left, ref _right]) = expr.kind; if let ExprKind::Path(ref func_qpath) = func.kind; if let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id(); - if match_def_path(cx, def_id, &paths::PTR_EQ); + if cx.tcx.is_diagnostic_item(sym::ptr_eq, def_id); let ty_param = cx.typeck_results().node_args(func.hir_id).type_at(0); if ty_param.is_trait(); then { diff --git a/clippy_lints/src/unused_peekable.rs b/clippy_lints/src/unused_peekable.rs index 4ee16d9a5e4ad..db91beec0efa7 100644 --- a/clippy_lints/src/unused_peekable.rs +++ b/clippy_lints/src/unused_peekable.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::ty::{match_type, peel_mid_ty_refs_is_mutable}; -use clippy_utils::{fn_def_id, is_trait_method, path_to_local_id, paths, peel_ref_operators}; +use clippy_utils::ty::{is_type_diagnostic_item, peel_mid_ty_refs_is_mutable}; +use clippy_utils::{fn_def_id, is_trait_method, path_to_local_id, peel_ref_operators}; use rustc_ast::Mutability; use rustc_hir::intravisit::{walk_expr, Visitor}; use rustc_hir::{Block, Expr, ExprKind, HirId, Local, Node, PatKind, PathSegment, StmtKind}; @@ -49,7 +49,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedPeekable { // Don't lint `Peekable`s returned from a block if let Some(expr) = block.expr && let Some(ty) = cx.typeck_results().expr_ty_opt(peel_ref_operators(cx, expr)) - && match_type(cx, ty, &paths::PEEKABLE) + && is_type_diagnostic_item(cx, ty, sym::IterPeekable) { return; } @@ -62,7 +62,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedPeekable { && !init.span.from_expansion() && let Some(ty) = cx.typeck_results().expr_ty_opt(init) && let (ty, _, Mutability::Mut) = peel_mid_ty_refs_is_mutable(ty) - && match_type(cx, ty, &paths::PEEKABLE) + && is_type_diagnostic_item(cx, ty, sym::IterPeekable) { let mut vis = PeekableVisitor::new(cx, binding); @@ -222,7 +222,7 @@ impl<'tcx> Visitor<'tcx> for PeekableVisitor<'_, 'tcx> { fn arg_is_mut_peekable(cx: &LateContext<'_>, arg: &Expr<'_>) -> bool { if let Some(ty) = cx.typeck_results().expr_ty_opt(arg) && let (ty, _, Mutability::Mut) = peel_mid_ty_refs_is_mutable(ty) - && match_type(cx, ty, &paths::PEEKABLE) + && is_type_diagnostic_item(cx, ty, sym::IterPeekable) { true } else { diff --git a/clippy_lints/src/useless_conversion.rs b/clippy_lints/src/useless_conversion.rs index f32e7edad6cb6..3cc91838c0004 100644 --- a/clippy_lints/src/useless_conversion.rs +++ b/clippy_lints/src/useless_conversion.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg, span_lin use clippy_utils::source::{snippet, snippet_with_applicability, snippet_with_context}; use clippy_utils::sugg::Sugg; use clippy_utils::ty::{is_copy, is_type_diagnostic_item, same_type_and_consts}; -use clippy_utils::{get_parent_expr, is_trait_method, is_ty_alias, match_def_path, path_to_local, paths}; +use clippy_utils::{get_parent_expr, is_trait_method, is_ty_alias, path_to_local}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::def::DefKind; @@ -331,7 +331,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { let a = cx.typeck_results().expr_ty(e); let b = cx.typeck_results().expr_ty(arg); if_chain! { - if match_def_path(cx, def_id, &paths::TRY_FROM); + if cx.tcx.is_diagnostic_item(sym::try_from_fn, def_id); if is_type_diagnostic_item(cx, a, sym::Result); if let ty::Adt(_, args) = a.kind(); if let Some(a_type) = args.types().next(); diff --git a/clippy_utils/src/higher.rs b/clippy_utils/src/higher.rs index 802adbd4d2d56..741f9f54883d6 100644 --- a/clippy_utils/src/higher.rs +++ b/clippy_utils/src/higher.rs @@ -457,7 +457,7 @@ pub fn get_vec_init_kind<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) - }; }, ExprKind::Path(QPath::Resolved(_, path)) - if match_def_path(cx, path.res.opt_def_id()?, &paths::DEFAULT_TRAIT_METHOD) + if cx.tcx.is_diagnostic_item(sym::default_fn, path.res.opt_def_id()?) && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(expr), sym::Vec) => { return Some(VecInitKind::Default); diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 13da79fba7e8e..64ca2ff787363 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -2076,7 +2076,7 @@ pub fn is_expr_identity_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool match expr.kind { ExprKind::Closure(&Closure { body, .. }) => is_body_identity_function(cx, cx.tcx.hir().body(body)), - _ => path_def_id(cx, expr).map_or(false, |id| match_def_path(cx, id, &paths::CONVERT_IDENTITY)), + _ => path_def_id(cx, expr).map_or(false, |id| cx.tcx.is_diagnostic_item(sym::convert_identity, id)), } } diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index 2fb24b5c7ed9d..1f2bb16f459fc 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -25,17 +25,12 @@ pub const CORE_ITER_COPIED: [&str; 6] = ["core", "iter", "traits", "iterator", " pub const CORE_ITER_FILTER: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "filter"]; pub const CORE_RESULT_OK_METHOD: [&str; 4] = ["core", "result", "Result", "ok"]; pub const CSTRING_AS_C_STR: [&str; 5] = ["alloc", "ffi", "c_str", "CString", "as_c_str"]; -pub const DEFAULT_TRAIT_METHOD: [&str; 4] = ["core", "default", "Default", "default"]; -pub const DEREF_MUT_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "DerefMut", "deref_mut"]; #[cfg(feature = "internal")] pub const EARLY_CONTEXT: [&str; 2] = ["rustc_lint", "EarlyContext"]; #[cfg(feature = "internal")] pub const EARLY_LINT_PASS: [&str; 3] = ["rustc_lint", "passes", "EarlyLintPass"]; -pub const EXIT: [&str; 3] = ["std", "process", "exit"]; pub const F32_EPSILON: [&str; 4] = ["core", "f32", "", "EPSILON"]; pub const F64_EPSILON: [&str; 4] = ["core", "f64", "", "EPSILON"]; -pub const FROM_ITERATOR_METHOD: [&str; 6] = ["core", "iter", "traits", "collect", "FromIterator", "from_iter"]; -pub const FROM_STR_METHOD: [&str; 5] = ["core", "str", "traits", "FromStr", "from_str"]; #[expect(clippy::invalid_paths)] // internal lints do not know about all external crates pub const FUTURES_IO_ASYNCREADEXT: [&str; 3] = ["futures_util", "io", "AsyncReadExt"]; #[expect(clippy::invalid_paths)] // internal lints do not know about all external crates @@ -48,8 +43,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_EMPTY: [&str; 5] = ["core", "iter", "sources", "empty", "Empty"]; -pub const ITER_ONCE: [&str; 5] = ["core", "iter", "sources", "once", "Once"]; pub const ITERTOOLS_NEXT_TUPLE: [&str; 3] = ["itertools", "Itertools", "next_tuple"]; #[cfg(feature = "internal")] pub const KW_MODULE: [&str; 3] = ["rustc_span", "symbol", "kw"]; @@ -59,10 +52,8 @@ pub const LATE_CONTEXT: [&str; 2] = ["rustc_lint", "LateContext"]; pub const LATE_LINT_PASS: [&str; 3] = ["rustc_lint", "passes", "LateLintPass"]; #[cfg(feature = "internal")] pub const LINT: [&str; 2] = ["rustc_lint_defs", "Lint"]; -pub const MEM_SWAP: [&str; 3] = ["core", "mem", "swap"]; #[cfg(feature = "internal")] pub const MSRV: [&str; 3] = ["clippy_utils", "msrvs", "Msrv"]; -pub const OPEN_OPTIONS: [&str; 3] = ["std", "fs", "OpenOptions"]; pub const OS_STRING_AS_OS_STR: [&str; 5] = ["std", "ffi", "os_str", "OsString", "as_os_str"]; pub const OS_STR_TO_OS_STRING: [&str; 5] = ["std", "ffi", "os_str", "OsStr", "to_os_string"]; pub const PARKING_LOT_MUTEX_GUARD: [&str; 3] = ["lock_api", "mutex", "MutexGuard"]; @@ -71,28 +62,9 @@ pub const PARKING_LOT_RWLOCK_WRITE_GUARD: [&str; 3] = ["lock_api", "rwlock", "Rw pub const PATH_BUF_AS_PATH: [&str; 4] = ["std", "path", "PathBuf", "as_path"]; pub const PATH_MAIN_SEPARATOR: [&str; 3] = ["std", "path", "MAIN_SEPARATOR"]; pub const PATH_TO_PATH_BUF: [&str; 4] = ["std", "path", "Path", "to_path_buf"]; -pub const PEEKABLE: [&str; 5] = ["core", "iter", "adapters", "peekable", "Peekable"]; -pub const PERMISSIONS: [&str; 3] = ["std", "fs", "Permissions"]; #[cfg_attr(not(unix), allow(clippy::invalid_paths))] pub const PERMISSIONS_FROM_MODE: [&str; 6] = ["std", "os", "unix", "fs", "PermissionsExt", "from_mode"]; -pub const PTR_COPY: [&str; 3] = ["core", "intrinsics", "copy"]; -pub const PTR_COPY_NONOVERLAPPING: [&str; 3] = ["core", "intrinsics", "copy_nonoverlapping"]; -pub const PTR_EQ: [&str; 3] = ["core", "ptr", "eq"]; -pub const PTR_SLICE_FROM_RAW_PARTS: [&str; 3] = ["core", "ptr", "slice_from_raw_parts"]; -pub const PTR_SLICE_FROM_RAW_PARTS_MUT: [&str; 3] = ["core", "ptr", "slice_from_raw_parts_mut"]; -pub const PTR_SWAP_NONOVERLAPPING: [&str; 3] = ["core", "ptr", "swap_nonoverlapping"]; -pub const PTR_READ: [&str; 3] = ["core", "ptr", "read"]; -pub const PTR_READ_UNALIGNED: [&str; 3] = ["core", "ptr", "read_unaligned"]; -pub const PTR_READ_VOLATILE: [&str; 3] = ["core", "ptr", "read_volatile"]; -pub const PTR_REPLACE: [&str; 3] = ["core", "ptr", "replace"]; -pub const PTR_SWAP: [&str; 3] = ["core", "ptr", "swap"]; -pub const PTR_UNALIGNED_VOLATILE_LOAD: [&str; 3] = ["core", "intrinsics", "unaligned_volatile_load"]; -pub const PTR_UNALIGNED_VOLATILE_STORE: [&str; 3] = ["core", "intrinsics", "unaligned_volatile_store"]; -pub const PTR_WRITE_BYTES: [&str; 3] = ["core", "intrinsics", "write_bytes"]; pub const PUSH_STR: [&str; 4] = ["alloc", "string", "String", "push_str"]; -pub const RANGE_ARGUMENT_TRAIT: [&str; 3] = ["core", "ops", "RangeBounds"]; -pub const REFCELL_REF: [&str; 3] = ["core", "cell", "Ref"]; -pub const REFCELL_REFMUT: [&str; 3] = ["core", "cell", "RefMut"]; pub const REGEX_BUILDER_NEW: [&str; 3] = ["regex", "RegexBuilder", "new"]; pub const REGEX_BYTES_BUILDER_NEW: [&str; 4] = ["regex", "bytes", "RegexBuilder", "new"]; pub const REGEX_BYTES_NEW: [&str; 4] = ["regex", "bytes", "Regex", "new"]; @@ -101,21 +73,11 @@ pub const REGEX_NEW: [&str; 3] = ["regex", "Regex", "new"]; pub const REGEX_SET_NEW: [&str; 3] = ["regex", "RegexSet", "new"]; pub const SERDE_DESERIALIZE: [&str; 3] = ["serde", "de", "Deserialize"]; pub const SERDE_DE_VISITOR: [&str; 3] = ["serde", "de", "Visitor"]; -pub const SLICE_FROM_RAW_PARTS: [&str; 4] = ["core", "slice", "raw", "from_raw_parts"]; -pub const SLICE_FROM_RAW_PARTS_MUT: [&str; 4] = ["core", "slice", "raw", "from_raw_parts_mut"]; pub const SLICE_GET: [&str; 4] = ["core", "slice", "", "get"]; pub const SLICE_INTO_VEC: [&str; 4] = ["alloc", "slice", "", "into_vec"]; pub const SLICE_INTO: [&str; 4] = ["core", "slice", "", "iter"]; -pub const SLICE_ITER: [&str; 4] = ["core", "slice", "iter", "Iter"]; -pub const STDERR: [&str; 4] = ["std", "io", "stdio", "stderr"]; -pub const STDOUT: [&str; 4] = ["std", "io", "stdio", "stdout"]; -pub const CONVERT_IDENTITY: [&str; 3] = ["core", "convert", "identity"]; -pub const STD_FS_CREATE_DIR: [&str; 3] = ["std", "fs", "create_dir"]; -pub const STD_IO_LINES: [&str; 3] = ["std", "io", "Lines"]; -pub const STD_IO_SEEK: [&str; 3] = ["std", "io", "Seek"]; pub const STD_IO_SEEK_FROM_CURRENT: [&str; 4] = ["std", "io", "SeekFrom", "Current"]; pub const STD_IO_SEEKFROM_START: [&str; 4] = ["std", "io", "SeekFrom", "Start"]; -pub const STD_PROCESS_COMMAND: [&str; 3] = ["std", "process", "Command"]; pub const STRING_AS_MUT_STR: [&str; 4] = ["alloc", "string", "String", "as_mut_str"]; pub const STRING_AS_STR: [&str; 4] = ["alloc", "string", "String", "as_str"]; pub const STRING_NEW: [&str; 4] = ["alloc", "string", "String", "new"]; @@ -136,13 +98,11 @@ pub const SYMBOL_TO_IDENT_STRING: [&str; 4] = ["rustc_span", "symbol", "Symbol", pub const SYM_MODULE: [&str; 3] = ["rustc_span", "symbol", "sym"]; #[cfg(feature = "internal")] pub const SYNTAX_CONTEXT: [&str; 3] = ["rustc_span", "hygiene", "SyntaxContext"]; -pub const TO_OWNED_METHOD: [&str; 4] = ["alloc", "borrow", "ToOwned", "to_owned"]; pub const TO_STRING_METHOD: [&str; 4] = ["alloc", "string", "ToString", "to_string"]; #[expect(clippy::invalid_paths)] // internal lints do not know about all external crates pub const TOKIO_IO_ASYNCREADEXT: [&str; 5] = ["tokio", "io", "util", "async_read_ext", "AsyncReadExt"]; #[expect(clippy::invalid_paths)] // internal lints do not know about all external crates pub const TOKIO_IO_ASYNCWRITEEXT: [&str; 5] = ["tokio", "io", "util", "async_write_ext", "AsyncWriteExt"]; -pub const TRY_FROM: [&str; 4] = ["core", "convert", "TryFrom", "try_from"]; pub const VEC_AS_MUT_SLICE: [&str; 4] = ["alloc", "vec", "Vec", "as_mut_slice"]; pub const VEC_AS_SLICE: [&str; 4] = ["alloc", "vec", "Vec", "as_slice"]; pub const VEC_DEQUE_ITER: [&str; 5] = ["alloc", "collections", "vec_deque", "VecDeque", "iter"]; @@ -150,18 +110,10 @@ pub const VEC_FROM_ELEM: [&str; 3] = ["alloc", "vec", "from_elem"]; pub const VEC_NEW: [&str; 4] = ["alloc", "vec", "Vec", "new"]; pub const VEC_WITH_CAPACITY: [&str; 4] = ["alloc", "vec", "Vec", "with_capacity"]; pub const VEC_RESIZE: [&str; 4] = ["alloc", "vec", "Vec", "resize"]; -pub const WEAK_ARC: [&str; 3] = ["alloc", "sync", "Weak"]; -pub const WEAK_RC: [&str; 3] = ["alloc", "rc", "Weak"]; -pub const PTR_NON_NULL: [&str; 4] = ["core", "ptr", "non_null", "NonNull"]; pub const INSTANT_NOW: [&str; 4] = ["std", "time", "Instant", "now"]; -pub const INSTANT: [&str; 3] = ["std", "time", "Instant"]; pub const VEC_IS_EMPTY: [&str; 4] = ["alloc", "vec", "Vec", "is_empty"]; pub const VEC_POP: [&str; 4] = ["alloc", "vec", "Vec", "pop"]; pub const OPTION_UNWRAP: [&str; 4] = ["core", "option", "Option", "unwrap"]; pub const OPTION_EXPECT: [&str; 4] = ["core", "option", "Option", "expect"]; -pub const FORMATTER: [&str; 3] = ["core", "fmt", "Formatter"]; -pub const DEBUG_STRUCT: [&str; 4] = ["core", "fmt", "builders", "DebugStruct"]; -pub const ORD_CMP: [&str; 4] = ["core", "cmp", "Ord", "cmp"]; #[expect(clippy::invalid_paths)] // not sure why it thinks this, it works so pub const BOOL_THEN: [&str; 4] = ["core", "bool", "", "then"]; -pub const ARRAY_INTO_ITER: [&str; 4] = ["core", "array", "iter", "IntoIter"]; diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index 604dc76912e65..2d305a63eca12 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -31,7 +31,7 @@ use rustc_trait_selection::traits::{Obligation, ObligationCause}; use std::assert_matches::debug_assert_matches; use std::iter; -use crate::{match_def_path, path_res, paths}; +use crate::{match_def_path, path_res}; mod type_certainty; pub use type_certainty::expr_type_is_certain; @@ -461,10 +461,8 @@ pub fn needs_ordered_drop<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { else if is_type_lang_item(cx, ty, LangItem::OwnedBox) || matches!( get_type_diagnostic_name(cx, ty), - Some(sym::HashSet | sym::Rc | sym::Arc | sym::cstring_type) + Some(sym::HashSet | sym::Rc | sym::Arc | sym::cstring_type | sym::RcWeak | sym::ArcWeak) ) - || match_type(cx, ty, &paths::WEAK_RC) - || match_type(cx, ty, &paths::WEAK_ARC) { // Check all of the generic arguments. if let ty::Adt(_, subs) = ty.kind() { diff --git a/tests/ui-internal/unnecessary_def_path_hardcoded_path.rs b/tests/ui-internal/unnecessary_def_path_hardcoded_path.rs index b5ff3a5420561..60be297881341 100644 --- a/tests/ui-internal/unnecessary_def_path_hardcoded_path.rs +++ b/tests/ui-internal/unnecessary_def_path_hardcoded_path.rs @@ -11,6 +11,6 @@ fn main() { const DEREF_MUT_TRAIT: [&str; 4] = ["core", "ops", "deref", "DerefMut"]; const DEREF_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "Deref", "deref"]; - // Don't lint, not yet a diagnostic or language item - const DEREF_MUT_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "DerefMut", "deref_mut"]; + // Don't lint, not a diagnostic or language item + const OPS_MOD: [&str; 5] = ["core", "ops"]; } diff --git a/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr b/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr index 58b1fd92b5dc9..076786329cd9f 100644 --- a/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr +++ b/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr @@ -19,8 +19,8 @@ LL | const DEREF_MUT_TRAIT: [&str; 4] = ["core", "ops", "deref", "DerefMut"] error: hardcoded path to a diagnostic item --> $DIR/unnecessary_def_path_hardcoded_path.rs:12:43 | -LL | const DEREF_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "Deref", "deref"]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | const OPS_MOD: [&str; 5] = ["core", "ops"]; + | ^^^^^^^^^^^^^^^ | = help: convert all references to use `sym::deref_method` From 8ebed4cc1a2e21844c58f3b0bfbad1a069bb09b6 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Fri, 6 Oct 2023 17:35:45 +0200 Subject: [PATCH 04/14] Merge commit 'b105fb4c39bc1a010807a6c076193cef8d93c109' into clippyup --- CHANGELOG.md | 97 ++++++- Cargo.toml | 4 +- book/src/development/adding_lints.md | 2 +- book/src/lint_configuration.md | 1 + clippy_dev/src/new_lint.rs | 63 ++++- clippy_lints/Cargo.toml | 5 +- clippy_lints/src/allow_attributes.rs | 2 +- clippy_lints/src/declared_lints.rs | 3 + clippy_lints/src/enum_clike.rs | 4 +- clippy_lints/src/error_impl_error.rs | 2 +- clippy_lints/src/four_forward_slashes.rs | 2 +- clippy_lints/src/ignored_unit_patterns.rs | 4 + clippy_lints/src/implicit_hasher.rs | 5 +- clippy_lints/src/items_after_test_module.rs | 108 +++++--- clippy_lints/src/iter_without_into_iter.rs | 249 ++++++++++++++++++ clippy_lints/src/lib.rs | 4 + clippy_lints/src/manual_float_methods.rs | 4 +- clippy_lints/src/manual_hash_one.rs | 133 ++++++++++ clippy_lints/src/manual_let_else.rs | 4 +- clippy_lints/src/manual_non_exhaustive.rs | 22 +- clippy_lints/src/matches/mod.rs | 2 +- clippy_lints/src/matches/overlapping_arms.rs | 6 +- clippy_lints/src/methods/mod.rs | 13 +- .../src/methods/unnecessary_literal_unwrap.rs | 11 +- clippy_lints/src/missing_assert_message.rs | 4 + .../src/mixed_read_write_in_expression.rs | 7 +- clippy_lints/src/needless_pass_by_ref_mut.rs | 4 +- clippy_lints/src/non_canonical_impls.rs | 2 +- clippy_lints/src/operators/mod.rs | 4 +- clippy_lints/src/raw_strings.rs | 30 +-- clippy_lints/src/redundant_locals.rs | 36 +-- clippy_lints/src/std_instead_of_core.rs | 6 +- clippy_lints/src/utils/conf.rs | 43 ++- clippy_lints/src/wildcard_imports.rs | 1 + clippy_lints/src/write.rs | 142 +++++++--- clippy_utils/Cargo.toml | 2 +- clippy_utils/src/consts.rs | 69 +++-- clippy_utils/src/lib.rs | 31 ++- clippy_utils/src/msrvs.rs | 2 +- clippy_utils/src/visitors.rs | 44 ++++ declare_clippy_lint/Cargo.toml | 2 +- rust-toolchain | 2 +- src/driver.rs | 55 ++-- src/main.rs | 63 +++-- tests/ui/auxiliary/proc_macro_derive.rs | 28 ++ tests/ui/ignored_unit_patterns.fixed | 15 ++ tests/ui/ignored_unit_patterns.rs | 15 ++ tests/ui/ignored_unit_patterns.stderr | 24 +- tests/ui/infinite_loop.rs | 2 - tests/ui/infinite_loop.stderr | 33 +-- tests/ui/into_iter_without_iter.rs | 124 +++++++++ tests/ui/into_iter_without_iter.stderr | 114 ++++++++ .../after_proc_macros.rs | 11 + .../auxiliary/submodule.rs | 4 + .../block_module.stderr | 2 - .../items_after_test_module/in_submodule.rs | 8 + .../in_submodule.stderr | 14 + .../multiple_modules.rs | 11 + .../{block_module.rs => root_module.fixed} | 15 +- .../ui/items_after_test_module/root_module.rs | 22 ++ .../root_module.stderr | 20 ++ tests/ui/iter_without_into_iter.rs | 120 +++++++++ tests/ui/iter_without_into_iter.stderr | 150 +++++++++++ tests/ui/let_underscore_future.rs | 2 - tests/ui/let_underscore_future.stderr | 17 +- tests/ui/manual_hash_one.fixed | 89 +++++++ tests/ui/manual_hash_one.rs | 89 +++++++ tests/ui/manual_hash_one.stderr | 56 ++++ tests/ui/manual_let_else_match.fixed | 4 + tests/ui/manual_let_else_match.rs | 8 + tests/ui/manual_let_else_match.stderr | 12 +- tests/ui/manual_non_exhaustive_enum.rs | 3 +- tests/ui/manual_non_exhaustive_enum.stderr | 20 +- tests/ui/mut_key.rs | 2 - tests/ui/mut_key.stderr | 41 ++- tests/ui/mut_reference.rs | 2 - tests/ui/mut_reference.stderr | 17 +- tests/ui/needless_pass_by_ref_mut.rs | 1 + tests/ui/needless_pass_by_ref_mut.stderr | 42 +-- tests/ui/needless_raw_string.fixed | 4 + tests/ui/needless_raw_string.rs | 4 + tests/ui/needless_raw_string.stderr | 46 +++- tests/ui/needless_raw_string_hashes.stderr | 30 +-- tests/ui/print_literal.fixed | 18 +- tests/ui/print_literal.rs | 18 +- tests/ui/print_literal.stderr | 124 ++++++--- tests/ui/redundant_locals.rs | 37 +++ tests/ui/redundant_locals.stderr | 139 ++++++---- tests/ui/should_impl_trait/method_list_2.rs | 2 - .../ui/should_impl_trait/method_list_2.stderr | 36 +-- tests/ui/slow_vector_initialization.rs | 2 - tests/ui/slow_vector_initialization.stderr | 11 +- tests/ui/std_instead_of_core.fixed | 11 + tests/ui/std_instead_of_core.rs | 11 + tests/ui/std_instead_of_core.stderr | 22 +- tests/ui/wildcard_imports.fixed | 28 ++ tests/ui/wildcard_imports.rs | 28 ++ tests/ui/wildcard_imports.stderr | 38 +-- .../wildcard_imports_2021.edition2018.fixed | 28 ++ .../wildcard_imports_2021.edition2018.stderr | 38 +-- .../wildcard_imports_2021.edition2021.fixed | 28 ++ .../wildcard_imports_2021.edition2021.stderr | 38 +-- tests/ui/wildcard_imports_2021.rs | 28 ++ tests/ui/write_literal.fixed | 14 +- tests/ui/write_literal.rs | 14 +- tests/ui/write_literal.stderr | 74 +++--- tests/ui/write_literal_2.rs | 16 +- tests/ui/write_literal_2.stderr | 82 ++---- 108 files changed, 2637 insertions(+), 768 deletions(-) create mode 100644 clippy_lints/src/iter_without_into_iter.rs create mode 100644 clippy_lints/src/manual_hash_one.rs create mode 100644 tests/ui/into_iter_without_iter.rs create mode 100644 tests/ui/into_iter_without_iter.stderr create mode 100644 tests/ui/items_after_test_module/after_proc_macros.rs create mode 100644 tests/ui/items_after_test_module/auxiliary/submodule.rs delete mode 100644 tests/ui/items_after_test_module/block_module.stderr create mode 100644 tests/ui/items_after_test_module/in_submodule.rs create mode 100644 tests/ui/items_after_test_module/in_submodule.stderr create mode 100644 tests/ui/items_after_test_module/multiple_modules.rs rename tests/ui/items_after_test_module/{block_module.rs => root_module.fixed} (86%) create mode 100644 tests/ui/items_after_test_module/root_module.rs create mode 100644 tests/ui/items_after_test_module/root_module.stderr create mode 100644 tests/ui/iter_without_into_iter.rs create mode 100644 tests/ui/iter_without_into_iter.stderr create mode 100644 tests/ui/manual_hash_one.fixed create mode 100644 tests/ui/manual_hash_one.rs create mode 100644 tests/ui/manual_hash_one.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c9ab1e2402ca..fef25ad8635ae 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,11 +6,101 @@ document. ## Unreleased / Beta / In Rust Nightly -[37f4c172...master](https://github.com/rust-lang/rust-clippy/compare/37f4c172...master) +[1e8fdf49...master](https://github.com/rust-lang/rust-clippy/compare/1e8fdf49...master) + +## Rust 1.73 + +Current stable, released 2023-10-05 + +[View all 103 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2023-07-02T12%3A24%3A40Z..2023-08-11T11%3A09%3A56Z+base%3Amaster) + +### New Lints + +* [`impossible_comparisons`] + [#10843](https://github.com/rust-lang/rust-clippy/pull/10843) +* [`redundant_comparisons`] + [#10843](https://github.com/rust-lang/rust-clippy/pull/10843) +* [`ignored_unit_patterns`] + [#11242](https://github.com/rust-lang/rust-clippy/pull/11242) +* [`readonly_write_lock`] + [#11210](https://github.com/rust-lang/rust-clippy/pull/11210) +* [`filter_map_bool_then`] + [#11115](https://github.com/rust-lang/rust-clippy/pull/11115) +* [`needless_return_with_question_mark`] + [#11031](https://github.com/rust-lang/rust-clippy/pull/11031) +* [`redundant_guards`] + [#10955](https://github.com/rust-lang/rust-clippy/pull/10955) +* [`redundant_locals`] + [#10885](https://github.com/rust-lang/rust-clippy/pull/10885) +* [`absolute_paths`] + [#11003](https://github.com/rust-lang/rust-clippy/pull/11003) +* [`error_impl_error`] + [#11107](https://github.com/rust-lang/rust-clippy/pull/11107) +* [`iter_skip_zero`] + [#11046](https://github.com/rust-lang/rust-clippy/pull/11046) +* [`string_lit_chars_any`] + [#11052](https://github.com/rust-lang/rust-clippy/pull/11052) +* [`four_forward_slashes`] + [#11140](https://github.com/rust-lang/rust-clippy/pull/11140) +* [`format_collect`] + [#11116](https://github.com/rust-lang/rust-clippy/pull/11116) +* [`needless_pass_by_ref_mut`] + [#10900](https://github.com/rust-lang/rust-clippy/pull/10900) +* [`manual_is_infinite`] + [#11049](https://github.com/rust-lang/rust-clippy/pull/11049) +* [`manual_is_finite`] + [#11049](https://github.com/rust-lang/rust-clippy/pull/11049) +* [`incorrect_partial_ord_impl_on_ord_type`] + [#10788](https://github.com/rust-lang/rust-clippy/pull/10788) +* [`read_line_without_trim`] + [#10970](https://github.com/rust-lang/rust-clippy/pull/10970) +* [`type_id_on_box`] + [#10987](https://github.com/rust-lang/rust-clippy/pull/10987) + +### Moves and Deprecations + +* Renamed `unwrap_or_else_default` to [`unwrap_or_default`] + [#10120](https://github.com/rust-lang/rust-clippy/pull/10120) +* Moved [`tuple_array_conversions`] to `pedantic` (Now allow-by-default) + [#11146](https://github.com/rust-lang/rust-clippy/pull/11146) +* Moved [`arc_with_non_send_sync`] to `suspicious` (Now warn-by-default) + [#11104](https://github.com/rust-lang/rust-clippy/pull/11104) +* Moved [`needless_raw_string_hashes`] to `pedantic` (Now allow-by-default) + [#11415](https://github.com/rust-lang/rust-clippy/pull/11415) + +### Enhancements + +* [`unwrap_used`]: No longer lints on the never-type or never-like enums + [#11252](https://github.com/rust-lang/rust-clippy/pull/11252) +* [`expect_used`]: No longer lints on the never-type or never-like enums + [#11252](https://github.com/rust-lang/rust-clippy/pull/11252) + +### False Positive Fixes + +* [`panic_in_result_fn`]: No longer triggers on `todo!`, `unimplemented!`, `unreachable!` + [#11123](https://github.com/rust-lang/rust-clippy/pull/11123) + +### Suggestion Fixes/Improvements + +* [`semicolon_if_nothing_returned`]: The suggestion is now machine-applicable with rustfix + [#11083](https://github.com/rust-lang/rust-clippy/pull/11083) + +### ICE Fixes + +* [`filter_map_bool_then`]: No longer crashes on late-bound regions + [#11318](https://github.com/rust-lang/rust-clippy/pull/11318) +* [`unwrap_or_default`]: No longer crashes on alias types for local items + [#11258](https://github.com/rust-lang/rust-clippy/pull/11258) +* [`unnecessary_literal_unwrap`]: No longer crashes on `None.unwrap_or_default()` + [#11106](https://github.com/rust-lang/rust-clippy/pull/11106) +* Fixed MIR-related ICE + [#11130](https://github.com/rust-lang/rust-clippy/pull/11130) +* [`missing_fields_in_debug`]: No longer crashes on non-ADT self types + [#11069](https://github.com/rust-lang/rust-clippy/pull/11069) ## Rust 1.72 -Current stable, released 2023-08-24 +Released 2023-08-24 [View all 131 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2023-05-22T14%3A53%3A59Z..2023-07-01T22%3A57%3A20Z+base%3Amaster) @@ -5011,6 +5101,7 @@ Released 2018-09-13 [`integer_division`]: https://rust-lang.github.io/rust-clippy/master/index.html#integer_division [`into_iter_on_array`]: https://rust-lang.github.io/rust-clippy/master/index.html#into_iter_on_array [`into_iter_on_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#into_iter_on_ref +[`into_iter_without_iter`]: https://rust-lang.github.io/rust-clippy/master/index.html#into_iter_without_iter [`invalid_atomic_ordering`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_atomic_ordering [`invalid_null_ptr_usage`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_null_ptr_usage [`invalid_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_ref @@ -5036,6 +5127,7 @@ Released 2018-09-13 [`iter_skip_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_skip_next [`iter_skip_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_skip_zero [`iter_with_drain`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_with_drain +[`iter_without_into_iter`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_without_into_iter [`iterator_step_by_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#iterator_step_by_zero [`just_underscores_and_digits`]: https://rust-lang.github.io/rust-clippy/master/index.html#just_underscores_and_digits [`large_const_arrays`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_const_arrays @@ -5072,6 +5164,7 @@ Released 2018-09-13 [`manual_find`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_find [`manual_find_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_find_map [`manual_flatten`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_flatten +[`manual_hash_one`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_hash_one [`manual_instant_elapsed`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_instant_elapsed [`manual_is_ascii_check`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_ascii_check [`manual_is_finite`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_finite diff --git a/Cargo.toml b/Cargo.toml index 66786004f6e72..cbcb42dad79b2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy" -version = "0.1.74" +version = "0.1.75" description = "A bunch of helpful lints to avoid common pitfalls in Rust" repository = "https://github.com/rust-lang/rust-clippy" readme = "README.md" @@ -25,6 +25,8 @@ clippy_lints = { path = "clippy_lints" } rustc_tools_util = "0.3.0" tempfile = { version = "3.2", optional = true } termize = "0.1" +color-print = "0.3.4" # Sync version with Cargo +anstream = "0.5.0" [dev-dependencies] ui_test = "0.20" diff --git a/book/src/development/adding_lints.md b/book/src/development/adding_lints.md index f6f0c95c72933..e001197842bdc 100644 --- a/book/src/development/adding_lints.md +++ b/book/src/development/adding_lints.md @@ -261,7 +261,7 @@ impl EarlyLintPass for FooFunctions {} [declare_clippy_lint]: https://github.com/rust-lang/rust-clippy/blob/557f6848bd5b7183f55c1e1522a326e9e1df6030/clippy_lints/src/lib.rs#L60 [example_lint_page]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure [lint_naming]: https://rust-lang.github.io/rfcs/0344-conventions-galore.html#lints -[category_level_mapping]: https://github.com/rust-lang/rust-clippy/blob/557f6848bd5b7183f55c1e1522a326e9e1df6030/clippy_lints/src/lib.rs#L110 +[category_level_mapping]: ../index.html ## Lint registration diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md index b980083f1f52a..2c958ccbbc246 100644 --- a/book/src/lint_configuration.md +++ b/book/src/lint_configuration.md @@ -151,6 +151,7 @@ The minimum rust version that the project supports * [`type_repetition_in_bounds`](https://rust-lang.github.io/rust-clippy/master/index.html#type_repetition_in_bounds) * [`tuple_array_conversions`](https://rust-lang.github.io/rust-clippy/master/index.html#tuple_array_conversions) * [`manual_try_fold`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_try_fold) +* [`manual_hash_one`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_hash_one) ## `cognitive-complexity-threshold` diff --git a/clippy_dev/src/new_lint.rs b/clippy_dev/src/new_lint.rs index e64cf2c874968..be2386bb1d24b 100644 --- a/clippy_dev/src/new_lint.rs +++ b/clippy_dev/src/new_lint.rs @@ -58,7 +58,7 @@ pub fn create( }; create_lint(&lint, msrv).context("Unable to create lint implementation")?; - create_test(&lint).context("Unable to create a test for the new lint")?; + create_test(&lint, msrv).context("Unable to create a test for the new lint")?; if lint.ty.is_none() { add_lint(&lint, msrv).context("Unable to add lint to clippy_lints/src/lib.rs")?; @@ -88,15 +88,21 @@ fn create_lint(lint: &LintData<'_>, enable_msrv: bool) -> io::Result<()> { } } -fn create_test(lint: &LintData<'_>) -> io::Result<()> { - fn create_project_layout>(lint_name: &str, location: P, case: &str, hint: &str) -> io::Result<()> { +fn create_test(lint: &LintData<'_>, msrv: bool) -> io::Result<()> { + fn create_project_layout>( + lint_name: &str, + location: P, + case: &str, + hint: &str, + msrv: bool, + ) -> io::Result<()> { let mut path = location.into().join(case); fs::create_dir(&path)?; write_file(path.join("Cargo.toml"), get_manifest_contents(lint_name, hint))?; path.push("src"); fs::create_dir(&path)?; - write_file(path.join("main.rs"), get_test_file_contents(lint_name))?; + write_file(path.join("main.rs"), get_test_file_contents(lint_name, msrv))?; Ok(()) } @@ -106,13 +112,25 @@ fn create_test(lint: &LintData<'_>) -> io::Result<()> { let test_dir = lint.project_root.join(&relative_test_dir); fs::create_dir(&test_dir)?; - create_project_layout(lint.name, &test_dir, "fail", "Content that triggers the lint goes here")?; - create_project_layout(lint.name, &test_dir, "pass", "This file should not trigger the lint")?; + create_project_layout( + lint.name, + &test_dir, + "fail", + "Content that triggers the lint goes here", + msrv, + )?; + create_project_layout( + lint.name, + &test_dir, + "pass", + "This file should not trigger the lint", + false, + )?; println!("Generated test directories: `{relative_test_dir}/pass`, `{relative_test_dir}/fail`"); } else { let test_path = format!("tests/ui/{}.rs", lint.name); - let test_contents = get_test_file_contents(lint.name); + let test_contents = get_test_file_contents(lint.name, msrv); write_file(lint.project_root.join(&test_path), test_contents)?; println!("Generated test file: `{test_path}`"); @@ -194,8 +212,8 @@ pub(crate) fn get_stabilization_version() -> String { parse_manifest(&contents).expect("Unable to find package version in `Cargo.toml`") } -fn get_test_file_contents(lint_name: &str) -> String { - formatdoc!( +fn get_test_file_contents(lint_name: &str, msrv: bool) -> String { + let mut test = formatdoc!( r#" #![warn(clippy::{lint_name})] @@ -203,7 +221,29 @@ fn get_test_file_contents(lint_name: &str) -> String { // test code goes here }} "# - ) + ); + + if msrv { + let _ = writedoc!( + test, + r#" + + // TODO: set xx to the version one below the MSRV used by the lint, and yy to + // the version used by the lint + #[clippy::msrv = "1.xx"] + fn msrv_1_xx() {{ + // a simple example that would trigger the lint if the MSRV were met + }} + + #[clippy::msrv = "1.yy"] + fn msrv_1_yy() {{ + // the same example as above + }} + "# + ); + } + + test } fn get_manifest_contents(lint_name: &str, hint: &str) -> String { @@ -258,7 +298,7 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String { ) }); - let _: fmt::Result = write!(result, "{}", get_lint_declaration(&name_upper, category)); + let _: fmt::Result = writeln!(result, "{}", get_lint_declaration(&name_upper, category)); result.push_str(&if enable_msrv { formatdoc!( @@ -281,7 +321,6 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String { }} // TODO: Add MSRV level to `clippy_utils/src/msrvs.rs` if needed. - // TODO: Add MSRV test to `tests/ui/min_rust_version_attr.rs`. // TODO: Update msrv config comment in `clippy_lints/src/utils/conf.rs` "# ) diff --git a/clippy_lints/Cargo.toml b/clippy_lints/Cargo.toml index dcd9a4adcbd46..4d5b3bf8a948d 100644 --- a/clippy_lints/Cargo.toml +++ b/clippy_lints/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy_lints" -version = "0.1.74" +version = "0.1.75" description = "A bunch of helpful lints to avoid common pitfalls in Rust" repository = "https://github.com/rust-lang/rust-clippy" readme = "README.md" @@ -28,6 +28,9 @@ semver = "1.0" rustc-semver = "1.1" url = "2.2" +[dev-dependencies] +walkdir = "2.3" + [features] deny-warnings = ["clippy_utils/deny-warnings"] # build clippy with internal lints enabled, off by default diff --git a/clippy_lints/src/allow_attributes.rs b/clippy_lints/src/allow_attributes.rs index e1ef514edfd18..e3f4cf79d315c 100644 --- a/clippy_lints/src/allow_attributes.rs +++ b/clippy_lints/src/allow_attributes.rs @@ -8,6 +8,7 @@ use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { + /// ### What it does /// Checks for usage of the `#[allow]` attribute and suggests replacing it with /// the `#[expect]` (See [RFC 2383](https://rust-lang.github.io/rfcs/2383-lint-reasons.html)) /// @@ -19,7 +20,6 @@ declare_clippy_lint! { /// (`#![allow]`) are usually used to enable or disable lints on a global scale. /// /// ### Why is this bad? - /// /// `#[expect]` attributes suppress the lint emission, but emit a warning, if /// the expectation is unfulfilled. This can be useful to be notified when the /// lint is no longer triggered. diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 4d1281ec1e7c7..481c44031cf72 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -229,6 +229,8 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::items_after_statements::ITEMS_AFTER_STATEMENTS_INFO, crate::items_after_test_module::ITEMS_AFTER_TEST_MODULE_INFO, crate::iter_not_returning_iterator::ITER_NOT_RETURNING_ITERATOR_INFO, + crate::iter_without_into_iter::INTO_ITER_WITHOUT_ITER_INFO, + crate::iter_without_into_iter::ITER_WITHOUT_INTO_ITER_INFO, crate::large_const_arrays::LARGE_CONST_ARRAYS_INFO, crate::large_enum_variant::LARGE_ENUM_VARIANT_INFO, crate::large_futures::LARGE_FUTURES_INFO, @@ -280,6 +282,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::manual_clamp::MANUAL_CLAMP_INFO, crate::manual_float_methods::MANUAL_IS_FINITE_INFO, crate::manual_float_methods::MANUAL_IS_INFINITE_INFO, + crate::manual_hash_one::MANUAL_HASH_ONE_INFO, crate::manual_is_ascii_check::MANUAL_IS_ASCII_CHECK_INFO, crate::manual_let_else::MANUAL_LET_ELSE_INFO, crate::manual_main_separator_str::MANUAL_MAIN_SEPARATOR_STR_INFO, diff --git a/clippy_lints/src/enum_clike.rs b/clippy_lints/src/enum_clike.rs index 3f60e5a7c4d64..646767868e2cf 100644 --- a/clippy_lints/src/enum_clike.rs +++ b/clippy_lints/src/enum_clike.rs @@ -1,7 +1,7 @@ //! lint on C-like enums that are `repr(isize/usize)` and have values that //! don't fit into an `i32` -use clippy_utils::consts::{miri_to_const, Constant}; +use clippy_utils::consts::{mir_to_const, Constant}; use clippy_utils::diagnostics::span_lint; use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -51,7 +51,7 @@ impl<'tcx> LateLintPass<'tcx> for UnportableVariant { .const_eval_poly(def_id.to_def_id()) .ok() .map(|val| rustc_middle::mir::Const::from_value(val, ty)); - if let Some(Constant::Int(val)) = constant.and_then(|c| miri_to_const(cx, c)) { + if let Some(Constant::Int(val)) = constant.and_then(|c| mir_to_const(cx, c)) { if let ty::Adt(adt, _) = ty.kind() { if adt.is_enum() { ty = adt.repr().discr_type().to_ty(cx.tcx); diff --git a/clippy_lints/src/error_impl_error.rs b/clippy_lints/src/error_impl_error.rs index f24577c738229..6d429fbd03538 100644 --- a/clippy_lints/src/error_impl_error.rs +++ b/clippy_lints/src/error_impl_error.rs @@ -27,7 +27,7 @@ declare_clippy_lint! { /// /// impl std::error::Error for Error { ... } /// ``` - #[clippy::version = "1.72.0"] + #[clippy::version = "1.73.0"] pub ERROR_IMPL_ERROR, restriction, "exported types named `Error` that implement `Error`" diff --git a/clippy_lints/src/four_forward_slashes.rs b/clippy_lints/src/four_forward_slashes.rs index 419c77343441c..0ec52f89e7166 100644 --- a/clippy_lints/src/four_forward_slashes.rs +++ b/clippy_lints/src/four_forward_slashes.rs @@ -28,7 +28,7 @@ declare_clippy_lint! { /// // ... /// } /// ``` - #[clippy::version = "1.72.0"] + #[clippy::version = "1.73.0"] pub FOUR_FORWARD_SLASHES, suspicious, "comments with 4 forward slashes (`////`) likely intended to be doc comments (`///`)" diff --git a/clippy_lints/src/ignored_unit_patterns.rs b/clippy_lints/src/ignored_unit_patterns.rs index d8ead1c9d9f68..ef2a66d4a209a 100644 --- a/clippy_lints/src/ignored_unit_patterns.rs +++ b/clippy_lints/src/ignored_unit_patterns.rs @@ -37,6 +37,10 @@ declare_lint_pass!(IgnoredUnitPatterns => [IGNORED_UNIT_PATTERNS]); impl<'tcx> LateLintPass<'tcx> for IgnoredUnitPatterns { fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx hir::Pat<'tcx>) { + if pat.span.from_expansion() { + return; + } + match cx.tcx.hir().get_parent(pat.hir_id) { Node::Param(param) if matches!(cx.tcx.hir().get_parent(param.hir_id), Node::Item(_)) => { // Ignore function parameters diff --git a/clippy_lints/src/implicit_hasher.rs b/clippy_lints/src/implicit_hasher.rs index 64a4a3fa741bc..2b2ea156cd4d3 100644 --- a/clippy_lints/src/implicit_hasher.rs +++ b/clippy_lints/src/implicit_hasher.rs @@ -6,9 +6,8 @@ use rustc_hir as hir; use rustc_hir::intravisit::{walk_body, walk_expr, walk_inf, walk_ty, Visitor}; use rustc_hir::{Body, Expr, ExprKind, GenericArg, Item, ItemKind, QPath, TyKind}; use rustc_hir_analysis::hir_ty_to_ty; -use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; -use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{Ty, TypeckResults}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; @@ -162,7 +161,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitHasher { vis.visit_ty(ty); for target in &vis.found { - if in_external_macro(cx.sess(), generics.span) { + if generics.span.from_expansion() { continue; } let generics_suggestion_span = generics.span.substitute_dummy({ diff --git a/clippy_lints/src/items_after_test_module.rs b/clippy_lints/src/items_after_test_module.rs index 55a43e9156282..41477242bcc0b 100644 --- a/clippy_lints/src/items_after_test_module.rs +++ b/clippy_lints/src/items_after_test_module.rs @@ -1,10 +1,12 @@ -use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::{is_from_proc_macro, is_in_cfg_test}; -use rustc_hir::{HirId, ItemId, ItemKind, Mod}; -use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::lint::in_external_macro; +use clippy_utils::diagnostics::span_lint_hir_and_then; +use clippy_utils::source::snippet_opt; +use clippy_utils::{fulfill_or_allowed, is_cfg_test, is_from_proc_macro}; +use rustc_errors::{Applicability, SuggestionStyle}; +use rustc_hir::{HirId, Item, ItemKind, Mod}; +use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::{sym, Span}; +use rustc_span::hygiene::AstPass; +use rustc_span::{sym, ExpnKind}; declare_clippy_lint! { /// ### What it does @@ -41,46 +43,72 @@ declare_clippy_lint! { declare_lint_pass!(ItemsAfterTestModule => [ITEMS_AFTER_TEST_MODULE]); -impl LateLintPass<'_> for ItemsAfterTestModule { - fn check_mod(&mut self, cx: &LateContext<'_>, _: &Mod<'_>, _: HirId) { - let mut was_test_mod_visited = false; - let mut test_mod_span: Option = None; +fn cfg_test_module<'tcx>(cx: &LateContext<'tcx>, item: &Item<'tcx>) -> bool { + if let ItemKind::Mod(test_mod) = item.kind + && item.span.hi() == test_mod.spans.inner_span.hi() + && is_cfg_test(cx.tcx, item.hir_id()) + && !item.span.from_expansion() + && !is_from_proc_macro(cx, item) + { + true + } else { + false + } +} - let hir = cx.tcx.hir(); - let items = hir.items().collect::>(); +impl LateLintPass<'_> for ItemsAfterTestModule { + fn check_mod(&mut self, cx: &LateContext<'_>, module: &Mod<'_>, _: HirId) { + let mut items = module.item_ids.iter().map(|&id| cx.tcx.hir().item(id)); - for (i, itid) in items.iter().enumerate() { - let item = hir.item(*itid); + let Some((mod_pos, test_mod)) = items.by_ref().enumerate().find(|(_, item)| cfg_test_module(cx, item)) else { + return; + }; - if_chain! { - if was_test_mod_visited; - if i == (items.len() - 3 /* Weird magic number (HIR-translation behaviour) */); - if cx.sess().source_map().lookup_char_pos(item.span.lo()).file.name_hash - == cx.sess().source_map().lookup_char_pos(test_mod_span.unwrap().lo()).file.name_hash; // Will never fail - if !matches!(item.kind, ItemKind::Mod(_)); - if !is_in_cfg_test(cx.tcx, itid.hir_id()); // The item isn't in the testing module itself - if !in_external_macro(cx.sess(), item.span); - if !is_from_proc_macro(cx, item); + let after: Vec<_> = items + .filter(|item| { + // Ignore the generated test main function + !(item.ident.name == sym::main + && item.span.ctxt().outer_expn_data().kind == ExpnKind::AstPass(AstPass::TestHarness)) + }) + .collect(); - then { - span_lint_and_help(cx, ITEMS_AFTER_TEST_MODULE, test_mod_span.unwrap().with_hi(item.span.hi()), "items were found after the testing module", None, "move the items to before the testing module was defined"); - }}; + if let Some(last) = after.last() + && after.iter().all(|&item| { + !matches!(item.kind, ItemKind::Mod(_)) + && !item.span.from_expansion() + && !is_from_proc_macro(cx, item) + }) + && !fulfill_or_allowed(cx, ITEMS_AFTER_TEST_MODULE, after.iter().map(|item| item.hir_id())) + { + let def_spans: Vec<_> = std::iter::once(test_mod.owner_id) + .chain(after.iter().map(|item| item.owner_id)) + .map(|id| cx.tcx.def_span(id)) + .collect(); - if let ItemKind::Mod(module) = item.kind && item.span.hi() == module.spans.inner_span.hi() { - // Check that it works the same way, the only I way I've found for #10713 - for attr in cx.tcx.get_attrs(item.owner_id.to_def_id(), sym::cfg) { - if_chain! { - if attr.has_name(sym::cfg); - if let Some(mitems) = attr.meta_item_list(); - if let [mitem] = &*mitems; - if mitem.has_name(sym::test); - then { - was_test_mod_visited = true; - test_mod_span = Some(item.span); - } + span_lint_hir_and_then( + cx, + ITEMS_AFTER_TEST_MODULE, + test_mod.hir_id(), + def_spans, + "items after a test module", + |diag| { + if let Some(prev) = mod_pos.checked_sub(1) + && let prev = cx.tcx.hir().item(module.item_ids[prev]) + && let items_span = last.span.with_lo(test_mod.span.hi()) + && let Some(items) = snippet_opt(cx, items_span) + { + diag.multipart_suggestion_with_style( + "move the items to before the test module was defined", + vec![ + (prev.span.shrink_to_hi(), items), + (items_span, String::new()) + ], + Applicability::MachineApplicable, + SuggestionStyle::HideCodeAlways, + ); } - } - } + }, + ); } } } diff --git a/clippy_lints/src/iter_without_into_iter.rs b/clippy_lints/src/iter_without_into_iter.rs new file mode 100644 index 0000000000000..43e1b92c9b9a7 --- /dev/null +++ b/clippy_lints/src/iter_without_into_iter.rs @@ -0,0 +1,249 @@ +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::get_parent_as_impl; +use clippy_utils::source::snippet; +use clippy_utils::ty::{implements_trait, make_normalized_projection}; +use rustc_ast::Mutability; +use rustc_errors::Applicability; +use rustc_hir::{FnRetTy, ImplItemKind, ImplicitSelfKind, ItemKind, TyKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::{self, Ty}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::{sym, Symbol}; + +declare_clippy_lint! { + /// ### What it does + /// Looks for `iter` and `iter_mut` methods without an associated `IntoIterator for (&|&mut) Type` implementation. + /// + /// ### Why is this bad? + /// It's not bad, but having them is idiomatic and allows the type to be used in for loops directly + /// (`for val in &iter {}`), without having to first call `iter()` or `iter_mut()`. + /// + /// ### Example + /// ```rust + /// struct MySlice<'a>(&'a [u8]); + /// impl<'a> MySlice<'a> { + /// pub fn iter(&self) -> std::slice::Iter<'a, u8> { + /// self.0.iter() + /// } + /// } + /// ``` + /// Use instead: + /// ```rust + /// struct MySlice<'a>(&'a [u8]); + /// impl<'a> MySlice<'a> { + /// pub fn iter(&self) -> std::slice::Iter<'a, u8> { + /// self.0.iter() + /// } + /// } + /// impl<'a> IntoIterator for &MySlice<'a> { + /// type Item = &'a u8; + /// type IntoIter = std::slice::Iter<'a, u8>; + /// fn into_iter(self) -> Self::IntoIter { + /// self.iter() + /// } + /// } + /// ``` + #[clippy::version = "1.74.0"] + pub ITER_WITHOUT_INTO_ITER, + pedantic, + "implementing `iter(_mut)` without an associated `IntoIterator for (&|&mut) Type` impl" +} + +declare_clippy_lint! { + /// ### What it does + /// This is the opposite of the `iter_without_into_iter` lint. + /// It looks for `IntoIterator for (&|&mut) Type` implementations without an inherent `iter` or `iter_mut` method. + /// + /// ### Why is this bad? + /// It's not bad, but having them is idiomatic and allows the type to be used in iterator chains + /// by just calling `.iter()`, instead of the more awkward `<&Type>::into_iter` or `(&val).iter()` syntax + /// in case of ambiguity with another `Intoiterator` impl. + /// + /// ### Example + /// ```rust + /// struct MySlice<'a>(&'a [u8]); + /// impl<'a> IntoIterator for &MySlice<'a> { + /// type Item = &'a u8; + /// type IntoIter = std::slice::Iter<'a, u8>; + /// fn into_iter(self) -> Self::IntoIter { + /// self.0.iter() + /// } + /// } + /// ``` + /// Use instead: + /// ```rust + /// struct MySlice<'a>(&'a [u8]); + /// impl<'a> MySlice<'a> { + /// pub fn iter(&self) -> std::slice::Iter<'a, u8> { + /// self.into_iter() + /// } + /// } + /// impl<'a> IntoIterator for &MySlice<'a> { + /// type Item = &'a u8; + /// type IntoIter = std::slice::Iter<'a, u8>; + /// fn into_iter(self) -> Self::IntoIter { + /// self.0.iter() + /// } + /// } + /// ``` + #[clippy::version = "1.74.0"] + pub INTO_ITER_WITHOUT_ITER, + pedantic, + "implementing `IntoIterator for (&|&mut) Type` without an inherent `iter(_mut)` method" +} + +declare_lint_pass!(IterWithoutIntoIter => [ITER_WITHOUT_INTO_ITER, INTO_ITER_WITHOUT_ITER]); + +/// Checks if a given type is nameable in a trait (impl). +/// RPIT is stable, but impl Trait in traits is not (yet), so when we have +/// a function such as `fn iter(&self) -> impl IntoIterator`, we can't +/// suggest `type IntoIter = impl IntoIterator`. +fn is_nameable_in_impl_trait(ty: &rustc_hir::Ty<'_>) -> bool { + !matches!(ty.kind, TyKind::OpaqueDef(..)) +} + +fn type_has_inherent_method(cx: &LateContext<'_>, ty: Ty<'_>, method_name: Symbol) -> bool { + if let Some(ty_did) = ty.ty_adt_def().map(ty::AdtDef::did) { + cx.tcx.inherent_impls(ty_did).iter().any(|&did| { + cx.tcx + .associated_items(did) + .filter_by_name_unhygienic(method_name) + .next() + .is_some_and(|item| item.kind == ty::AssocKind::Fn) + }) + } else { + false + } +} + +impl LateLintPass<'_> for IterWithoutIntoIter { + fn check_item(&mut self, cx: &LateContext<'_>, item: &rustc_hir::Item<'_>) { + if let ItemKind::Impl(imp) = item.kind + && let TyKind::Ref(_, self_ty_without_ref) = &imp.self_ty.kind + && let Some(trait_ref) = imp.of_trait + && trait_ref.trait_def_id().is_some_and(|did| cx.tcx.is_diagnostic_item(sym::IntoIterator, did)) + && let &ty::Ref(_, ty, mtbl) = cx.tcx.type_of(item.owner_id).instantiate_identity().kind() + && let expected_method_name = match mtbl { + Mutability::Mut => sym::iter_mut, + Mutability::Not => sym::iter, + } + && !type_has_inherent_method(cx, ty, expected_method_name) + && let Some(iter_assoc_span) = imp.items.iter().find_map(|item| { + if item.ident.name == sym!(IntoIter) { + Some(cx.tcx.hir().impl_item(item.id).expect_type().span) + } else { + None + } + }) + { + span_lint_and_then( + cx, + INTO_ITER_WITHOUT_ITER, + item.span, + &format!("`IntoIterator` implemented for a reference type without an `{expected_method_name}` method"), + |diag| { + // The suggestion forwards to the `IntoIterator` impl and uses a form of UFCS + // to avoid name ambiguities, as there might be an inherent into_iter method + // that we don't want to call. + let sugg = format!( +" +impl {self_ty_without_ref} {{ + fn {expected_method_name}({ref_self}self) -> {iter_ty} {{ + <{ref_self}Self as IntoIterator>::into_iter(self) + }} +}} +", + self_ty_without_ref = snippet(cx, self_ty_without_ref.ty.span, ".."), + ref_self = mtbl.ref_prefix_str(), + iter_ty = snippet(cx, iter_assoc_span, ".."), + ); + + diag.span_suggestion_verbose( + item.span.shrink_to_lo(), + format!("consider implementing `{expected_method_name}`"), + sugg, + // Just like iter_without_into_iter, this suggestion is on a best effort basis + // and requires potentially adding lifetimes or moving them around. + Applicability::Unspecified + ); + } + ); + } + } + + fn check_impl_item(&mut self, cx: &LateContext<'_>, item: &rustc_hir::ImplItem<'_>) { + let item_did = item.owner_id.to_def_id(); + let (borrow_prefix, expected_implicit_self) = match item.ident.name { + sym::iter => ("&", ImplicitSelfKind::ImmRef), + sym::iter_mut => ("&mut ", ImplicitSelfKind::MutRef), + _ => return, + }; + + if let ImplItemKind::Fn(sig, _) = item.kind + && let FnRetTy::Return(ret) = sig.decl.output + && is_nameable_in_impl_trait(ret) + && cx.tcx.generics_of(item_did).params.is_empty() + && sig.decl.implicit_self == expected_implicit_self + && sig.decl.inputs.len() == 1 + && let Some(imp) = get_parent_as_impl(cx.tcx, item.hir_id()) + && imp.of_trait.is_none() + && let sig = cx.tcx.liberate_late_bound_regions( + item_did, + cx.tcx.fn_sig(item_did).instantiate_identity() + ) + && let ref_ty = sig.inputs()[0] + && let Some(into_iter_did) = cx.tcx.get_diagnostic_item(sym::IntoIterator) + && let Some(iterator_did) = cx.tcx.get_diagnostic_item(sym::Iterator) + && let ret_ty = sig.output() + // Order is important here, we need to check that the `fn iter` return type actually implements `IntoIterator` + // *before* normalizing `<_ as IntoIterator>::Item` (otherwise make_normalized_projection ICEs) + && implements_trait(cx, ret_ty, iterator_did, &[]) + && let Some(iter_ty) = make_normalized_projection( + cx.tcx, + cx.param_env, + iterator_did, + sym!(Item), + [ret_ty], + ) + // Only lint if the `IntoIterator` impl doesn't actually exist + && !implements_trait(cx, ref_ty, into_iter_did, &[]) + { + let self_ty_snippet = format!("{borrow_prefix}{}", snippet(cx, imp.self_ty.span, "..")); + + span_lint_and_then( + cx, + ITER_WITHOUT_INTO_ITER, + item.span, + &format!("`{}` method without an `IntoIterator` impl for `{self_ty_snippet}`", item.ident), + |diag| { + // Get the lower span of the `impl` block, and insert the suggestion right before it: + // impl X { + // ^ fn iter(&self) -> impl IntoIterator { ... } + // } + let span_behind_impl = cx.tcx + .def_span(cx.tcx.hir().parent_id(item.hir_id()).owner.def_id) + .shrink_to_lo(); + + let sugg = format!( +" +impl IntoIterator for {self_ty_snippet} {{ + type IntoIter = {ret_ty}; + type Iter = {iter_ty}; + fn into_iter() -> Self::IntoIter {{ + self.iter() + }} +}} +" + ); + diag.span_suggestion_verbose( + span_behind_impl, + format!("consider implementing `IntoIterator` for `{self_ty_snippet}`"), + sugg, + // Suggestion is on a best effort basis, might need some adjustments by the user + // such as adding some lifetimes in the associated types, or importing types. + Applicability::Unspecified, + ); + }); + } + } +} diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 1271be2fd9368..0f35ec2766574 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -169,6 +169,7 @@ mod invalid_upcast_comparisons; mod items_after_statements; mod items_after_test_module; mod iter_not_returning_iterator; +mod iter_without_into_iter; mod large_const_arrays; mod large_enum_variant; mod large_futures; @@ -190,6 +191,7 @@ mod manual_async_fn; mod manual_bits; mod manual_clamp; mod manual_float_methods; +mod manual_hash_one; mod manual_is_ascii_check; mod manual_let_else; mod manual_main_separator_str; @@ -1119,6 +1121,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: msrv(), )) }); + store.register_late_pass(move |_| Box::new(manual_hash_one::ManualHashOne::new(msrv()))); + store.register_late_pass(|_| Box::new(iter_without_into_iter::IterWithoutIntoIter)); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/clippy_lints/src/manual_float_methods.rs b/clippy_lints/src/manual_float_methods.rs index 88db7ae6aece0..ed9189a180495 100644 --- a/clippy_lints/src/manual_float_methods.rs +++ b/clippy_lints/src/manual_float_methods.rs @@ -26,7 +26,7 @@ declare_clippy_lint! { /// # let x = 1.0f32; /// if x.is_infinite() {} /// ``` - #[clippy::version = "1.72.0"] + #[clippy::version = "1.73.0"] pub MANUAL_IS_INFINITE, style, "use dedicated method to check if a float is infinite" @@ -51,7 +51,7 @@ declare_clippy_lint! { /// if x.is_finite() {} /// if x.is_finite() {} /// ``` - #[clippy::version = "1.72.0"] + #[clippy::version = "1.73.0"] pub MANUAL_IS_FINITE, style, "use dedicated method to check if a float is finite" diff --git a/clippy_lints/src/manual_hash_one.rs b/clippy_lints/src/manual_hash_one.rs new file mode 100644 index 0000000000000..ea91133545044 --- /dev/null +++ b/clippy_lints/src/manual_hash_one.rs @@ -0,0 +1,133 @@ +use clippy_utils::diagnostics::span_lint_hir_and_then; +use clippy_utils::msrvs::{self, Msrv}; +use clippy_utils::source::snippet_opt; +use clippy_utils::visitors::{is_local_used, local_used_once}; +use clippy_utils::{is_trait_method, path_to_local_id}; +use rustc_errors::Applicability; +use rustc_hir::{BindingAnnotation, ExprKind, Local, Node, PatKind, StmtKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_span::sym; + +declare_clippy_lint! { + /// ### What it does + /// Checks for cases where [`BuildHasher::hash_one`] can be used. + /// + /// [`BuildHasher::hash_one`]: https://doc.rust-lang.org/std/hash/trait.BuildHasher.html#method.hash_one + /// + /// ### Why is this bad? + /// It is more concise to use the `hash_one` method. + /// + /// ### Example + /// ```rust + /// use std::hash::{BuildHasher, Hash, Hasher}; + /// use std::collections::hash_map::RandomState; + /// + /// let s = RandomState::new(); + /// let value = vec![1, 2, 3]; + /// + /// let mut hasher = s.build_hasher(); + /// value.hash(&mut hasher); + /// let hash = hasher.finish(); + /// ``` + /// Use instead: + /// ```rust + /// use std::hash::BuildHasher; + /// use std::collections::hash_map::RandomState; + /// + /// let s = RandomState::new(); + /// let value = vec![1, 2, 3]; + /// + /// let hash = s.hash_one(&value); + /// ``` + #[clippy::version = "1.74.0"] + pub MANUAL_HASH_ONE, + complexity, + "manual implementations of `BuildHasher::hash_one`" +} + +pub struct ManualHashOne { + msrv: Msrv, +} + +impl ManualHashOne { + #[must_use] + pub fn new(msrv: Msrv) -> Self { + Self { msrv } + } +} + +impl_lint_pass!(ManualHashOne => [MANUAL_HASH_ONE]); + +impl LateLintPass<'_> for ManualHashOne { + fn check_local(&mut self, cx: &LateContext<'_>, local: &Local<'_>) { + // `let mut hasher = seg.build_hasher();` + if let PatKind::Binding(BindingAnnotation::MUT, hasher, _, None) = local.pat.kind + && let Some(init) = local.init + && !init.span.from_expansion() + && let ExprKind::MethodCall(seg, build_hasher, [], _) = init.kind + && seg.ident.name == sym!(build_hasher) + + && let Node::Stmt(local_stmt) = cx.tcx.hir().get_parent(local.hir_id) + && let Node::Block(block) = cx.tcx.hir().get_parent(local_stmt.hir_id) + + && let mut stmts = block.stmts.iter() + .skip_while(|stmt| stmt.hir_id != local_stmt.hir_id) + .skip(1) + .filter(|&stmt| is_local_used(cx, stmt, hasher)) + + // `hashed_value.hash(&mut hasher);` + && let Some(hash_stmt) = stmts.next() + && let StmtKind::Semi(hash_expr) = hash_stmt.kind + && !hash_expr.span.from_expansion() + && let ExprKind::MethodCall(seg, hashed_value, [ref_to_hasher], _) = hash_expr.kind + && seg.ident.name == sym::hash + && is_trait_method(cx, hash_expr, sym::Hash) + && path_to_local_id(ref_to_hasher.peel_borrows(), hasher) + + && let maybe_finish_stmt = stmts.next() + // There should be no more statements referencing `hasher` + && stmts.next().is_none() + + // `hasher.finish()`, may be anywhere in a statement or the trailing expr of the block + && let Some(path_expr) = local_used_once(cx, (maybe_finish_stmt, block.expr), hasher) + && let Node::Expr(finish_expr) = cx.tcx.hir().get_parent(path_expr.hir_id) + && !finish_expr.span.from_expansion() + && let ExprKind::MethodCall(seg, _, [], _) = finish_expr.kind + && seg.ident.name == sym!(finish) + + && self.msrv.meets(msrvs::BUILD_HASHER_HASH_ONE) + { + span_lint_hir_and_then( + cx, + MANUAL_HASH_ONE, + finish_expr.hir_id, + finish_expr.span, + "manual implementation of `BuildHasher::hash_one`", + |diag| { + if let Some(build_hasher) = snippet_opt(cx, build_hasher.span) + && let Some(hashed_value) = snippet_opt(cx, hashed_value.span) + { + diag.multipart_suggestion( + "try", + vec![ + (local_stmt.span, String::new()), + (hash_stmt.span, String::new()), + ( + finish_expr.span, + // `needless_borrows_for_generic_args` will take care of + // removing the `&` when it isn't needed + format!("{build_hasher}.hash_one(&{hashed_value})") + ) + ], + Applicability::MachineApplicable, + ); + + } + }, + ); + } + } + + extract_msrv_attr!(LateContext); +} diff --git a/clippy_lints/src/manual_let_else.rs b/clippy_lints/src/manual_let_else.rs index c531137b785e8..2117308cd4009 100644 --- a/clippy_lints/src/manual_let_else.rs +++ b/clippy_lints/src/manual_let_else.rs @@ -136,9 +136,9 @@ fn emit_manual_let_else( // for this to be machine applicable. let mut app = Applicability::HasPlaceholders; let (sn_expr, _) = snippet_with_context(cx, expr.span, span.ctxt(), "", &mut app); - let (sn_else, _) = snippet_with_context(cx, else_body.span, span.ctxt(), "", &mut app); + let (sn_else, else_is_mac_call) = snippet_with_context(cx, else_body.span, span.ctxt(), "", &mut app); - let else_bl = if matches!(else_body.kind, ExprKind::Block(..)) { + let else_bl = if matches!(else_body.kind, ExprKind::Block(..)) && !else_is_mac_call { sn_else.into_owned() } else { format!("{{ {sn_else} }}") diff --git a/clippy_lints/src/manual_non_exhaustive.rs b/clippy_lints/src/manual_non_exhaustive.rs index 0e22485db2c59..c12727c4a28cc 100644 --- a/clippy_lints/src/manual_non_exhaustive.rs +++ b/clippy_lints/src/manual_non_exhaustive.rs @@ -3,6 +3,7 @@ use clippy_utils::is_doc_hidden; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_opt; use rustc_ast::ast::{self, VisibilityKind}; +use rustc_ast::attr; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; @@ -158,7 +159,8 @@ impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustiveEnum { let mut iter = def.variants.iter().filter_map(|v| { (matches!(v.data, hir::VariantData::Unit(_, _)) && v.ident.as_str().starts_with('_') - && is_doc_hidden(cx.tcx.hir().attrs(v.hir_id))) + && is_doc_hidden(cx.tcx.hir().attrs(v.hir_id)) + && !attr::contains_name(cx.tcx.hir().attrs(item.hir_id()), sym::non_exhaustive)) .then_some((v.def_id, v.span)) }); if let Some((id, span)) = iter.next() @@ -198,16 +200,14 @@ impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustiveEnum { enum_span, "this seems like a manual implementation of the non-exhaustive pattern", |diag| { - if !cx.tcx.adt_def(enum_id).is_variant_list_non_exhaustive() - && let header_span = cx.sess().source_map().span_until_char(enum_span, '{') - && let Some(snippet) = snippet_opt(cx, header_span) - { - diag.span_suggestion( - header_span, - "add the attribute", - format!("#[non_exhaustive] {snippet}"), - Applicability::Unspecified, - ); + let header_span = cx.sess().source_map().span_until_char(enum_span, '{'); + if let Some(snippet) = snippet_opt(cx, header_span) { + diag.span_suggestion( + header_span, + "add the attribute", + format!("#[non_exhaustive] {snippet}"), + Applicability::Unspecified, + ); } diag.span_help(variant_span, "remove this variant"); }, diff --git a/clippy_lints/src/matches/mod.rs b/clippy_lints/src/matches/mod.rs index 930386a60aa02..a23000e5fe15c 100644 --- a/clippy_lints/src/matches/mod.rs +++ b/clippy_lints/src/matches/mod.rs @@ -961,7 +961,7 @@ declare_clippy_lint! { /// _ => todo!(), /// } /// ``` - #[clippy::version = "1.72.0"] + #[clippy::version = "1.73.0"] pub REDUNDANT_GUARDS, complexity, "checks for unnecessary guards in match expressions" diff --git a/clippy_lints/src/matches/overlapping_arms.rs b/clippy_lints/src/matches/overlapping_arms.rs index 7c0485914b83b..8f0083f812cc2 100644 --- a/clippy_lints/src/matches/overlapping_arms.rs +++ b/clippy_lints/src/matches/overlapping_arms.rs @@ -1,4 +1,4 @@ -use clippy_utils::consts::{constant, constant_full_int, miri_to_const, FullInt}; +use clippy_utils::consts::{constant, constant_full_int, mir_to_const, FullInt}; use clippy_utils::diagnostics::span_lint_and_note; use core::cmp::Ordering; use rustc_hir::{Arm, Expr, PatKind, RangeEnd}; @@ -37,14 +37,14 @@ fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>) Some(lhs) => constant(cx, cx.typeck_results(), lhs)?, None => { let min_val_const = ty.numeric_min_val(cx.tcx)?; - miri_to_const(cx, mir::Const::from_ty_const(min_val_const, cx.tcx))? + mir_to_const(cx, mir::Const::from_ty_const(min_val_const, cx.tcx))? }, }; let rhs_const = match rhs { Some(rhs) => constant(cx, cx.typeck_results(), rhs)?, None => { let max_val_const = ty.numeric_max_val(cx.tcx)?; - miri_to_const(cx, mir::Const::from_ty_const(max_val_const, cx.tcx))? + mir_to_const(cx, mir::Const::from_ty_const(max_val_const, cx.tcx))? }, }; let lhs_val = lhs_const.int_value(cx, ty)?; diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index e7fcef9e9de27..a935aea5075d7 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -2970,7 +2970,7 @@ declare_clippy_lint! { /// assert_eq!((*any_box).type_id(), TypeId::of::()); /// // ^ dereference first, to call `type_id` on `dyn Any` /// ``` - #[clippy::version = "1.72.0"] + #[clippy::version = "1.73.0"] pub TYPE_ID_ON_BOX, suspicious, "calling `.type_id()` on `Box`" @@ -3368,6 +3368,7 @@ declare_clippy_lint! { } declare_clippy_lint! { + /// ### What it does /// Looks for calls to [`Stdin::read_line`] to read a line from the standard input /// into a string, then later attempting to parse this string into a type without first trimming it, which will /// always fail because the string has a trailing newline in it. @@ -3390,7 +3391,7 @@ declare_clippy_lint! { /// // ^^^^^^^^^^^ remove the trailing newline /// assert_eq!(num, 42); /// ``` - #[clippy::version = "1.72.0"] + #[clippy::version = "1.73.0"] pub READ_LINE_WITHOUT_TRIM, correctness, "calling `Stdin::read_line`, then trying to parse it without first trimming" @@ -3418,7 +3419,7 @@ declare_clippy_lint! { /// # let c = 'c'; /// matches!(c, '\\' | '.' | '+' | '*' | '(' | ')' | '|' | '[' | ']' | '{' | '}' | '^' | '$' | '#' | '&' | '-' | '~'); /// ``` - #[clippy::version = "1.72.0"] + #[clippy::version = "1.73.0"] pub STRING_LIT_CHARS_ANY, restriction, "checks for `.chars().any(|i| i == c)`" @@ -3453,7 +3454,7 @@ declare_clippy_lint! { /// }) /// } /// ``` - #[clippy::version = "1.72.0"] + #[clippy::version = "1.73.0"] pub FORMAT_COLLECT, perf, "`format!`ing every element in a collection, then collecting the strings into a new `String`" @@ -3474,7 +3475,7 @@ declare_clippy_lint! { /// let y = v.iter().collect::>(); /// assert_eq!(x, y); /// ``` - #[clippy::version = "1.72.0"] + #[clippy::version = "1.73.0"] pub ITER_SKIP_ZERO, correctness, "disallows `.skip(0)`" @@ -3505,7 +3506,7 @@ declare_clippy_lint! { /// # let v = vec![]; /// _ = v.into_iter().filter(|i| i % 2 == 0).map(|i| really_expensive_fn(i)); /// ``` - #[clippy::version = "1.72.0"] + #[clippy::version = "1.73.0"] pub FILTER_MAP_BOOL_THEN, style, "checks for usage of `bool::then` in `Iterator::filter_map`" diff --git a/clippy_lints/src/methods/unnecessary_literal_unwrap.rs b/clippy_lints/src/methods/unnecessary_literal_unwrap.rs index 24c0ea3f60a99..3e19d72ec912a 100644 --- a/clippy_lints/src/methods/unnecessary_literal_unwrap.rs +++ b/clippy_lints/src/methods/unnecessary_literal_unwrap.rs @@ -24,7 +24,6 @@ fn get_ty_from_args<'a>(args: Option<&'a [hir::GenericArg<'a>]>, index: usize) - } } -#[expect(clippy::too_many_lines)] pub(super) fn check( cx: &LateContext<'_>, expr: &hir::Expr<'_>, @@ -101,11 +100,11 @@ pub(super) fn check( (expr.span.with_lo(args[0].span.hi()), String::new()), ]), ("None", "unwrap_or_else", _) => match args[0].kind { - hir::ExprKind::Closure(hir::Closure { - body, - .. - }) => Some(vec![ - (expr.span.with_hi(cx.tcx.hir().body(*body).value.span.lo()), String::new()), + hir::ExprKind::Closure(hir::Closure { body, .. }) => Some(vec![ + ( + expr.span.with_hi(cx.tcx.hir().body(*body).value.span.lo()), + String::new(), + ), (expr.span.with_lo(args[0].span.hi()), String::new()), ]), _ => None, diff --git a/clippy_lints/src/missing_assert_message.rs b/clippy_lints/src/missing_assert_message.rs index c17f00c427515..136947a2c8cd3 100644 --- a/clippy_lints/src/missing_assert_message.rs +++ b/clippy_lints/src/missing_assert_message.rs @@ -15,6 +15,10 @@ declare_clippy_lint! { /// A good custom message should be more about why the failure of the assertion is problematic /// and not what is failed because the assertion already conveys that. /// + /// Although the same reasoning applies to testing functions, this lint ignores them as they would be too noisy. + /// Also, in most cases understanding the test failure would be easier + /// compared to understanding a complex invariant distributed around the codebase. + /// /// ### Known problems /// This lint cannot check the quality of the custom panic messages. /// Hence, you can suppress this lint simply by adding placeholder messages diff --git a/clippy_lints/src/mixed_read_write_in_expression.rs b/clippy_lints/src/mixed_read_write_in_expression.rs index ea6a9bc5657da..e87aea263d48e 100644 --- a/clippy_lints/src/mixed_read_write_in_expression.rs +++ b/clippy_lints/src/mixed_read_write_in_expression.rs @@ -135,10 +135,7 @@ impl<'a, 'tcx> DivergenceVisitor<'a, 'tcx> { } fn stmt_might_diverge(stmt: &Stmt<'_>) -> bool { - match stmt.kind { - StmtKind::Item(..) => false, - _ => true, - } + !matches!(stmt.kind, StmtKind::Item(..)) } impl<'a, 'tcx> Visitor<'tcx> for DivergenceVisitor<'a, 'tcx> { @@ -148,7 +145,7 @@ impl<'a, 'tcx> Visitor<'tcx> for DivergenceVisitor<'a, 'tcx> { ExprKind::Block(block, ..) => match (block.stmts, block.expr) { (stmts, Some(e)) => { if stmts.iter().all(|stmt| !stmt_might_diverge(stmt)) { - self.visit_expr(e) + self.visit_expr(e); } }, ([first @ .., stmt], None) => { diff --git a/clippy_lints/src/needless_pass_by_ref_mut.rs b/clippy_lints/src/needless_pass_by_ref_mut.rs index 57652e5ff546b..212d6234bdb3c 100644 --- a/clippy_lints/src/needless_pass_by_ref_mut.rs +++ b/clippy_lints/src/needless_pass_by_ref_mut.rs @@ -47,9 +47,9 @@ declare_clippy_lint! { /// 12 + *y /// } /// ``` - #[clippy::version = "1.72.0"] + #[clippy::version = "1.73.0"] pub NEEDLESS_PASS_BY_REF_MUT, - suspicious, + nursery, "using a `&mut` argument when it's not mutated" } diff --git a/clippy_lints/src/non_canonical_impls.rs b/clippy_lints/src/non_canonical_impls.rs index 4be140647fcc4..0e4b6aa1b7d23 100644 --- a/clippy_lints/src/non_canonical_impls.rs +++ b/clippy_lints/src/non_canonical_impls.rs @@ -102,7 +102,7 @@ declare_clippy_lint! { /// } /// } /// ``` - #[clippy::version = "1.72.0"] + #[clippy::version = "1.73.0"] pub NON_CANONICAL_PARTIAL_ORD_IMPL, suspicious, "non-canonical implementation of `PartialOrd` on an `Ord` type" diff --git a/clippy_lints/src/operators/mod.rs b/clippy_lints/src/operators/mod.rs index 4635e1164cd31..6b247cf5f6ae1 100644 --- a/clippy_lints/src/operators/mod.rs +++ b/clippy_lints/src/operators/mod.rs @@ -312,7 +312,7 @@ declare_clippy_lint! { /// # let status_code = 200; /// if status_code <= 400 && status_code > 500 {} /// ``` - #[clippy::version = "1.71.0"] + #[clippy::version = "1.73.0"] pub IMPOSSIBLE_COMPARISONS, correctness, "double comparisons that will never evaluate to `true`" @@ -332,7 +332,7 @@ declare_clippy_lint! { /// # let status_code = 200; /// if status_code <= 400 && status_code < 500 {} /// ``` - #[clippy::version = "1.71.0"] + #[clippy::version = "1.73.0"] pub REDUNDANT_COMPARISONS, correctness, "double comparisons where one of them can be removed" diff --git a/clippy_lints/src/raw_strings.rs b/clippy_lints/src/raw_strings.rs index 8a7e487466610..c951d9a4a09d5 100644 --- a/clippy_lints/src/raw_strings.rs +++ b/clippy_lints/src/raw_strings.rs @@ -75,6 +75,7 @@ impl EarlyLintPass for RawStrings { if !snippet(cx, expr.span, prefix).trim().starts_with(prefix) { return; } + let descr = lit.kind.descr(); if !str.contains(['\\', '"']) { span_lint_and_then( @@ -89,20 +90,17 @@ impl EarlyLintPass for RawStrings { let r_pos = expr.span.lo() + BytePos::from_usize(prefix.len() - 1); let start = start.with_lo(r_pos); - if end.is_empty() { - diag.span_suggestion( - start, - "use a string literal instead", - format!("\"{str}\""), - Applicability::MachineApplicable, - ); - } else { - diag.multipart_suggestion( - "try", - vec![(start, String::new()), (end, String::new())], - Applicability::MachineApplicable, - ); + let mut remove = vec![(start, String::new())]; + // avoid debug ICE from empty suggestions + if !end.is_empty() { + remove.push((end, String::new())); } + + diag.multipart_suggestion_verbose( + format!("use a plain {descr} literal instead"), + remove, + Applicability::MachineApplicable, + ); }, ); if !matches!(cx.get_lint_level(NEEDLESS_RAW_STRINGS), rustc_lint::Allow) { @@ -149,9 +147,9 @@ impl EarlyLintPass for RawStrings { let (start, end) = hash_spans(expr.span, prefix, req, max); let message = match max - req { - _ if req == 0 => "remove all the hashes around the literal".to_string(), - 1 => "remove one hash from both sides of the literal".to_string(), - n => format!("remove {n} hashes from both sides of the literal"), + _ if req == 0 => format!("remove all the hashes around the {descr} literal"), + 1 => format!("remove one hash from both sides of the {descr} literal"), + n => format!("remove {n} hashes from both sides of the {descr} literal"), }; diag.multipart_suggestion( diff --git a/clippy_lints/src/redundant_locals.rs b/clippy_lints/src/redundant_locals.rs index 0c89c7ee47d36..197742b5dd41d 100644 --- a/clippy_lints/src/redundant_locals.rs +++ b/clippy_lints/src/redundant_locals.rs @@ -3,11 +3,9 @@ use clippy_utils::is_from_proc_macro; use clippy_utils::ty::needs_ordered_drop; use rustc_ast::Mutability; use rustc_hir::def::Res; -use rustc_hir::{ - BindingAnnotation, ByRef, Expr, ExprKind, HirId, Local, Node, Pat, PatKind, QPath, -}; +use rustc_hir::{BindingAnnotation, ByRef, ExprKind, HirId, Local, Node, Pat, PatKind, QPath}; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::lint::{in_external_macro, is_from_async_await}; +use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::symbol::Ident; use rustc_span::DesugaringKind; @@ -39,7 +37,7 @@ declare_clippy_lint! { /// // no redefinition with the same name /// } /// ``` - #[clippy::version = "1.72.0"] + #[clippy::version = "1.73.0"] pub REDUNDANT_LOCALS, correctness, "redundant redefinition of a local binding" @@ -68,21 +66,18 @@ impl<'tcx> LateLintPass<'tcx> for RedundantLocals { // the local does not change the effect of assignments to the binding. see #11290 if !affects_assignments(cx, mutability, binding_id, local.hir_id); // the local does not affect the code's drop behavior - if !affects_drop_behavior(cx, binding_id, local.hir_id, expr); + if !needs_ordered_drop(cx, cx.typeck_results().expr_ty(expr)); // the local is user-controlled if !in_external_macro(cx.sess(), local.span); if !is_from_proc_macro(cx, expr); - // Async function parameters are lowered into the closure body, so we can't lint them. - // see `lower_maybe_async_body` in `rust_ast_lowering` - if !is_from_async_await(local.span); then { span_lint_and_help( cx, REDUNDANT_LOCALS, - vec![binding_pat.span, local.span], - "redundant redefinition of a binding", - None, - &format!("remove the redefinition of `{ident}`"), + local.span, + &format!("redundant redefinition of a binding `{ident}`"), + Some(binding_pat.span), + &format!("`{ident}` is initially defined here"), ); } } @@ -109,18 +104,3 @@ fn affects_assignments(cx: &LateContext<'_>, mutability: Mutability, bind: HirId // the binding is mutable and the rebinding is in a different scope than the original binding mutability == Mutability::Mut && hir.get_enclosing_scope(bind) != hir.get_enclosing_scope(rebind) } - -/// Check if a rebinding of a local affects the code's drop behavior. -fn affects_drop_behavior<'tcx>( - cx: &LateContext<'tcx>, - bind: HirId, - rebind: HirId, - rebind_expr: &Expr<'tcx>, -) -> bool { - let hir = cx.tcx.hir(); - - // the rebinding is in a different scope than the original binding - // and the type of the binding cares about drop order - hir.get_enclosing_scope(bind) != hir.get_enclosing_scope(rebind) - && needs_ordered_drop(cx, cx.typeck_results().expr_ty(rebind_expr)) -} diff --git a/clippy_lints/src/std_instead_of_core.rs b/clippy_lints/src/std_instead_of_core.rs index 5f54a10d1c41d..b7396535eedff 100644 --- a/clippy_lints/src/std_instead_of_core.rs +++ b/clippy_lints/src/std_instead_of_core.rs @@ -1,9 +1,11 @@ use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::is_from_proc_macro; use rustc_errors::Applicability; use rustc_hir::def::Res; use rustc_hir::def_id::DefId; use rustc_hir::{HirId, Path, PathSegment}; -use rustc_lint::{LateContext, LateLintPass}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_middle::lint::in_external_macro; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::symbol::kw; use rustc_span::{sym, Span}; @@ -99,6 +101,8 @@ impl<'tcx> LateLintPass<'tcx> for StdReexports { if let Res::Def(_, def_id) = path.res && let Some(first_segment) = get_first_segment(path) && is_stable(cx, def_id) + && !in_external_macro(cx.sess(), path.span) + && !is_from_proc_macro(cx, &first_segment.ident) { let (lint, used_mod, replace_with) = match first_segment.ident.name { sym::std => match cx.tcx.crate_name(def_id.krate) { diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index 75c3c7a958a21..23da1de77303e 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -294,7 +294,7 @@ define_Conf! { /// /// Suppress lints whenever the suggested change would cause breakage for other crates. (avoid_breaking_exported_api: bool = true), - /// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, OPTION_MAP_UNWRAP_OR, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT, DEPRECATED_CFG_ATTR, INDEX_REFUTABLE_SLICE, MAP_CLONE, BORROW_AS_PTR, MANUAL_BITS, ERR_EXPECT, CAST_ABS_TO_UNSIGNED, UNINLINED_FORMAT_ARGS, MANUAL_CLAMP, MANUAL_LET_ELSE, UNCHECKED_DURATION_SUBTRACTION, COLLAPSIBLE_STR_REPLACE, SEEK_FROM_CURRENT, SEEK_REWIND, UNNECESSARY_LAZY_EVALUATIONS, TRANSMUTE_PTR_TO_REF, ALMOST_COMPLETE_RANGE, NEEDLESS_BORROW, DERIVABLE_IMPLS, MANUAL_IS_ASCII_CHECK, MANUAL_REM_EUCLID, MANUAL_RETAIN, TYPE_REPETITION_IN_BOUNDS, TUPLE_ARRAY_CONVERSIONS, MANUAL_TRY_FOLD. + /// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, OPTION_MAP_UNWRAP_OR, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT, DEPRECATED_CFG_ATTR, INDEX_REFUTABLE_SLICE, MAP_CLONE, BORROW_AS_PTR, MANUAL_BITS, ERR_EXPECT, CAST_ABS_TO_UNSIGNED, UNINLINED_FORMAT_ARGS, MANUAL_CLAMP, MANUAL_LET_ELSE, UNCHECKED_DURATION_SUBTRACTION, COLLAPSIBLE_STR_REPLACE, SEEK_FROM_CURRENT, SEEK_REWIND, UNNECESSARY_LAZY_EVALUATIONS, TRANSMUTE_PTR_TO_REF, ALMOST_COMPLETE_RANGE, NEEDLESS_BORROW, DERIVABLE_IMPLS, MANUAL_IS_ASCII_CHECK, MANUAL_REM_EUCLID, MANUAL_RETAIN, TYPE_REPETITION_IN_BOUNDS, TUPLE_ARRAY_CONVERSIONS, MANUAL_TRY_FOLD, MANUAL_HASH_ONE. /// /// The minimum rust version that the project supports (msrv: Option = None), @@ -744,3 +744,44 @@ fn calculate_dimensions(fields: &[&str]) -> (usize, Vec) { (rows, column_widths) } + +#[cfg(test)] +mod tests { + use rustc_data_structures::fx::{FxHashMap, FxHashSet}; + use serde::de::IgnoredAny; + use std::fs; + use walkdir::WalkDir; + + #[test] + fn configs_are_tested() { + let mut names: FxHashSet = super::metadata::get_configuration_metadata() + .into_iter() + .map(|meta| meta.name.replace('_', "-")) + .collect(); + + let toml_files = WalkDir::new("../tests") + .into_iter() + .map(Result::unwrap) + .filter(|entry| entry.file_name() == "clippy.toml"); + + for entry in toml_files { + let file = fs::read_to_string(entry.path()).unwrap(); + #[allow(clippy::zero_sized_map_values)] + if let Ok(map) = toml::from_str::>(&file) { + for name in map.keys() { + names.remove(name.as_str()); + } + } + } + + assert!( + names.remove("allow-one-hash-in-raw-strings"), + "remove this when #11481 is fixed" + ); + + assert!( + names.is_empty(), + "Configuration variable lacks test: {names:?}\nAdd a test to `tests/ui-toml`" + ); + } +} diff --git a/clippy_lints/src/wildcard_imports.rs b/clippy_lints/src/wildcard_imports.rs index d09d02a7dfda9..70b83149ce1a6 100644 --- a/clippy_lints/src/wildcard_imports.rs +++ b/clippy_lints/src/wildcard_imports.rs @@ -132,6 +132,7 @@ impl LateLintPass<'_> for WildcardImports { if self.warn_on_all || !self.check_exceptions(item, use_path.segments); let used_imports = cx.tcx.names_imported_by_glob_use(item.owner_id.def_id); if !used_imports.is_empty(); // Already handled by `unused_imports` + if !used_imports.contains(&kw::Underscore); then { let mut applicability = Applicability::MachineApplicable; let import_source_snippet = snippet_with_applicability(cx, use_path.span, "..", &mut applicability); diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs index da083fb14aae1..855aefa70cb15 100644 --- a/clippy_lints/src/write.rs +++ b/clippy_lints/src/write.rs @@ -3,12 +3,15 @@ use clippy_utils::macros::{find_format_args, format_arg_removal_span, root_macro use clippy_utils::source::{expand_past_previous_comma, snippet_opt}; use clippy_utils::{is_in_cfg_test, is_in_test_function}; use rustc_ast::token::LitKind; -use rustc_ast::{FormatArgPosition, FormatArgs, FormatArgsPiece, FormatOptions, FormatPlaceholder, FormatTrait}; +use rustc_ast::{ + FormatArgPosition, FormatArgPositionKind, FormatArgs, FormatArgsPiece, FormatOptions, FormatPlaceholder, + FormatTrait, +}; use rustc_errors::Applicability; use rustc_hir::{Expr, Impl, Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use rustc_span::{sym, BytePos}; +use rustc_span::{sym, BytePos, Span}; declare_clippy_lint! { /// ### What it does @@ -450,6 +453,12 @@ fn check_empty_string(cx: &LateContext<'_>, format_args: &FormatArgs, macro_call fn check_literal(cx: &LateContext<'_>, format_args: &FormatArgs, name: &str) { let arg_index = |argument: &FormatArgPosition| argument.index.unwrap_or_else(|pos| pos); + let lint_name = if name.starts_with("write") { + WRITE_LITERAL + } else { + PRINT_LITERAL + }; + let mut counts = vec![0u32; format_args.arguments.all_args().len()]; for piece in &format_args.template { if let FormatArgsPiece::Placeholder(placeholder) = piece { @@ -457,6 +466,12 @@ fn check_literal(cx: &LateContext<'_>, format_args: &FormatArgs, name: &str) { } } + let mut suggestion: Vec<(Span, String)> = vec![]; + // holds index of replaced positional arguments; used to decrement the index of the remaining + // positional arguments. + let mut replaced_position: Vec = vec![]; + let mut sug_span: Option = None; + for piece in &format_args.template { if let FormatArgsPiece::Placeholder(FormatPlaceholder { argument, @@ -471,9 +486,9 @@ fn check_literal(cx: &LateContext<'_>, format_args: &FormatArgs, name: &str) { && let rustc_ast::ExprKind::Lit(lit) = &arg.expr.kind && !arg.expr.span.from_expansion() && let Some(value_string) = snippet_opt(cx, arg.expr.span) - { + { let (replacement, replace_raw) = match lit.kind { - LitKind::Str | LitKind::StrRaw(_) => match extract_str_literal(&value_string) { + LitKind::Str | LitKind::StrRaw(_) => match extract_str_literal(&value_string) { Some(extracted) => extracted, None => return, }, @@ -493,12 +508,6 @@ fn check_literal(cx: &LateContext<'_>, format_args: &FormatArgs, name: &str) { _ => continue, }; - let lint = if name.starts_with("write") { - WRITE_LITERAL - } else { - PRINT_LITERAL - }; - let Some(format_string_snippet) = snippet_opt(cx, format_args.span) else { continue }; let format_string_is_raw = format_string_snippet.starts_with('r'); @@ -519,29 +528,58 @@ fn check_literal(cx: &LateContext<'_>, format_args: &FormatArgs, name: &str) { }, }; - span_lint_and_then( - cx, - lint, - arg.expr.span, - "literal with an empty format string", - |diag| { - if let Some(replacement) = replacement - // `format!("{}", "a")`, `format!("{named}", named = "b") - // ~~~~~ ~~~~~~~~~~~~~ - && let Some(removal_span) = format_arg_removal_span(format_args, index) - { - let replacement = replacement.replace('{', "{{").replace('}', "}}"); - diag.multipart_suggestion( - "try", - vec![(*placeholder_span, replacement), (removal_span, String::new())], - Applicability::MachineApplicable, - ); - } - }, - ); + sug_span = Some(sug_span.unwrap_or(arg.expr.span).to(arg.expr.span)); + + if let Some((_, index)) = positional_arg_piece_span(piece) { + replaced_position.push(index); + } + + if let Some(replacement) = replacement + // `format!("{}", "a")`, `format!("{named}", named = "b") + // ~~~~~ ~~~~~~~~~~~~~ + && let Some(removal_span) = format_arg_removal_span(format_args, index) { + let replacement = escape_braces(&replacement, !format_string_is_raw && !replace_raw); + suggestion.push((*placeholder_span, replacement)); + suggestion.push((removal_span, String::new())); + } + } + } + // Decrement the index of the remaining by the number of replaced positional arguments + if !suggestion.is_empty() { + for piece in &format_args.template { + if let Some((span, index)) = positional_arg_piece_span(piece) + && suggestion.iter().all(|(s, _)| *s != span) { + let decrement = replaced_position.iter().filter(|i| **i < index).count(); + suggestion.push((span, format!("{{{}}}", index.saturating_sub(decrement)))); + } } } + + if let Some(span) = sug_span { + span_lint_and_then(cx, lint_name, span, "literal with an empty format string", |diag| { + if !suggestion.is_empty() { + diag.multipart_suggestion("try", suggestion, Applicability::MachineApplicable); + } + }); + } +} + +/// Extract Span and its index from the given `piece`, iff it's positional argument. +fn positional_arg_piece_span(piece: &FormatArgsPiece) -> Option<(Span, usize)> { + match piece { + FormatArgsPiece::Placeholder(FormatPlaceholder { + argument: + FormatArgPosition { + index: Ok(index), + kind: FormatArgPositionKind::Number, + .. + }, + span: Some(span), + .. + }) => Some((*span, *index)), + _ => None, + } } /// Removes the raw marker, `#`s and quotes from a str, and returns if the literal is raw @@ -593,3 +631,47 @@ fn conservative_unescape(literal: &str) -> Result { if err { Err(UnescapeErr::Lint) } else { Ok(unescaped) } } + +/// Replaces `{` with `{{` and `}` with `}}`. If `preserve_unicode_escapes` is `true` the braces in +/// `\u{xxxx}` are left unmodified +#[expect(clippy::match_same_arms)] +fn escape_braces(literal: &str, preserve_unicode_escapes: bool) -> String { + #[derive(Clone, Copy)] + enum State { + Normal, + Backslash, + UnicodeEscape, + } + + let mut escaped = String::with_capacity(literal.len()); + let mut state = State::Normal; + + for ch in literal.chars() { + state = match (ch, state) { + // Escape braces outside of unicode escapes by doubling them up + ('{' | '}', State::Normal) => { + escaped.push(ch); + State::Normal + }, + // If `preserve_unicode_escapes` isn't enabled stay in `State::Normal`, otherwise: + // + // \u{aaaa} \\ \x01 + // ^ ^ ^ + ('\\', State::Normal) if preserve_unicode_escapes => State::Backslash, + // \u{aaaa} + // ^ + ('u', State::Backslash) => State::UnicodeEscape, + // \xAA \\ + // ^ ^ + (_, State::Backslash) => State::Normal, + // \u{aaaa} + // ^ + ('}', State::UnicodeEscape) => State::Normal, + _ => state, + }; + + escaped.push(ch); + } + + escaped +} diff --git a/clippy_utils/Cargo.toml b/clippy_utils/Cargo.toml index 1596bb773976a..8522493f67b3a 100644 --- a/clippy_utils/Cargo.toml +++ b/clippy_utils/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy_utils" -version = "0.1.74" +version = "0.1.75" edition = "2021" publish = false diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs index d596eed4b7c4d..0bae7056c4fb8 100644 --- a/clippy_utils/src/consts.rs +++ b/clippy_utils/src/consts.rs @@ -9,11 +9,12 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::{BinOp, BinOpKind, Block, ConstBlock, Expr, ExprKind, HirId, Item, ItemKind, Node, QPath, UnOp}; use rustc_lexer::tokenize; use rustc_lint::LateContext; -use rustc_middle::mir::interpret::Scalar; +use rustc_middle::mir::interpret::{alloc_range, Scalar}; use rustc_middle::ty::{self, EarlyBinder, FloatTy, GenericArgsRef, List, ScalarInt, Ty, TyCtxt}; use rustc_middle::{bug, mir, span_bug}; use rustc_span::symbol::{Ident, Symbol}; use rustc_span::SyntaxContext; +use rustc_target::abi::Size; use std::cmp::Ordering::{self, Equal}; use std::hash::{Hash, Hasher}; use std::iter; @@ -403,7 +404,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { && adt_def.is_struct() && let Some(desired_field) = field_of_struct(*adt_def, self.lcx, *constant, field) { - miri_to_const(self.lcx, desired_field) + mir_to_const(self.lcx, desired_field) } else { result @@ -483,7 +484,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { .const_eval_resolve(self.param_env, mir::UnevaluatedConst::new(def_id, args), None) .ok() .map(|val| rustc_middle::mir::Const::from_value(val, ty))?; - let result = miri_to_const(self.lcx, result)?; + let result = mir_to_const(self.lcx, result)?; self.source = ConstantSource::Constant; Some(result) }, @@ -655,10 +656,14 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { } } -pub fn miri_to_const<'tcx>(lcx: &LateContext<'tcx>, result: mir::Const<'tcx>) -> Option> { +pub fn mir_to_const<'tcx>(lcx: &LateContext<'tcx>, result: mir::Const<'tcx>) -> Option> { use rustc_middle::mir::ConstValue; - match result { - mir::Const::Val(ConstValue::Scalar(Scalar::Int(int)), _) => match result.ty().kind() { + let mir::Const::Val(val, _) = result else { + // We only work on evaluated consts. + return None; + }; + match (val, result.ty().kind()) { + (ConstValue::Scalar(Scalar::Int(int)), _) => match result.ty().kind() { ty::Adt(adt_def, _) if adt_def.is_struct() => Some(Constant::Adt(result)), ty::Bool => Some(Constant::Bool(int == ScalarInt::TRUE)), ty::Uint(_) | ty::Int(_) => Some(Constant::Int(int.assert_bits(int.size()))), @@ -671,42 +676,28 @@ pub fn miri_to_const<'tcx>(lcx: &LateContext<'tcx>, result: mir::Const<'tcx>) -> ty::RawPtr(_) => Some(Constant::RawPtr(int.assert_bits(int.size()))), _ => None, }, - mir::Const::Val(cv, _) if matches!(result.ty().kind(), ty::Ref(_, inner_ty, _) if matches!(inner_ty.kind(), ty::Str)) => - { - let data = cv.try_get_slice_bytes_for_diagnostics(lcx.tcx)?; + (_, ty::Ref(_, inner_ty, _)) if matches!(inner_ty.kind(), ty::Str) => { + let data = val.try_get_slice_bytes_for_diagnostics(lcx.tcx)?; String::from_utf8(data.to_owned()).ok().map(Constant::Str) }, - mir::Const::Val(ConstValue::Indirect { alloc_id, offset: _ }, _) => { - let alloc = lcx.tcx.global_alloc(alloc_id).unwrap_memory(); - match result.ty().kind() { - ty::Adt(adt_def, _) if adt_def.is_struct() => Some(Constant::Adt(result)), - ty::Array(sub_type, len) => match sub_type.kind() { - ty::Float(FloatTy::F32) => match len.try_to_target_usize(lcx.tcx) { - Some(len) => alloc - .inner() - .inspect_with_uninit_and_ptr_outside_interpreter(0..(4 * usize::try_from(len).unwrap())) - .to_owned() - .array_chunks::<4>() - .map(|&chunk| Some(Constant::F32(f32::from_le_bytes(chunk)))) - .collect::>>>() - .map(Constant::Vec), - _ => None, - }, - ty::Float(FloatTy::F64) => match len.try_to_target_usize(lcx.tcx) { - Some(len) => alloc - .inner() - .inspect_with_uninit_and_ptr_outside_interpreter(0..(8 * usize::try_from(len).unwrap())) - .to_owned() - .array_chunks::<8>() - .map(|&chunk| Some(Constant::F64(f64::from_le_bytes(chunk)))) - .collect::>>>() - .map(Constant::Vec), - _ => None, - }, - _ => None, - }, - _ => None, + (_, ty::Adt(adt_def, _)) if adt_def.is_struct() => Some(Constant::Adt(result)), + (ConstValue::Indirect { alloc_id, offset }, ty::Array(sub_type, len)) => { + let alloc = lcx.tcx.global_alloc(alloc_id).unwrap_memory().inner(); + let len = len.try_to_target_usize(lcx.tcx)?; + let ty::Float(flt) = sub_type.kind() else { + return None; + }; + let size = Size::from_bits(flt.bit_width()); + let mut res = Vec::new(); + for idx in 0..len { + let range = alloc_range(offset + size * idx, size); + let val = alloc.read_scalar(&lcx.tcx, range, /* read_provenance */ false).ok()?; + res.push(match flt { + FloatTy::F32 => Constant::F32(f32::from_bits(val.to_u32().ok()?)), + FloatTy::F64 => Constant::F64(f64::from_bits(val.to_u64().ok()?)), + }); } + Some(Constant::Vec(res)) }, _ => None, } diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 64ca2ff787363..c2c97259d38bf 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -80,7 +80,6 @@ use std::sync::{Mutex, MutexGuard, OnceLock}; use if_chain::if_chain; use itertools::Itertools; use rustc_ast::ast::{self, LitKind, RangeLimits}; -use rustc_ast::Attribute; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::unhash::UnhashMap; use rustc_hir::def::{DefKind, Res}; @@ -113,7 +112,7 @@ use rustc_span::{sym, Span}; use rustc_target::abi::Integer; use visitors::Visitable; -use crate::consts::{constant, miri_to_const, Constant}; +use crate::consts::{constant, mir_to_const, Constant}; use crate::higher::Range; use crate::ty::{ adt_and_variant_of_res, can_partially_move_ty, expr_sig, is_copy, is_recursively_primitive_type, @@ -1509,9 +1508,7 @@ pub fn is_range_full(cx: &LateContext<'_>, expr: &Expr<'_>, container_path: Opti if let rustc_ty::Adt(_, subst) = ty.kind() && let bnd_ty = subst.type_at(0) && let Some(min_val) = bnd_ty.numeric_min_val(cx.tcx) - && let const_val = cx.tcx.valtree_to_const_val((bnd_ty, min_val.to_valtree())) - && let min_const_kind = Const::from_value(const_val, bnd_ty) - && let Some(min_const) = miri_to_const(cx, min_const_kind) + && let Some(min_const) = mir_to_const(cx, Const::from_ty_const(min_val, cx.tcx)) && let Some(start_const) = constant(cx, cx.typeck_results(), start) { start_const == min_const @@ -1525,9 +1522,7 @@ pub fn is_range_full(cx: &LateContext<'_>, expr: &Expr<'_>, container_path: Opti if let rustc_ty::Adt(_, subst) = ty.kind() && let bnd_ty = subst.type_at(0) && let Some(max_val) = bnd_ty.numeric_max_val(cx.tcx) - && let const_val = cx.tcx.valtree_to_const_val((bnd_ty, max_val.to_valtree())) - && let max_const_kind = Const::from_value(const_val, bnd_ty) - && let Some(max_const) = miri_to_const(cx, max_const_kind) + && let Some(max_const) = mir_to_const(cx, Const::from_ty_const(max_val, cx.tcx)) && let Some(end_const) = constant(cx, cx.typeck_results(), end) { end_const == max_const @@ -2456,11 +2451,12 @@ pub fn is_in_test_function(tcx: TyCtxt<'_>, id: hir::HirId) -> bool { }) } -/// Checks if the item containing the given `HirId` has `#[cfg(test)]` attribute applied +/// Checks if `id` has a `#[cfg(test)]` attribute applied /// -/// Note: Add `//@compile-flags: --test` to UI tests with a `#[cfg(test)]` function -pub fn is_in_cfg_test(tcx: TyCtxt<'_>, id: hir::HirId) -> bool { - fn is_cfg_test(attr: &Attribute) -> bool { +/// This only checks directly applied attributes, to see if a node is inside a `#[cfg(test)]` parent +/// use [`is_in_cfg_test`] +pub fn is_cfg_test(tcx: TyCtxt<'_>, id: hir::HirId) -> bool { + tcx.hir().attrs(id).iter().any(|attr| { if attr.has_name(sym::cfg) && let Some(items) = attr.meta_item_list() && let [item] = &*items @@ -2470,11 +2466,14 @@ pub fn is_in_cfg_test(tcx: TyCtxt<'_>, id: hir::HirId) -> bool { } else { false } - } + }) +} + +/// Checks if any parent node of `HirId` has `#[cfg(test)]` attribute applied +pub fn is_in_cfg_test(tcx: TyCtxt<'_>, id: hir::HirId) -> bool { tcx.hir() - .parent_iter(id) - .flat_map(|(parent_id, _)| tcx.hir().attrs(parent_id)) - .any(is_cfg_test) + .parent_id_iter(id) + .any(|parent_id| is_cfg_test(tcx, parent_id)) } /// Checks if the item of any of its parents has `#[cfg(...)]` attribute applied. diff --git a/clippy_utils/src/msrvs.rs b/clippy_utils/src/msrvs.rs index 0faff05eb2319..df839c2106f14 100644 --- a/clippy_utils/src/msrvs.rs +++ b/clippy_utils/src/msrvs.rs @@ -19,7 +19,7 @@ macro_rules! msrv_aliases { // names may refer to stabilized feature flags or library items msrv_aliases! { - 1,71,0 { TUPLE_ARRAY_CONVERSIONS } + 1,71,0 { TUPLE_ARRAY_CONVERSIONS, BUILD_HASHER_HASH_ONE } 1,70,0 { OPTION_IS_SOME_AND, BINARY_HEAP_RETAIN } 1,68,0 { PATH_MAIN_SEPARATOR_STR } 1,65,0 { LET_ELSE, POINTER_CAST_CONSTNESS } diff --git a/clippy_utils/src/visitors.rs b/clippy_utils/src/visitors.rs index 3b47a451345eb..d752fe7d97ebf 100644 --- a/clippy_utils/src/visitors.rs +++ b/clippy_utils/src/visitors.rs @@ -62,6 +62,27 @@ where } } } +impl<'tcx, A, B> Visitable<'tcx> for (A, B) +where + A: Visitable<'tcx>, + B: Visitable<'tcx>, +{ + fn visit>(self, visitor: &mut V) { + let (a, b) = self; + a.visit(visitor); + b.visit(visitor); + } +} +impl<'tcx, T> Visitable<'tcx> for Option +where + T: Visitable<'tcx>, +{ + fn visit>(self, visitor: &mut V) { + if let Some(x) = self { + x.visit(visitor); + } + } +} macro_rules! visitable_ref { ($t:ident, $f:ident) => { impl<'tcx> Visitable<'tcx> for &'tcx $t<'tcx> { @@ -748,3 +769,26 @@ pub fn contains_break_or_continue(expr: &Expr<'_>) -> bool { }) .is_some() } + +/// If the local is only used once in `visitable` returns the path expression referencing the given +/// local +pub fn local_used_once<'tcx>( + cx: &LateContext<'tcx>, + visitable: impl Visitable<'tcx>, + id: HirId, +) -> Option<&'tcx Expr<'tcx>> { + let mut expr = None; + + let cf = for_each_expr_with_closures(cx, visitable, |e| { + if path_to_local_id(e, id) && expr.replace(e).is_some() { + ControlFlow::Break(()) + } else { + ControlFlow::Continue(()) + } + }); + if cf.is_some() { + return None; + } + + expr +} diff --git a/declare_clippy_lint/Cargo.toml b/declare_clippy_lint/Cargo.toml index 1470da61fac0c..beea9fd00e7a9 100644 --- a/declare_clippy_lint/Cargo.toml +++ b/declare_clippy_lint/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "declare_clippy_lint" -version = "0.1.74" +version = "0.1.75" edition = "2021" publish = false diff --git a/rust-toolchain b/rust-toolchain index 5ce22b65f0074..fe2c77ab47f00 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2023-09-25" +channel = "nightly-2023-10-06" components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] diff --git a/src/driver.rs b/src/driver.rs index 1d89477dcc16b..d47767faed9ed 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -26,6 +26,8 @@ use std::ops::Deref; use std::path::Path; use std::process::exit; +use anstream::println; + /// If a command-line option matches `find_arg`, then apply the predicate `pred` on its value. If /// true, then return it. The parameter is assumed to be either `--arg=value` or `--arg value`. fn arg_value<'a, T: Deref>( @@ -162,39 +164,15 @@ impl rustc_driver::Callbacks for ClippyCallbacks { } } +#[allow(clippy::ignored_unit_patterns)] fn display_help() { - println!( - "\ -Checks a package to catch common mistakes and improve your Rust code. - -Usage: - cargo clippy [options] [--] [...] - -Common options: - -h, --help Print this message - --rustc Pass all args to rustc - -V, --version Print version info and exit - -For the other options see `cargo check --help`. - -To allow or deny a lint from the command line you can use `cargo clippy --` -with: - - -W --warn OPT Set lint warnings - -A --allow OPT Set lint allowed - -D --deny OPT Set lint denied - -F --forbid OPT Set lint forbidden - -You can use tool lints to allow or deny lints from your code, eg.: - - #[allow(clippy::needless_lifetimes)] -" - ); + println!("{}", help_message()); } const BUG_REPORT_URL: &str = "https://github.com/rust-lang/rust-clippy/issues/new?template=ice.yml"; #[allow(clippy::too_many_lines)] +#[allow(clippy::ignored_unit_patterns)] pub fn main() { let handler = EarlyErrorHandler::new(ErrorOutputType::default()); @@ -236,6 +214,7 @@ pub fn main() { if orig_args.iter().any(|a| a == "--version" || a == "-V") { let version_info = rustc_tools_util::get_version_info!(); + println!("{version_info}"); exit(0); } @@ -292,3 +271,25 @@ pub fn main() { } })) } + +#[must_use] +fn help_message() -> &'static str { + color_print::cstr!( + "Checks a file to catch common mistakes and improve your Rust code. +Run clippy-driver with the same arguments you use for rustc + +Usage: + clippy-driver [OPTIONS] INPUT + +Common options: + -h, --help Print this message + -V, --version Print version info and exit + --rustc Pass all arguments to rustc + +Allowing / Denying lints +You can use tool lints to allow or deny lints from your code, e.g.: + + #[allow(clippy::needless_lifetimes)] +" + ) +} diff --git a/src/main.rs b/src/main.rs index 26b655076cf65..bbf7d22c85043 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,37 +6,14 @@ use std::env; use std::path::PathBuf; use std::process::{self, Command}; -const CARGO_CLIPPY_HELP: &str = "Checks a package to catch common mistakes and improve your Rust code. - -Usage: - cargo clippy [options] [--] [...] - -Common options: - --no-deps Run Clippy only on the given crate, without linting the dependencies - --fix Automatically apply lint suggestions. This flag implies `--no-deps` and `--all-targets` - -h, --help Print this message - -V, --version Print version info and exit - --explain LINT Print the documentation for a given lint - -For the other options see `cargo check --help`. - -To allow or deny a lint from the command line you can use `cargo clippy --` -with: - - -W --warn OPT Set lint warnings - -A --allow OPT Set lint allowed - -D --deny OPT Set lint denied - -F --forbid OPT Set lint forbidden - -You can use tool lints to allow or deny lints from your code, e.g.: - - #[allow(clippy::needless_lifetimes)] -"; +use anstream::println; +#[allow(clippy::ignored_unit_patterns)] fn show_help() { - println!("{CARGO_CLIPPY_HELP}"); + println!("{}", help_message()); } +#[allow(clippy::ignored_unit_patterns)] fn show_version() { let version_info = rustc_tools_util::get_version_info!(); println!("{version_info}"); @@ -168,6 +145,38 @@ where } } +#[must_use] +pub fn help_message() -> &'static str { + color_print::cstr!( +"Checks a package to catch common mistakes and improve your Rust code. + +Usage: + cargo clippy [OPTIONS] [--] [<>...] + +Common options: + --no-deps Run Clippy only on the given crate, without linting the dependencies + --fix Automatically apply lint suggestions. This flag implies --no-deps and --all-targets + -h, --help Print this message + -V, --version Print version info and exit + --explain [LINT] Print the documentation for a given lint + +See all options with cargo check --help. + +Allowing / Denying lints + +To allow or deny a lint from the command line you can use cargo clippy -- with: + + -W / --warn [LINT] Set lint warnings + -A / --allow [LINT] Set lint allowed + -D / --deny [LINT] Set lint denied + -F / --forbid [LINT] Set lint forbidden + +You can use tool lints to allow or deny lints from your code, e.g.: + + #[allow(clippy::needless_lifetimes)] +" + ) +} #[cfg(test)] mod tests { use super::ClippyCmd; diff --git a/tests/ui/auxiliary/proc_macro_derive.rs b/tests/ui/auxiliary/proc_macro_derive.rs index 37f0ec2b37d88..79a95d775b11e 100644 --- a/tests/ui/auxiliary/proc_macro_derive.rs +++ b/tests/ui/auxiliary/proc_macro_derive.rs @@ -21,6 +21,18 @@ pub fn derive(_: TokenStream) -> TokenStream { output } +#[proc_macro_derive(ImplStructWithStdDisplay)] +pub fn derive_std(_: TokenStream) -> TokenStream { + quote! { + struct A {} + impl ::std::fmt::Display for A { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + write!(f, "A") + } + } + } +} + #[proc_macro_derive(FieldReassignWithDefault)] pub fn derive_foo(_input: TokenStream) -> TokenStream { quote! { @@ -141,3 +153,19 @@ pub fn shadow_derive(_: TokenStream) -> TokenStream { .into(), ]) } + +#[proc_macro_derive(StructIgnoredUnitPattern)] +pub fn derive_ignored_unit_pattern(_: TokenStream) -> TokenStream { + quote! { + struct A; + impl A { + fn a(&self) -> Result<(), ()> { + unimplemented!() + } + + pub fn b(&self) { + let _ = self.a().unwrap(); + } + } + } +} diff --git a/tests/ui/ignored_unit_patterns.fixed b/tests/ui/ignored_unit_patterns.fixed index 6c6f21fee16b0..15eaf1f659abf 100644 --- a/tests/ui/ignored_unit_patterns.fixed +++ b/tests/ui/ignored_unit_patterns.fixed @@ -1,3 +1,4 @@ +//@aux-build:proc_macro_derive.rs #![warn(clippy::ignored_unit_patterns)] #![allow(clippy::let_unit_value, clippy::redundant_pattern_matching, clippy::single_match)] @@ -14,8 +15,22 @@ fn main() { //~^ ERROR: matching over `()` is more explicit let _ = foo().map_err(|()| todo!()); //~^ ERROR: matching over `()` is more explicit + + println!( + "{:?}", + match foo() { + Ok(()) => {}, + //~^ ERROR: matching over `()` is more explicit + Err(()) => {}, + //~^ ERROR: matching over `()` is more explicit + } + ); } +// ignored_unit_patterns in derive macro should be ok +#[derive(proc_macro_derive::StructIgnoredUnitPattern)] +pub struct B; + #[allow(unused)] pub fn moo(_: ()) { let () = foo().unwrap(); diff --git a/tests/ui/ignored_unit_patterns.rs b/tests/ui/ignored_unit_patterns.rs index 5e8c2e03ba2cb..9cac3a440aba3 100644 --- a/tests/ui/ignored_unit_patterns.rs +++ b/tests/ui/ignored_unit_patterns.rs @@ -1,3 +1,4 @@ +//@aux-build:proc_macro_derive.rs #![warn(clippy::ignored_unit_patterns)] #![allow(clippy::let_unit_value, clippy::redundant_pattern_matching, clippy::single_match)] @@ -14,8 +15,22 @@ fn main() { //~^ ERROR: matching over `()` is more explicit let _ = foo().map_err(|_| todo!()); //~^ ERROR: matching over `()` is more explicit + + println!( + "{:?}", + match foo() { + Ok(_) => {}, + //~^ ERROR: matching over `()` is more explicit + Err(_) => {}, + //~^ ERROR: matching over `()` is more explicit + } + ); } +// ignored_unit_patterns in derive macro should be ok +#[derive(proc_macro_derive::StructIgnoredUnitPattern)] +pub struct B; + #[allow(unused)] pub fn moo(_: ()) { let _ = foo().unwrap(); diff --git a/tests/ui/ignored_unit_patterns.stderr b/tests/ui/ignored_unit_patterns.stderr index df5e1d89e906e..cac01a87dba0d 100644 --- a/tests/ui/ignored_unit_patterns.stderr +++ b/tests/ui/ignored_unit_patterns.stderr @@ -1,5 +1,5 @@ error: matching over `()` is more explicit - --> $DIR/ignored_unit_patterns.rs:10:12 + --> $DIR/ignored_unit_patterns.rs:11:12 | LL | Ok(_) => {}, | ^ help: use `()` instead of `_`: `()` @@ -8,28 +8,40 @@ LL | Ok(_) => {}, = help: to override `-D warnings` add `#[allow(clippy::ignored_unit_patterns)]` error: matching over `()` is more explicit - --> $DIR/ignored_unit_patterns.rs:11:13 + --> $DIR/ignored_unit_patterns.rs:12:13 | LL | Err(_) => {}, | ^ help: use `()` instead of `_`: `()` error: matching over `()` is more explicit - --> $DIR/ignored_unit_patterns.rs:13:15 + --> $DIR/ignored_unit_patterns.rs:14:15 | LL | if let Ok(_) = foo() {} | ^ help: use `()` instead of `_`: `()` error: matching over `()` is more explicit - --> $DIR/ignored_unit_patterns.rs:15:28 + --> $DIR/ignored_unit_patterns.rs:16:28 | LL | let _ = foo().map_err(|_| todo!()); | ^ help: use `()` instead of `_`: `()` error: matching over `()` is more explicit - --> $DIR/ignored_unit_patterns.rs:21:9 + --> $DIR/ignored_unit_patterns.rs:22:16 + | +LL | Ok(_) => {}, + | ^ help: use `()` instead of `_`: `()` + +error: matching over `()` is more explicit + --> $DIR/ignored_unit_patterns.rs:24:17 + | +LL | Err(_) => {}, + | ^ help: use `()` instead of `_`: `()` + +error: matching over `()` is more explicit + --> $DIR/ignored_unit_patterns.rs:36:9 | LL | let _ = foo().unwrap(); | ^ help: use `()` instead of `_`: `()` -error: aborting due to 5 previous errors +error: aborting due to 7 previous errors diff --git a/tests/ui/infinite_loop.rs b/tests/ui/infinite_loop.rs index 281e12c7b938a..765c670114746 100644 --- a/tests/ui/infinite_loop.rs +++ b/tests/ui/infinite_loop.rs @@ -7,8 +7,6 @@ fn fn_constref(i: &i32) -> i32 { unimplemented!() } fn fn_mutref(i: &mut i32) { - //~^ ERROR: this argument is a mutable reference, but not used mutably - //~| NOTE: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings` unimplemented!() } fn fooi() -> i32 { diff --git a/tests/ui/infinite_loop.stderr b/tests/ui/infinite_loop.stderr index c32b5e323c09e..a78e47d02290c 100644 --- a/tests/ui/infinite_loop.stderr +++ b/tests/ui/infinite_loop.stderr @@ -1,5 +1,5 @@ error: variables in the condition are not mutated in the loop body - --> $DIR/infinite_loop.rs:24:11 + --> $DIR/infinite_loop.rs:22:11 | LL | while y < 10 { | ^^^^^^ @@ -8,7 +8,7 @@ LL | while y < 10 { = note: `#[deny(clippy::while_immutable_condition)]` on by default error: variables in the condition are not mutated in the loop body - --> $DIR/infinite_loop.rs:31:11 + --> $DIR/infinite_loop.rs:29:11 | LL | while y < 10 && x < 3 { | ^^^^^^^^^^^^^^^ @@ -16,7 +16,7 @@ LL | while y < 10 && x < 3 { = note: this may lead to an infinite or to a never running loop error: variables in the condition are not mutated in the loop body - --> $DIR/infinite_loop.rs:40:11 + --> $DIR/infinite_loop.rs:38:11 | LL | while !cond { | ^^^^^ @@ -24,7 +24,7 @@ LL | while !cond { = note: this may lead to an infinite or to a never running loop error: variables in the condition are not mutated in the loop body - --> $DIR/infinite_loop.rs:86:11 + --> $DIR/infinite_loop.rs:84:11 | LL | while i < 3 { | ^^^^^ @@ -32,7 +32,7 @@ LL | while i < 3 { = note: this may lead to an infinite or to a never running loop error: variables in the condition are not mutated in the loop body - --> $DIR/infinite_loop.rs:93:11 + --> $DIR/infinite_loop.rs:91:11 | LL | while i < 3 && j > 0 { | ^^^^^^^^^^^^^^ @@ -40,7 +40,7 @@ LL | while i < 3 && j > 0 { = note: this may lead to an infinite or to a never running loop error: variables in the condition are not mutated in the loop body - --> $DIR/infinite_loop.rs:99:11 + --> $DIR/infinite_loop.rs:97:11 | LL | while i < 3 { | ^^^^^ @@ -48,7 +48,7 @@ LL | while i < 3 { = note: this may lead to an infinite or to a never running loop error: variables in the condition are not mutated in the loop body - --> $DIR/infinite_loop.rs:116:11 + --> $DIR/infinite_loop.rs:114:11 | LL | while i < 3 { | ^^^^^ @@ -56,7 +56,7 @@ LL | while i < 3 { = note: this may lead to an infinite or to a never running loop error: variables in the condition are not mutated in the loop body - --> $DIR/infinite_loop.rs:123:11 + --> $DIR/infinite_loop.rs:121:11 | LL | while i < 3 { | ^^^^^ @@ -64,7 +64,7 @@ LL | while i < 3 { = note: this may lead to an infinite or to a never running loop error: variables in the condition are not mutated in the loop body - --> $DIR/infinite_loop.rs:191:15 + --> $DIR/infinite_loop.rs:189:15 | LL | while self.count < n { | ^^^^^^^^^^^^^^ @@ -72,7 +72,7 @@ LL | while self.count < n { = note: this may lead to an infinite or to a never running loop error: variables in the condition are not mutated in the loop body - --> $DIR/infinite_loop.rs:201:11 + --> $DIR/infinite_loop.rs:199:11 | LL | while y < 10 { | ^^^^^^ @@ -82,7 +82,7 @@ LL | while y < 10 { = help: rewrite it as `if cond { loop { } }` error: variables in the condition are not mutated in the loop body - --> $DIR/infinite_loop.rs:210:11 + --> $DIR/infinite_loop.rs:208:11 | LL | while y < 10 { | ^^^^^^ @@ -91,14 +91,5 @@ LL | while y < 10 { = note: this loop contains `return`s or `break`s = help: rewrite it as `if cond { loop { } }` -error: this argument is a mutable reference, but not used mutably - --> $DIR/infinite_loop.rs:9:17 - | -LL | fn fn_mutref(i: &mut i32) { - | ^^^^^^^^ help: consider changing to: `&i32` - | - = note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::needless_pass_by_ref_mut)]` - -error: aborting due to 12 previous errors +error: aborting due to 11 previous errors diff --git a/tests/ui/into_iter_without_iter.rs b/tests/ui/into_iter_without_iter.rs new file mode 100644 index 0000000000000..6be3bb8abdddc --- /dev/null +++ b/tests/ui/into_iter_without_iter.rs @@ -0,0 +1,124 @@ +//@no-rustfix +#![warn(clippy::into_iter_without_iter)] + +use std::iter::IntoIterator; + +fn main() { + { + struct S; + + impl<'a> IntoIterator for &'a S { + //~^ ERROR: `IntoIterator` implemented for a reference type without an `iter` method + type IntoIter = std::slice::Iter<'a, u8>; + type Item = &'a u8; + fn into_iter(self) -> Self::IntoIter { + todo!() + } + } + impl<'a> IntoIterator for &'a mut S { + //~^ ERROR: `IntoIterator` implemented for a reference type without an `iter_mut` method + type IntoIter = std::slice::IterMut<'a, u8>; + type Item = &'a mut u8; + fn into_iter(self) -> Self::IntoIter { + todo!() + } + } + } + { + struct S(T); + impl<'a, T> IntoIterator for &'a S { + //~^ ERROR: `IntoIterator` implemented for a reference type without an `iter` method + type IntoIter = std::slice::Iter<'a, T>; + type Item = &'a T; + fn into_iter(self) -> Self::IntoIter { + todo!() + } + } + impl<'a, T> IntoIterator for &'a mut S { + //~^ ERROR: `IntoIterator` implemented for a reference type without an `iter_mut` method + type IntoIter = std::slice::IterMut<'a, T>; + type Item = &'a mut T; + fn into_iter(self) -> Self::IntoIter { + todo!() + } + } + } + { + // Both iter and iter_mut methods exist, don't lint + struct S<'a, T>(&'a T); + + impl<'a, T> S<'a, T> { + fn iter(&self) -> std::slice::Iter<'a, T> { + todo!() + } + fn iter_mut(&mut self) -> std::slice::IterMut<'a, T> { + todo!() + } + } + + impl<'a, T> IntoIterator for &S<'a, T> { + type IntoIter = std::slice::Iter<'a, T>; + type Item = &'a T; + fn into_iter(self) -> Self::IntoIter { + todo!() + } + } + + impl<'a, T> IntoIterator for &mut S<'a, T> { + type IntoIter = std::slice::IterMut<'a, T>; + type Item = &'a mut T; + fn into_iter(self) -> Self::IntoIter { + todo!() + } + } + } + { + // Only `iter` exists, no `iter_mut` + struct S<'a, T>(&'a T); + + impl<'a, T> S<'a, T> { + fn iter(&self) -> std::slice::Iter<'a, T> { + todo!() + } + } + + impl<'a, T> IntoIterator for &S<'a, T> { + type IntoIter = std::slice::Iter<'a, T>; + type Item = &'a T; + fn into_iter(self) -> Self::IntoIter { + todo!() + } + } + + impl<'a, T> IntoIterator for &mut S<'a, T> { + //~^ ERROR: `IntoIterator` implemented for a reference type without an `iter_mut` method + type IntoIter = std::slice::IterMut<'a, T>; + type Item = &'a mut T; + fn into_iter(self) -> Self::IntoIter { + todo!() + } + } + } + { + // `iter` exists, but `IntoIterator` is implemented for an alias. inherent_impls doesn't "normalize" + // aliases so that `inherent_impls(Alias)` where `type Alias = S` returns nothing, so this can lead + // to fun FPs. Make sure it doesn't happen here (we're using type_of, which should skip the alias). + struct S; + + impl S { + fn iter(&self) -> std::slice::Iter<'static, u8> { + todo!() + } + } + + type Alias = S; + + impl IntoIterator for &Alias { + type IntoIter = std::slice::Iter<'static, u8>; + type Item = &'static u8; + fn into_iter(self) -> Self::IntoIter { + todo!() + } + } + } +} diff --git a/tests/ui/into_iter_without_iter.stderr b/tests/ui/into_iter_without_iter.stderr new file mode 100644 index 0000000000000..f543d1d8e86c1 --- /dev/null +++ b/tests/ui/into_iter_without_iter.stderr @@ -0,0 +1,114 @@ +error: `IntoIterator` implemented for a reference type without an `iter` method + --> $DIR/into_iter_without_iter.rs:10:9 + | +LL | / impl<'a> IntoIterator for &'a S { +LL | | +LL | | type IntoIter = std::slice::Iter<'a, u8>; +LL | | type Item = &'a u8; +... | +LL | | } +LL | | } + | |_________^ + | + = note: `-D clippy::into-iter-without-iter` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::into_iter_without_iter)]` +help: consider implementing `iter` + | +LL ~ +LL + impl S { +LL + fn iter(&self) -> std::slice::Iter<'a, u8> { +LL + <&Self as IntoIterator>::into_iter(self) +LL + } +LL + } + | + +error: `IntoIterator` implemented for a reference type without an `iter_mut` method + --> $DIR/into_iter_without_iter.rs:18:9 + | +LL | / impl<'a> IntoIterator for &'a mut S { +LL | | +LL | | type IntoIter = std::slice::IterMut<'a, u8>; +LL | | type Item = &'a mut u8; +... | +LL | | } +LL | | } + | |_________^ + | +help: consider implementing `iter_mut` + | +LL ~ +LL + impl S { +LL + fn iter_mut(&mut self) -> std::slice::IterMut<'a, u8> { +LL + <&mut Self as IntoIterator>::into_iter(self) +LL + } +LL + } + | + +error: `IntoIterator` implemented for a reference type without an `iter` method + --> $DIR/into_iter_without_iter.rs:29:9 + | +LL | / impl<'a, T> IntoIterator for &'a S { +LL | | +LL | | type IntoIter = std::slice::Iter<'a, T>; +LL | | type Item = &'a T; +... | +LL | | } +LL | | } + | |_________^ + | +help: consider implementing `iter` + | +LL ~ +LL + impl S { +LL + fn iter(&self) -> std::slice::Iter<'a, T> { +LL + <&Self as IntoIterator>::into_iter(self) +LL + } +LL + } + | + +error: `IntoIterator` implemented for a reference type without an `iter_mut` method + --> $DIR/into_iter_without_iter.rs:37:9 + | +LL | / impl<'a, T> IntoIterator for &'a mut S { +LL | | +LL | | type IntoIter = std::slice::IterMut<'a, T>; +LL | | type Item = &'a mut T; +... | +LL | | } +LL | | } + | |_________^ + | +help: consider implementing `iter_mut` + | +LL ~ +LL + impl S { +LL + fn iter_mut(&mut self) -> std::slice::IterMut<'a, T> { +LL + <&mut Self as IntoIterator>::into_iter(self) +LL + } +LL + } + | + +error: `IntoIterator` implemented for a reference type without an `iter_mut` method + --> $DIR/into_iter_without_iter.rs:93:9 + | +LL | / impl<'a, T> IntoIterator for &mut S<'a, T> { +LL | | +LL | | type IntoIter = std::slice::IterMut<'a, T>; +LL | | type Item = &'a mut T; +... | +LL | | } +LL | | } + | |_________^ + | +help: consider implementing `iter_mut` + | +LL ~ +LL + impl S<'a, T> { +LL + fn iter_mut(&mut self) -> std::slice::IterMut<'a, T> { +LL + <&mut Self as IntoIterator>::into_iter(self) +LL + } +LL + } + | + +error: aborting due to 5 previous errors + diff --git a/tests/ui/items_after_test_module/after_proc_macros.rs b/tests/ui/items_after_test_module/after_proc_macros.rs new file mode 100644 index 0000000000000..d9c0aef88c8cf --- /dev/null +++ b/tests/ui/items_after_test_module/after_proc_macros.rs @@ -0,0 +1,11 @@ +//@aux-build:../auxiliary/proc_macros.rs +extern crate proc_macros; + +proc_macros::with_span! { + span + #[cfg(test)] + mod tests {} +} + +#[test] +fn f() {} diff --git a/tests/ui/items_after_test_module/auxiliary/submodule.rs b/tests/ui/items_after_test_module/auxiliary/submodule.rs new file mode 100644 index 0000000000000..69d61790121c0 --- /dev/null +++ b/tests/ui/items_after_test_module/auxiliary/submodule.rs @@ -0,0 +1,4 @@ +#[cfg(test)] +mod tests {} + +fn in_submodule() {} diff --git a/tests/ui/items_after_test_module/block_module.stderr b/tests/ui/items_after_test_module/block_module.stderr deleted file mode 100644 index 1b6257471618c..0000000000000 --- a/tests/ui/items_after_test_module/block_module.stderr +++ /dev/null @@ -1,2 +0,0 @@ -error: Option 'test' given more than once - diff --git a/tests/ui/items_after_test_module/in_submodule.rs b/tests/ui/items_after_test_module/in_submodule.rs new file mode 100644 index 0000000000000..7132e71764eb0 --- /dev/null +++ b/tests/ui/items_after_test_module/in_submodule.rs @@ -0,0 +1,8 @@ +#[path = "auxiliary/submodule.rs"] +mod submodule; + +#[cfg(test)] +mod tests { + #[test] + fn t() {} +} diff --git a/tests/ui/items_after_test_module/in_submodule.stderr b/tests/ui/items_after_test_module/in_submodule.stderr new file mode 100644 index 0000000000000..4e99876365cf8 --- /dev/null +++ b/tests/ui/items_after_test_module/in_submodule.stderr @@ -0,0 +1,14 @@ +error: items after a test module + --> $DIR/auxiliary/submodule.rs:2:1 + | +LL | mod tests {} + | ^^^^^^^^^ +LL | +LL | fn in_submodule() {} + | ^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::items-after-test-module` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::items_after_test_module)]` + +error: aborting due to previous error + diff --git a/tests/ui/items_after_test_module/multiple_modules.rs b/tests/ui/items_after_test_module/multiple_modules.rs new file mode 100644 index 0000000000000..8ab9e8200f18a --- /dev/null +++ b/tests/ui/items_after_test_module/multiple_modules.rs @@ -0,0 +1,11 @@ +#[cfg(test)] +mod tests { + #[test] + fn f() {} +} + +#[cfg(test)] +mod more_tests { + #[test] + fn g() {} +} diff --git a/tests/ui/items_after_test_module/block_module.rs b/tests/ui/items_after_test_module/root_module.fixed similarity index 86% rename from tests/ui/items_after_test_module/block_module.rs rename to tests/ui/items_after_test_module/root_module.fixed index 5136b2557ec1a..d444100a76b92 100644 --- a/tests/ui/items_after_test_module/block_module.rs +++ b/tests/ui/items_after_test_module/root_module.fixed @@ -1,4 +1,3 @@ -//@compile-flags: --test #![allow(unused)] #![warn(clippy::items_after_test_module)] @@ -6,6 +5,13 @@ fn main() {} fn should_not_lint() {} +fn should_lint() {} + +const SHOULD_ALSO_LINT: usize = 1; +macro_rules! should_lint { + () => {}; +} + #[allow(dead_code)] #[allow(unused)] // Some attributes to check that span replacement is good enough #[allow(clippy::allow_attributes)] @@ -14,10 +20,3 @@ mod tests { #[test] fn hi() {} } - -fn should_lint() {} - -const SHOULD_ALSO_LINT: usize = 1; -macro_rules! should_not_lint { - () => {}; -} diff --git a/tests/ui/items_after_test_module/root_module.rs b/tests/ui/items_after_test_module/root_module.rs new file mode 100644 index 0000000000000..57da01639cca6 --- /dev/null +++ b/tests/ui/items_after_test_module/root_module.rs @@ -0,0 +1,22 @@ +#![allow(unused)] +#![warn(clippy::items_after_test_module)] + +fn main() {} + +fn should_not_lint() {} + +#[allow(dead_code)] +#[allow(unused)] // Some attributes to check that span replacement is good enough +#[allow(clippy::allow_attributes)] +#[cfg(test)] +mod tests { + #[test] + fn hi() {} +} + +fn should_lint() {} + +const SHOULD_ALSO_LINT: usize = 1; +macro_rules! should_lint { + () => {}; +} diff --git a/tests/ui/items_after_test_module/root_module.stderr b/tests/ui/items_after_test_module/root_module.stderr new file mode 100644 index 0000000000000..67bc82ebff91f --- /dev/null +++ b/tests/ui/items_after_test_module/root_module.stderr @@ -0,0 +1,20 @@ +error: items after a test module + --> $DIR/root_module.rs:12:1 + | +LL | mod tests { + | ^^^^^^^^^ +... +LL | fn should_lint() {} + | ^^^^^^^^^^^^^^^^ +LL | +LL | const SHOULD_ALSO_LINT: usize = 1; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | macro_rules! should_lint { + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::items-after-test-module` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::items_after_test_module)]` + = help: move the items to before the test module was defined + +error: aborting due to previous error + diff --git a/tests/ui/iter_without_into_iter.rs b/tests/ui/iter_without_into_iter.rs new file mode 100644 index 0000000000000..cedb756c79de1 --- /dev/null +++ b/tests/ui/iter_without_into_iter.rs @@ -0,0 +1,120 @@ +//@no-rustfix +#![warn(clippy::iter_without_into_iter)] + +fn main() { + { + struct S; + impl S { + pub fn iter(&self) -> std::slice::Iter<'_, u8> { + //~^ ERROR: `iter` method without an `IntoIterator` impl + [].iter() + } + pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, u8> { + //~^ ERROR: `iter_mut` method without an `IntoIterator` impl + [].iter_mut() + } + } + } + { + struct S; + impl S { + pub fn iter(&self) -> impl Iterator { + // RPITIT is not stable, so we can't generally suggest it here yet + [].iter() + } + } + } + { + struct S<'a>(&'a mut [u8]); + impl<'a> S<'a> { + pub fn iter(&self) -> std::slice::Iter<'_, u8> { + //~^ ERROR: `iter` method without an `IntoIterator` impl + self.0.iter() + } + pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, u8> { + //~^ ERROR: `iter_mut` method without an `IntoIterator` impl + self.0.iter_mut() + } + } + } + { + // Incompatible signatures + struct S; + impl S { + pub fn iter(self) -> std::slice::Iter<'static, u8> { + todo!() + } + } + struct S2; + impl S2 { + pub async fn iter(&self) -> std::slice::Iter<'static, u8> { + todo!() + } + } + struct S3; + impl S3 { + pub fn iter(&self, _additional_param: ()) -> std::slice::Iter<'static, u8> { + todo!() + } + } + struct S4(T); + impl S4 { + pub fn iter(&self) -> std::slice::Iter<'static, (T, U)> { + todo!() + } + } + struct S5(T); + impl S5 { + pub fn iter(&self) -> std::slice::Iter<'static, T> { + todo!() + } + } + } + { + struct S(T); + impl S { + pub fn iter(&self) -> std::slice::Iter<'_, T> { + //~^ ERROR: `iter` method without an `IntoIterator` impl + todo!() + } + pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, T> { + //~^ ERROR: `iter_mut` method without an `IntoIterator` impl + todo!() + } + } + } + { + struct S(T); + impl S { + pub fn iter(&self) -> std::slice::Iter<'_, T> { + // Don't lint, there's an existing (wrong) IntoIterator impl + todo!() + } + } + + impl<'a, T> IntoIterator for &'a S { + type Item = &'a String; + type IntoIter = std::slice::Iter<'a, String>; + fn into_iter(self) -> Self::IntoIter { + todo!() + } + } + } + { + struct S(T); + impl S { + pub fn iter_mut(&self) -> std::slice::IterMut<'_, T> { + // Don't lint, there's an existing (wrong) IntoIterator impl + todo!() + } + } + + impl<'a, T> IntoIterator for &'a mut S { + type Item = &'a mut String; + type IntoIter = std::slice::IterMut<'a, String>; + fn into_iter(self) -> Self::IntoIter { + todo!() + } + } + } +} diff --git a/tests/ui/iter_without_into_iter.stderr b/tests/ui/iter_without_into_iter.stderr new file mode 100644 index 0000000000000..9d0b99415a50e --- /dev/null +++ b/tests/ui/iter_without_into_iter.stderr @@ -0,0 +1,150 @@ +error: `iter` method without an `IntoIterator` impl for `&S` + --> $DIR/iter_without_into_iter.rs:8:13 + | +LL | / pub fn iter(&self) -> std::slice::Iter<'_, u8> { +LL | | +LL | | [].iter() +LL | | } + | |_____________^ + | + = note: `-D clippy::iter-without-into-iter` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::iter_without_into_iter)]` +help: consider implementing `IntoIterator` for `&S` + | +LL ~ +LL + impl IntoIterator for &S { +LL + type IntoIter = std::slice::Iter<'_, u8>; +LL + type Iter = &u8; +LL + fn into_iter() -> Self::IntoIter { +LL + self.iter() +LL + } +LL + } + | + +error: `iter_mut` method without an `IntoIterator` impl for `&mut S` + --> $DIR/iter_without_into_iter.rs:12:13 + | +LL | / pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, u8> { +LL | | +LL | | [].iter_mut() +LL | | } + | |_____________^ + | +help: consider implementing `IntoIterator` for `&mut S` + | +LL ~ +LL + impl IntoIterator for &mut S { +LL + type IntoIter = std::slice::IterMut<'_, u8>; +LL + type Iter = &mut u8; +LL + fn into_iter() -> Self::IntoIter { +LL + self.iter() +LL + } +LL + } + | + +error: `iter` method without an `IntoIterator` impl for `&S<'a>` + --> $DIR/iter_without_into_iter.rs:30:13 + | +LL | / pub fn iter(&self) -> std::slice::Iter<'_, u8> { +LL | | +LL | | self.0.iter() +LL | | } + | |_____________^ + | +help: consider implementing `IntoIterator` for `&S<'a>` + | +LL ~ +LL + impl IntoIterator for &S<'a> { +LL + type IntoIter = std::slice::Iter<'_, u8>; +LL + type Iter = &u8; +LL + fn into_iter() -> Self::IntoIter { +LL + self.iter() +LL + } +LL + } + | + +error: `iter_mut` method without an `IntoIterator` impl for `&mut S<'a>` + --> $DIR/iter_without_into_iter.rs:34:13 + | +LL | / pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, u8> { +LL | | +LL | | self.0.iter_mut() +LL | | } + | |_____________^ + | +help: consider implementing `IntoIterator` for `&mut S<'a>` + | +LL ~ +LL + impl IntoIterator for &mut S<'a> { +LL + type IntoIter = std::slice::IterMut<'_, u8>; +LL + type Iter = &mut u8; +LL + fn into_iter() -> Self::IntoIter { +LL + self.iter() +LL + } +LL + } + | + +error: `iter` method without an `IntoIterator` impl for `&S5` + --> $DIR/iter_without_into_iter.rs:68:13 + | +LL | / pub fn iter(&self) -> std::slice::Iter<'static, T> { +LL | | todo!() +LL | | } + | |_____________^ + | +help: consider implementing `IntoIterator` for `&S5` + | +LL ~ +LL + impl IntoIterator for &S5 { +LL + type IntoIter = std::slice::Iter<'static, T>; +LL + type Iter = &T; +LL + fn into_iter() -> Self::IntoIter { +LL + self.iter() +LL + } +LL + } + | + +error: `iter` method without an `IntoIterator` impl for `&S` + --> $DIR/iter_without_into_iter.rs:76:13 + | +LL | / pub fn iter(&self) -> std::slice::Iter<'_, T> { +LL | | +LL | | todo!() +LL | | } + | |_____________^ + | +help: consider implementing `IntoIterator` for `&S` + | +LL ~ +LL + impl IntoIterator for &S { +LL + type IntoIter = std::slice::Iter<'_, T>; +LL + type Iter = &T; +LL + fn into_iter() -> Self::IntoIter { +LL + self.iter() +LL + } +LL + } + | + +error: `iter_mut` method without an `IntoIterator` impl for `&mut S` + --> $DIR/iter_without_into_iter.rs:80:13 + | +LL | / pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, T> { +LL | | +LL | | todo!() +LL | | } + | |_____________^ + | +help: consider implementing `IntoIterator` for `&mut S` + | +LL ~ +LL + impl IntoIterator for &mut S { +LL + type IntoIter = std::slice::IterMut<'_, T>; +LL + type Iter = &mut T; +LL + fn into_iter() -> Self::IntoIter { +LL + self.iter() +LL + } +LL + } + | + +error: aborting due to 7 previous errors + diff --git a/tests/ui/let_underscore_future.rs b/tests/ui/let_underscore_future.rs index 873ae667ab71a..c2185e9785d84 100644 --- a/tests/ui/let_underscore_future.rs +++ b/tests/ui/let_underscore_future.rs @@ -9,8 +9,6 @@ fn custom() -> impl Future { } fn do_something_to_future(future: &mut impl Future) {} -//~^ ERROR: this argument is a mutable reference, but not used mutably -//~| NOTE: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings` fn main() { let _ = some_async_fn(); diff --git a/tests/ui/let_underscore_future.stderr b/tests/ui/let_underscore_future.stderr index 3ba99c6377b73..ef927a8083bcc 100644 --- a/tests/ui/let_underscore_future.stderr +++ b/tests/ui/let_underscore_future.stderr @@ -1,5 +1,5 @@ error: non-binding `let` on a future - --> $DIR/let_underscore_future.rs:16:5 + --> $DIR/let_underscore_future.rs:14:5 | LL | let _ = some_async_fn(); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -9,7 +9,7 @@ LL | let _ = some_async_fn(); = help: to override `-D warnings` add `#[allow(clippy::let_underscore_future)]` error: non-binding `let` on a future - --> $DIR/let_underscore_future.rs:18:5 + --> $DIR/let_underscore_future.rs:16:5 | LL | let _ = custom(); | ^^^^^^^^^^^^^^^^^ @@ -17,21 +17,12 @@ LL | let _ = custom(); = help: consider awaiting the future or dropping explicitly with `std::mem::drop` error: non-binding `let` on a future - --> $DIR/let_underscore_future.rs:23:5 + --> $DIR/let_underscore_future.rs:21:5 | LL | let _ = future; | ^^^^^^^^^^^^^^^ | = help: consider awaiting the future or dropping explicitly with `std::mem::drop` -error: this argument is a mutable reference, but not used mutably - --> $DIR/let_underscore_future.rs:11:35 - | -LL | fn do_something_to_future(future: &mut impl Future) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&impl Future` - | - = note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::needless_pass_by_ref_mut)]` - -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors diff --git a/tests/ui/manual_hash_one.fixed b/tests/ui/manual_hash_one.fixed new file mode 100644 index 0000000000000..edfd9c4a47bba --- /dev/null +++ b/tests/ui/manual_hash_one.fixed @@ -0,0 +1,89 @@ +#![warn(clippy::manual_hash_one)] +#![allow(clippy::needless_borrows_for_generic_args)] + +use std::hash::{BuildHasher, Hash, Hasher}; + +fn returned(b: impl BuildHasher) -> u64 { + + + b.hash_one(&true) +} + +fn unsized_receiver(b: impl BuildHasher, s: &str) { + + + let _ = b.hash_one(&s[4..10]); +} + +fn owned_value(b: impl BuildHasher, v: Vec) -> Vec { + + + let _ = b.hash_one(&v); + v +} + +fn reused_hasher(b: impl BuildHasher) { + let mut hasher = b.build_hasher(); + true.hash(&mut hasher); + let _ = hasher.finish(); + let _ = hasher.finish(); +} + +fn reused_hasher_in_return(b: impl BuildHasher) -> u64 { + let mut hasher = b.build_hasher(); + true.hash(&mut hasher); + let _ = hasher.finish(); + hasher.finish() +} + +fn no_hash(b: impl BuildHasher) { + let mut hasher = b.build_hasher(); + let _ = hasher.finish(); +} + +fn hash_twice(b: impl BuildHasher) { + let mut hasher = b.build_hasher(); + true.hash(&mut hasher); + true.hash(&mut hasher); + let _ = hasher.finish(); +} + +fn other_hasher(b: impl BuildHasher) { + let mut other_hasher = b.build_hasher(); + + let mut hasher = b.build_hasher(); + true.hash(&mut other_hasher); + let _ = hasher.finish(); +} + +fn finish_then_hash(b: impl BuildHasher) { + let mut hasher = b.build_hasher(); + let _ = hasher.finish(); + true.hash(&mut hasher); +} + +fn in_macro(b: impl BuildHasher) { + macro_rules! m { + ($b:expr) => {{ + let mut hasher = $b.build_hasher(); + true.hash(&mut hasher); + let _ = hasher.finish(); + }}; + } + + m!(b); +} + +#[clippy::msrv = "1.70"] +fn msrv_1_70(b: impl BuildHasher, v: impl Hash) { + let mut hasher = b.build_hasher(); + v.hash(&mut hasher); + let _ = hasher.finish(); +} + +#[clippy::msrv = "1.71"] +fn msrv_1_71(b: impl BuildHasher, v: impl Hash) { + + + let _ = b.hash_one(&v); +} diff --git a/tests/ui/manual_hash_one.rs b/tests/ui/manual_hash_one.rs new file mode 100644 index 0000000000000..ee61522853f0f --- /dev/null +++ b/tests/ui/manual_hash_one.rs @@ -0,0 +1,89 @@ +#![warn(clippy::manual_hash_one)] +#![allow(clippy::needless_borrows_for_generic_args)] + +use std::hash::{BuildHasher, Hash, Hasher}; + +fn returned(b: impl BuildHasher) -> u64 { + let mut hasher = b.build_hasher(); + true.hash(&mut hasher); + hasher.finish() +} + +fn unsized_receiver(b: impl BuildHasher, s: &str) { + let mut hasher = b.build_hasher(); + s[4..10].hash(&mut hasher); + let _ = hasher.finish(); +} + +fn owned_value(b: impl BuildHasher, v: Vec) -> Vec { + let mut hasher = b.build_hasher(); + v.hash(&mut hasher); + let _ = hasher.finish(); + v +} + +fn reused_hasher(b: impl BuildHasher) { + let mut hasher = b.build_hasher(); + true.hash(&mut hasher); + let _ = hasher.finish(); + let _ = hasher.finish(); +} + +fn reused_hasher_in_return(b: impl BuildHasher) -> u64 { + let mut hasher = b.build_hasher(); + true.hash(&mut hasher); + let _ = hasher.finish(); + hasher.finish() +} + +fn no_hash(b: impl BuildHasher) { + let mut hasher = b.build_hasher(); + let _ = hasher.finish(); +} + +fn hash_twice(b: impl BuildHasher) { + let mut hasher = b.build_hasher(); + true.hash(&mut hasher); + true.hash(&mut hasher); + let _ = hasher.finish(); +} + +fn other_hasher(b: impl BuildHasher) { + let mut other_hasher = b.build_hasher(); + + let mut hasher = b.build_hasher(); + true.hash(&mut other_hasher); + let _ = hasher.finish(); +} + +fn finish_then_hash(b: impl BuildHasher) { + let mut hasher = b.build_hasher(); + let _ = hasher.finish(); + true.hash(&mut hasher); +} + +fn in_macro(b: impl BuildHasher) { + macro_rules! m { + ($b:expr) => {{ + let mut hasher = $b.build_hasher(); + true.hash(&mut hasher); + let _ = hasher.finish(); + }}; + } + + m!(b); +} + +#[clippy::msrv = "1.70"] +fn msrv_1_70(b: impl BuildHasher, v: impl Hash) { + let mut hasher = b.build_hasher(); + v.hash(&mut hasher); + let _ = hasher.finish(); +} + +#[clippy::msrv = "1.71"] +fn msrv_1_71(b: impl BuildHasher, v: impl Hash) { + let mut hasher = b.build_hasher(); + v.hash(&mut hasher); + let _ = hasher.finish(); +} diff --git a/tests/ui/manual_hash_one.stderr b/tests/ui/manual_hash_one.stderr new file mode 100644 index 0000000000000..3ce6f41e1f910 --- /dev/null +++ b/tests/ui/manual_hash_one.stderr @@ -0,0 +1,56 @@ +error: manual implementation of `BuildHasher::hash_one` + --> $DIR/manual_hash_one.rs:9:5 + | +LL | hasher.finish() + | ^^^^^^^^^^^^^^^ + | + = note: `-D clippy::manual-hash-one` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::manual_hash_one)]` +help: try + | +LL ~ +LL ~ +LL ~ b.hash_one(&true) + | + +error: manual implementation of `BuildHasher::hash_one` + --> $DIR/manual_hash_one.rs:15:13 + | +LL | let _ = hasher.finish(); + | ^^^^^^^^^^^^^^^ + | +help: try + | +LL ~ +LL ~ +LL ~ let _ = b.hash_one(&s[4..10]); + | + +error: manual implementation of `BuildHasher::hash_one` + --> $DIR/manual_hash_one.rs:21:13 + | +LL | let _ = hasher.finish(); + | ^^^^^^^^^^^^^^^ + | +help: try + | +LL ~ +LL ~ +LL ~ let _ = b.hash_one(&v); + | + +error: manual implementation of `BuildHasher::hash_one` + --> $DIR/manual_hash_one.rs:88:13 + | +LL | let _ = hasher.finish(); + | ^^^^^^^^^^^^^^^ + | +help: try + | +LL ~ +LL ~ +LL ~ let _ = b.hash_one(&v); + | + +error: aborting due to 4 previous errors + diff --git a/tests/ui/manual_let_else_match.fixed b/tests/ui/manual_let_else_match.fixed index 09b713f04101e..588ba5edd8f15 100644 --- a/tests/ui/manual_let_else_match.fixed +++ b/tests/ui/manual_let_else_match.fixed @@ -133,3 +133,7 @@ fn not_fire() { [data @ .., 0, 0, 0, 0] | [data @ .., 0, 0] | [data @ ..] => data, }; } + +fn issue11579() { + let Some(msg) = Some("hi") else { unreachable!("can't happen") }; +} diff --git a/tests/ui/manual_let_else_match.rs b/tests/ui/manual_let_else_match.rs index e6af47384200e..c37b5613ff7d5 100644 --- a/tests/ui/manual_let_else_match.rs +++ b/tests/ui/manual_let_else_match.rs @@ -170,3 +170,11 @@ fn not_fire() { [data @ .., 0, 0, 0, 0] | [data @ .., 0, 0] | [data @ ..] => data, }; } + +fn issue11579() { + let msg = match Some("hi") { + //~^ ERROR: this could be rewritten as `let...else` + Some(m) => m, + _ => unreachable!("can't happen"), + }; +} diff --git a/tests/ui/manual_let_else_match.stderr b/tests/ui/manual_let_else_match.stderr index 8ca2c84072d0f..18bfe324ba76a 100644 --- a/tests/ui/manual_let_else_match.stderr +++ b/tests/ui/manual_let_else_match.stderr @@ -92,5 +92,15 @@ LL | | _ => return, LL | | }; | |______^ help: consider writing: `let ([data @ .., 0, 0, 0, 0] | [data @ .., 0, 0] | [data @ .., 0]) = data.as_slice() else { return };` -error: aborting due to 9 previous errors +error: this could be rewritten as `let...else` + --> $DIR/manual_let_else_match.rs:175:5 + | +LL | / let msg = match Some("hi") { +LL | | +LL | | Some(m) => m, +LL | | _ => unreachable!("can't happen"), +LL | | }; + | |______^ help: consider writing: `let Some(msg) = Some("hi") else { unreachable!("can't happen") };` + +error: aborting due to 10 previous errors diff --git a/tests/ui/manual_non_exhaustive_enum.rs b/tests/ui/manual_non_exhaustive_enum.rs index 0e439dabfd651..e32ba8631761b 100644 --- a/tests/ui/manual_non_exhaustive_enum.rs +++ b/tests/ui/manual_non_exhaustive_enum.rs @@ -10,10 +10,9 @@ enum E { _C, } -// user forgot to remove the marker +// if the user explicitly marks as nonexhaustive we shouldn't warn them #[non_exhaustive] enum Ep { - //~^ ERROR: this seems like a manual implementation of the non-exhaustive pattern A, B, #[doc(hidden)] diff --git a/tests/ui/manual_non_exhaustive_enum.stderr b/tests/ui/manual_non_exhaustive_enum.stderr index ce7e21c94bbdc..7361a4a2cbbe8 100644 --- a/tests/ui/manual_non_exhaustive_enum.stderr +++ b/tests/ui/manual_non_exhaustive_enum.stderr @@ -22,23 +22,5 @@ LL | _C, = note: `-D clippy::manual-non-exhaustive` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::manual_non_exhaustive)]` -error: this seems like a manual implementation of the non-exhaustive pattern - --> $DIR/manual_non_exhaustive_enum.rs:15:1 - | -LL | / enum Ep { -LL | | -LL | | A, -LL | | B, -LL | | #[doc(hidden)] -LL | | _C, -LL | | } - | |_^ - | -help: remove this variant - --> $DIR/manual_non_exhaustive_enum.rs:20:5 - | -LL | _C, - | ^^ - -error: aborting due to 2 previous errors +error: aborting due to previous error diff --git a/tests/ui/mut_key.rs b/tests/ui/mut_key.rs index 8069213217683..2d70bfd4c770c 100644 --- a/tests/ui/mut_key.rs +++ b/tests/ui/mut_key.rs @@ -32,8 +32,6 @@ fn should_not_take_this_arg(m: &mut HashMap, _n: usize) -> HashSet = HashMap::new(); //~^ ERROR: mutable key type m.keys().cloned().collect() diff --git a/tests/ui/mut_key.stderr b/tests/ui/mut_key.stderr index 3701769a9ca7f..48eeaff78a789 100644 --- a/tests/ui/mut_key.stderr +++ b/tests/ui/mut_key.stderr @@ -14,103 +14,94 @@ LL | fn should_not_take_this_arg(m: &mut HashMap, _n: usize) -> Hash | ^^^^^^^^^^^^ error: mutable key type - --> $DIR/mut_key.rs:37:5 + --> $DIR/mut_key.rs:35:5 | LL | let _other: HashMap = HashMap::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: mutable key type - --> $DIR/mut_key.rs:65:22 + --> $DIR/mut_key.rs:63:22 | LL | fn tuples_bad(_m: &mut HashMap<(Key, U), bool>) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: mutable key type - --> $DIR/mut_key.rs:78:5 + --> $DIR/mut_key.rs:76:5 | LL | let _map = HashMap::, usize>::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: mutable key type - --> $DIR/mut_key.rs:80:5 + --> $DIR/mut_key.rs:78:5 | LL | let _map = HashMap::<&mut Cell, usize>::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: mutable key type - --> $DIR/mut_key.rs:82:5 + --> $DIR/mut_key.rs:80:5 | LL | let _map = HashMap::<&mut usize, usize>::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: mutable key type - --> $DIR/mut_key.rs:85:5 + --> $DIR/mut_key.rs:83:5 | LL | let _map = HashMap::>, usize>::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: mutable key type - --> $DIR/mut_key.rs:87:5 + --> $DIR/mut_key.rs:85:5 | LL | let _map = HashMap::, ()>, usize>::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: mutable key type - --> $DIR/mut_key.rs:89:5 + --> $DIR/mut_key.rs:87:5 | LL | let _map = HashMap::>, usize>::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: mutable key type - --> $DIR/mut_key.rs:91:5 + --> $DIR/mut_key.rs:89:5 | LL | let _map = HashMap::>, usize>::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: mutable key type - --> $DIR/mut_key.rs:93:5 + --> $DIR/mut_key.rs:91:5 | LL | let _map = HashMap::>, usize>::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: mutable key type - --> $DIR/mut_key.rs:95:5 + --> $DIR/mut_key.rs:93:5 | LL | let _map = HashMap::>>, usize>::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: mutable key type - --> $DIR/mut_key.rs:97:5 + --> $DIR/mut_key.rs:95:5 | LL | let _map = HashMap::, usize>::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: mutable key type - --> $DIR/mut_key.rs:100:5 + --> $DIR/mut_key.rs:98:5 | LL | let _map = HashMap::>, usize>::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: mutable key type - --> $DIR/mut_key.rs:102:5 + --> $DIR/mut_key.rs:100:5 | LL | let _map = HashMap::>, usize>::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: mutable key type - --> $DIR/mut_key.rs:104:5 + --> $DIR/mut_key.rs:102:5 | LL | let _map = HashMap::>, usize>::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: this argument is a mutable reference, but not used mutably - --> $DIR/mut_key.rs:31:32 - | -LL | fn should_not_take_this_arg(m: &mut HashMap, _n: usize) -> HashSet { - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&HashMap` - | - = note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::needless_pass_by_ref_mut)]` - -error: aborting due to 18 previous errors +error: aborting due to 17 previous errors diff --git a/tests/ui/mut_reference.rs b/tests/ui/mut_reference.rs index f3db226e4e7fc..1d7faaa5e75e4 100644 --- a/tests/ui/mut_reference.rs +++ b/tests/ui/mut_reference.rs @@ -22,8 +22,6 @@ impl MyStruct { fn takes_an_immutable_reference(&self, a: &i32) {} fn takes_a_mutable_reference(&self, a: &mut i32) {} - //~^ ERROR: this argument is a mutable reference, but not used mutably - //~| NOTE: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings` } #[warn(clippy::unnecessary_mut_passed)] diff --git a/tests/ui/mut_reference.stderr b/tests/ui/mut_reference.stderr index d7a0d0c225250..87db08e2a7420 100644 --- a/tests/ui/mut_reference.stderr +++ b/tests/ui/mut_reference.stderr @@ -1,5 +1,5 @@ error: the function `takes_an_immutable_reference` doesn't need a mutable reference - --> $DIR/mut_reference.rs:32:34 + --> $DIR/mut_reference.rs:30:34 | LL | takes_an_immutable_reference(&mut 42); | ^^^^^^^ @@ -8,25 +8,16 @@ LL | takes_an_immutable_reference(&mut 42); = help: to override `-D warnings` add `#[allow(clippy::unnecessary_mut_passed)]` error: the function `as_ptr` doesn't need a mutable reference - --> $DIR/mut_reference.rs:36:12 + --> $DIR/mut_reference.rs:34:12 | LL | as_ptr(&mut 42); | ^^^^^^^ error: the method `takes_an_immutable_reference` doesn't need a mutable reference - --> $DIR/mut_reference.rs:41:44 + --> $DIR/mut_reference.rs:39:44 | LL | my_struct.takes_an_immutable_reference(&mut 42); | ^^^^^^^ -error: this argument is a mutable reference, but not used mutably - --> $DIR/mut_reference.rs:24:44 - | -LL | fn takes_a_mutable_reference(&self, a: &mut i32) {} - | ^^^^^^^^ help: consider changing to: `&i32` - | - = note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::needless_pass_by_ref_mut)]` - -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors diff --git a/tests/ui/needless_pass_by_ref_mut.rs b/tests/ui/needless_pass_by_ref_mut.rs index 9cddcb3df2378..39d76f9990022 100644 --- a/tests/ui/needless_pass_by_ref_mut.rs +++ b/tests/ui/needless_pass_by_ref_mut.rs @@ -1,4 +1,5 @@ #![allow(clippy::if_same_then_else, clippy::no_effect, clippy::redundant_closure_call)] +#![warn(clippy::needless_pass_by_ref_mut)] #![feature(lint_reasons)] //@no-rustfix use std::ptr::NonNull; diff --git a/tests/ui/needless_pass_by_ref_mut.stderr b/tests/ui/needless_pass_by_ref_mut.stderr index 0c7fbd5df6d9d..aa937c3f6af2b 100644 --- a/tests/ui/needless_pass_by_ref_mut.stderr +++ b/tests/ui/needless_pass_by_ref_mut.stderr @@ -1,5 +1,5 @@ error: this argument is a mutable reference, but not used mutably - --> $DIR/needless_pass_by_ref_mut.rs:6:11 + --> $DIR/needless_pass_by_ref_mut.rs:7:11 | LL | fn foo(s: &mut Vec, b: &u32, x: &mut u32) { | ^^^^^^^^^^^^^ help: consider changing to: `&Vec` @@ -8,79 +8,79 @@ LL | fn foo(s: &mut Vec, b: &u32, x: &mut u32) { = help: to override `-D warnings` add `#[allow(clippy::needless_pass_by_ref_mut)]` error: this argument is a mutable reference, but not used mutably - --> $DIR/needless_pass_by_ref_mut.rs:31:12 + --> $DIR/needless_pass_by_ref_mut.rs:32:12 | LL | fn foo6(s: &mut Vec) { | ^^^^^^^^^^^^^ help: consider changing to: `&Vec` error: this argument is a mutable reference, but not used mutably - --> $DIR/needless_pass_by_ref_mut.rs:44:29 + --> $DIR/needless_pass_by_ref_mut.rs:45:29 | LL | fn mushroom(&self, vec: &mut Vec) -> usize { | ^^^^^^^^^^^^^ help: consider changing to: `&Vec` error: this argument is a mutable reference, but not used mutably - --> $DIR/needless_pass_by_ref_mut.rs:49:31 + --> $DIR/needless_pass_by_ref_mut.rs:50:31 | LL | fn badger(&mut self, vec: &mut Vec) -> usize { | ^^^^^^^^^^^^^ help: consider changing to: `&Vec` error: this argument is a mutable reference, but not used mutably - --> $DIR/needless_pass_by_ref_mut.rs:126:16 + --> $DIR/needless_pass_by_ref_mut.rs:127:16 | LL | async fn a1(x: &mut i32) { | ^^^^^^^^ help: consider changing to: `&i32` error: this argument is a mutable reference, but not used mutably - --> $DIR/needless_pass_by_ref_mut.rs:130:16 + --> $DIR/needless_pass_by_ref_mut.rs:131:16 | LL | async fn a2(x: &mut i32, y: String) { | ^^^^^^^^ help: consider changing to: `&i32` error: this argument is a mutable reference, but not used mutably - --> $DIR/needless_pass_by_ref_mut.rs:134:16 + --> $DIR/needless_pass_by_ref_mut.rs:135:16 | LL | async fn a3(x: &mut i32, y: String, z: String) { | ^^^^^^^^ help: consider changing to: `&i32` error: this argument is a mutable reference, but not used mutably - --> $DIR/needless_pass_by_ref_mut.rs:138:16 + --> $DIR/needless_pass_by_ref_mut.rs:139:16 | LL | async fn a4(x: &mut i32, y: i32) { | ^^^^^^^^ help: consider changing to: `&i32` error: this argument is a mutable reference, but not used mutably - --> $DIR/needless_pass_by_ref_mut.rs:142:24 + --> $DIR/needless_pass_by_ref_mut.rs:143:24 | LL | async fn a5(x: i32, y: &mut i32) { | ^^^^^^^^ help: consider changing to: `&i32` error: this argument is a mutable reference, but not used mutably - --> $DIR/needless_pass_by_ref_mut.rs:146:24 + --> $DIR/needless_pass_by_ref_mut.rs:147:24 | LL | async fn a6(x: i32, y: &mut i32) { | ^^^^^^^^ help: consider changing to: `&i32` error: this argument is a mutable reference, but not used mutably - --> $DIR/needless_pass_by_ref_mut.rs:150:32 + --> $DIR/needless_pass_by_ref_mut.rs:151:32 | LL | async fn a7(x: i32, y: i32, z: &mut i32) { | ^^^^^^^^ help: consider changing to: `&i32` error: this argument is a mutable reference, but not used mutably - --> $DIR/needless_pass_by_ref_mut.rs:154:24 + --> $DIR/needless_pass_by_ref_mut.rs:155:24 | LL | async fn a8(x: i32, a: &mut i32, y: i32, z: &mut i32) { | ^^^^^^^^ help: consider changing to: `&i32` error: this argument is a mutable reference, but not used mutably - --> $DIR/needless_pass_by_ref_mut.rs:154:45 + --> $DIR/needless_pass_by_ref_mut.rs:155:45 | LL | async fn a8(x: i32, a: &mut i32, y: i32, z: &mut i32) { | ^^^^^^^^ help: consider changing to: `&i32` error: this argument is a mutable reference, but not used mutably - --> $DIR/needless_pass_by_ref_mut.rs:188:16 + --> $DIR/needless_pass_by_ref_mut.rs:189:16 | LL | fn cfg_warn(s: &mut u32) {} | ^^^^^^^^ help: consider changing to: `&u32` @@ -88,7 +88,7 @@ LL | fn cfg_warn(s: &mut u32) {} = note: this is cfg-gated and may require further changes error: this argument is a mutable reference, but not used mutably - --> $DIR/needless_pass_by_ref_mut.rs:194:20 + --> $DIR/needless_pass_by_ref_mut.rs:195:20 | LL | fn cfg_warn(s: &mut u32) {} | ^^^^^^^^ help: consider changing to: `&u32` @@ -96,19 +96,19 @@ LL | fn cfg_warn(s: &mut u32) {} = note: this is cfg-gated and may require further changes error: this argument is a mutable reference, but not used mutably - --> $DIR/needless_pass_by_ref_mut.rs:208:39 + --> $DIR/needless_pass_by_ref_mut.rs:209:39 | LL | async fn inner_async2(x: &mut i32, y: &mut u32) { | ^^^^^^^^ help: consider changing to: `&u32` error: this argument is a mutable reference, but not used mutably - --> $DIR/needless_pass_by_ref_mut.rs:216:26 + --> $DIR/needless_pass_by_ref_mut.rs:217:26 | LL | async fn inner_async3(x: &mut i32, y: &mut u32) { | ^^^^^^^^ help: consider changing to: `&i32` error: this argument is a mutable reference, but not used mutably - --> $DIR/needless_pass_by_ref_mut.rs:235:34 + --> $DIR/needless_pass_by_ref_mut.rs:236:34 | LL | pub async fn call_in_closure1(n: &mut str) { | ^^^^^^^^ help: consider changing to: `&str` @@ -116,7 +116,7 @@ LL | pub async fn call_in_closure1(n: &mut str) { = warning: changing this function will impact semver compatibility error: this argument is a mutable reference, but not used mutably - --> $DIR/needless_pass_by_ref_mut.rs:247:25 + --> $DIR/needless_pass_by_ref_mut.rs:248:25 | LL | pub async fn closure(n: &mut usize) -> impl '_ + FnMut() { | ^^^^^^^^^^ help: consider changing to: `&usize` @@ -124,7 +124,7 @@ LL | pub async fn closure(n: &mut usize) -> impl '_ + FnMut() { = warning: changing this function will impact semver compatibility error: this argument is a mutable reference, but not used mutably - --> $DIR/needless_pass_by_ref_mut.rs:254:20 + --> $DIR/needless_pass_by_ref_mut.rs:255:20 | LL | pub fn closure2(n: &mut usize) -> impl '_ + FnMut() -> usize { | ^^^^^^^^^^ help: consider changing to: `&usize` @@ -132,7 +132,7 @@ LL | pub fn closure2(n: &mut usize) -> impl '_ + FnMut() -> usize { = warning: changing this function will impact semver compatibility error: this argument is a mutable reference, but not used mutably - --> $DIR/needless_pass_by_ref_mut.rs:265:26 + --> $DIR/needless_pass_by_ref_mut.rs:266:26 | LL | pub async fn closure4(n: &mut usize) { | ^^^^^^^^^^ help: consider changing to: `&usize` diff --git a/tests/ui/needless_raw_string.fixed b/tests/ui/needless_raw_string.fixed index 855498105135e..4ea711fd67a14 100644 --- a/tests/ui/needless_raw_string.fixed +++ b/tests/ui/needless_raw_string.fixed @@ -18,4 +18,8 @@ fn main() { multiline string "; + + "no hashes"; + b"no hashes"; + c"no hashes"; } diff --git a/tests/ui/needless_raw_string.rs b/tests/ui/needless_raw_string.rs index 06d4973038717..b6239f9b1f031 100644 --- a/tests/ui/needless_raw_string.rs +++ b/tests/ui/needless_raw_string.rs @@ -18,4 +18,8 @@ fn main() { multiline string "#; + + r"no hashes"; + br"no hashes"; + cr"no hashes"; } diff --git a/tests/ui/needless_raw_string.stderr b/tests/ui/needless_raw_string.stderr index e6806b31b1d96..276bc84c6c375 100644 --- a/tests/ui/needless_raw_string.stderr +++ b/tests/ui/needless_raw_string.stderr @@ -6,7 +6,7 @@ LL | r#"aaa"#; | = note: `-D clippy::needless-raw-strings` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::needless_raw_strings)]` -help: try +help: use a plain string literal instead | LL - r#"aaa"#; LL + "aaa"; @@ -18,7 +18,7 @@ error: unnecessary raw string literal LL | br#"aaa"#; | ^^^^^^^^^ | -help: try +help: use a plain byte string literal instead | LL - br#"aaa"#; LL + b"aaa"; @@ -30,7 +30,7 @@ error: unnecessary raw string literal LL | cr#"aaa"#; | ^^^^^^^^^ | -help: try +help: use a plain C string literal instead | LL - cr#"aaa"#; LL + c"aaa"; @@ -46,7 +46,7 @@ LL | | string LL | | "#; | |______^ | -help: try +help: use a plain string literal instead | LL ~ " LL | a @@ -55,5 +55,41 @@ LL | string LL ~ "; | -error: aborting due to 4 previous errors +error: unnecessary raw string literal + --> $DIR/needless_raw_string.rs:22:5 + | +LL | r"no hashes"; + | ^^^^^^^^^^^^ + | +help: use a plain string literal instead + | +LL - r"no hashes"; +LL + "no hashes"; + | + +error: unnecessary raw string literal + --> $DIR/needless_raw_string.rs:23:5 + | +LL | br"no hashes"; + | ^^^^^^^^^^^^^ + | +help: use a plain byte string literal instead + | +LL - br"no hashes"; +LL + b"no hashes"; + | + +error: unnecessary raw string literal + --> $DIR/needless_raw_string.rs:24:5 + | +LL | cr"no hashes"; + | ^^^^^^^^^^^^^ + | +help: use a plain C string literal instead + | +LL - cr"no hashes"; +LL + c"no hashes"; + | + +error: aborting due to 7 previous errors diff --git a/tests/ui/needless_raw_string_hashes.stderr b/tests/ui/needless_raw_string_hashes.stderr index 4399c6555c2c0..017160b1a421d 100644 --- a/tests/ui/needless_raw_string_hashes.stderr +++ b/tests/ui/needless_raw_string_hashes.stderr @@ -6,7 +6,7 @@ LL | r#"\aaa"#; | = note: `-D clippy::needless-raw-string-hashes` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::needless_raw_string_hashes)]` -help: remove all the hashes around the literal +help: remove all the hashes around the string literal | LL - r#"\aaa"#; LL + r"\aaa"; @@ -18,7 +18,7 @@ error: unnecessary hashes around raw string literal LL | r##"Hello "world"!"##; | ^^^^^^^^^^^^^^^^^^^^^ | -help: remove one hash from both sides of the literal +help: remove one hash from both sides of the string literal | LL - r##"Hello "world"!"##; LL + r#"Hello "world"!"#; @@ -30,7 +30,7 @@ error: unnecessary hashes around raw string literal LL | r######" "### "## "# "######; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: remove 2 hashes from both sides of the literal +help: remove 2 hashes from both sides of the string literal | LL - r######" "### "## "# "######; LL + r####" "### "## "# "####; @@ -42,7 +42,7 @@ error: unnecessary hashes around raw string literal LL | r######" "aa" "# "## "######; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: remove 3 hashes from both sides of the literal +help: remove 3 hashes from both sides of the string literal | LL - r######" "aa" "# "## "######; LL + r###" "aa" "# "## "###; @@ -54,7 +54,7 @@ error: unnecessary hashes around raw string literal LL | br#"\aaa"#; | ^^^^^^^^^^ | -help: remove all the hashes around the literal +help: remove all the hashes around the byte string literal | LL - br#"\aaa"#; LL + br"\aaa"; @@ -66,7 +66,7 @@ error: unnecessary hashes around raw string literal LL | br##"Hello "world"!"##; | ^^^^^^^^^^^^^^^^^^^^^^ | -help: remove one hash from both sides of the literal +help: remove one hash from both sides of the byte string literal | LL - br##"Hello "world"!"##; LL + br#"Hello "world"!"#; @@ -78,7 +78,7 @@ error: unnecessary hashes around raw string literal LL | br######" "### "## "# "######; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: remove 2 hashes from both sides of the literal +help: remove 2 hashes from both sides of the byte string literal | LL - br######" "### "## "# "######; LL + br####" "### "## "# "####; @@ -90,7 +90,7 @@ error: unnecessary hashes around raw string literal LL | br######" "aa" "# "## "######; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: remove 3 hashes from both sides of the literal +help: remove 3 hashes from both sides of the byte string literal | LL - br######" "aa" "# "## "######; LL + br###" "aa" "# "## "###; @@ -102,7 +102,7 @@ error: unnecessary hashes around raw string literal LL | cr#"\aaa"#; | ^^^^^^^^^^ | -help: remove all the hashes around the literal +help: remove all the hashes around the C string literal | LL - cr#"\aaa"#; LL + cr"\aaa"; @@ -114,7 +114,7 @@ error: unnecessary hashes around raw string literal LL | cr##"Hello "world"!"##; | ^^^^^^^^^^^^^^^^^^^^^^ | -help: remove one hash from both sides of the literal +help: remove one hash from both sides of the C string literal | LL - cr##"Hello "world"!"##; LL + cr#"Hello "world"!"#; @@ -126,7 +126,7 @@ error: unnecessary hashes around raw string literal LL | cr######" "### "## "# "######; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: remove 2 hashes from both sides of the literal +help: remove 2 hashes from both sides of the C string literal | LL - cr######" "### "## "# "######; LL + cr####" "### "## "# "####; @@ -138,7 +138,7 @@ error: unnecessary hashes around raw string literal LL | cr######" "aa" "# "## "######; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: remove 3 hashes from both sides of the literal +help: remove 3 hashes from both sides of the C string literal | LL - cr######" "aa" "# "## "######; LL + cr###" "aa" "# "## "###; @@ -154,7 +154,7 @@ LL | | string LL | | "#; | |______^ | -help: remove all the hashes around the literal +help: remove all the hashes around the string literal | LL ~ r" LL | \a @@ -169,7 +169,7 @@ error: unnecessary hashes around raw string literal LL | r###"rust"###; | ^^^^^^^^^^^^^ | -help: remove all the hashes around the literal +help: remove all the hashes around the string literal | LL - r###"rust"###; LL + r"rust"; @@ -181,7 +181,7 @@ error: unnecessary hashes around raw string literal LL | r#"hello world"#; | ^^^^^^^^^^^^^^^^ | -help: remove all the hashes around the literal +help: remove all the hashes around the string literal | LL - r#"hello world"#; LL + r"hello world"; diff --git a/tests/ui/print_literal.fixed b/tests/ui/print_literal.fixed index 88cd3a54b4100..a7157c07f8a98 100644 --- a/tests/ui/print_literal.fixed +++ b/tests/ui/print_literal.fixed @@ -39,20 +39,30 @@ fn main() { // throw a warning println!("hello world"); //~^ ERROR: literal with an empty format string - //~| ERROR: literal with an empty format string println!("world hello"); //~^ ERROR: literal with an empty format string - //~| ERROR: literal with an empty format string // named args shouldn't change anything either println!("hello world"); //~^ ERROR: literal with an empty format string - //~| ERROR: literal with an empty format string println!("world hello"); //~^ ERROR: literal with an empty format string - //~| ERROR: literal with an empty format string // The string literal from `file!()` has a callsite span that isn't marked as coming from an // expansion println!("file: {}", file!()); + + // Braces in unicode escapes should not be escaped + println!("{{}} \x00 \u{ab123} \\\u{ab123} {{:?}}"); + println!("\\\u{1234}"); + // This does not lint because it would have to suggest unescaping the character + println!(r"{}", "\u{ab123}"); + // These are not unicode escapes + println!("\\u{{ab123}} \\u{{{{"); + println!(r"\u{{ab123}} \u{{{{"); + println!("\\{{ab123}} \\u{{{{"); + println!("\\u{{ab123}}"); + println!("\\\\u{{1234}}"); + + println!("mixed: {{hello}} {world}"); } diff --git a/tests/ui/print_literal.rs b/tests/ui/print_literal.rs index bd7444c9606ab..4b04b42744ccd 100644 --- a/tests/ui/print_literal.rs +++ b/tests/ui/print_literal.rs @@ -39,20 +39,30 @@ fn main() { // throw a warning println!("{0} {1}", "hello", "world"); //~^ ERROR: literal with an empty format string - //~| ERROR: literal with an empty format string println!("{1} {0}", "hello", "world"); //~^ ERROR: literal with an empty format string - //~| ERROR: literal with an empty format string // named args shouldn't change anything either println!("{foo} {bar}", foo = "hello", bar = "world"); //~^ ERROR: literal with an empty format string - //~| ERROR: literal with an empty format string println!("{bar} {foo}", foo = "hello", bar = "world"); //~^ ERROR: literal with an empty format string - //~| ERROR: literal with an empty format string // The string literal from `file!()` has a callsite span that isn't marked as coming from an // expansion println!("file: {}", file!()); + + // Braces in unicode escapes should not be escaped + println!("{}", "{} \x00 \u{ab123} \\\u{ab123} {:?}"); + println!("{}", "\\\u{1234}"); + // This does not lint because it would have to suggest unescaping the character + println!(r"{}", "\u{ab123}"); + // These are not unicode escapes + println!("{}", r"\u{ab123} \u{{"); + println!(r"{}", r"\u{ab123} \u{{"); + println!("{}", r"\{ab123} \u{{"); + println!("{}", "\\u{ab123}"); + println!("{}", "\\\\u{1234}"); + + println!("mixed: {} {world}", "{hello}"); } diff --git a/tests/ui/print_literal.stderr b/tests/ui/print_literal.stderr index 1d9751b92e9c5..8c011d7bc0a6f 100644 --- a/tests/ui/print_literal.stderr +++ b/tests/ui/print_literal.stderr @@ -52,97 +52,145 @@ error: literal with an empty format string --> $DIR/print_literal.rs:40:25 | LL | println!("{0} {1}", "hello", "world"); - | ^^^^^^^ + | ^^^^^^^^^^^^^^^^ | help: try | LL - println!("{0} {1}", "hello", "world"); -LL + println!("hello {1}", "world"); +LL + println!("hello world"); | error: literal with an empty format string - --> $DIR/print_literal.rs:40:34 + --> $DIR/print_literal.rs:42:25 | -LL | println!("{0} {1}", "hello", "world"); - | ^^^^^^^ +LL | println!("{1} {0}", "hello", "world"); + | ^^^^^^^^^^^^^^^^ | help: try | -LL - println!("{0} {1}", "hello", "world"); -LL + println!("{0} world", "hello"); +LL - println!("{1} {0}", "hello", "world"); +LL + println!("world hello"); | error: literal with an empty format string - --> $DIR/print_literal.rs:43:34 + --> $DIR/print_literal.rs:46:35 | -LL | println!("{1} {0}", "hello", "world"); - | ^^^^^^^ +LL | println!("{foo} {bar}", foo = "hello", bar = "world"); + | ^^^^^^^^^^^^^^^^^^^^^^ | help: try | -LL - println!("{1} {0}", "hello", "world"); -LL + println!("world {0}", "hello"); +LL - println!("{foo} {bar}", foo = "hello", bar = "world"); +LL + println!("hello world"); | error: literal with an empty format string - --> $DIR/print_literal.rs:43:25 + --> $DIR/print_literal.rs:48:35 | -LL | println!("{1} {0}", "hello", "world"); - | ^^^^^^^ +LL | println!("{bar} {foo}", foo = "hello", bar = "world"); + | ^^^^^^^^^^^^^^^^^^^^^^ | help: try | -LL - println!("{1} {0}", "hello", "world"); -LL + println!("{1} hello", "world"); +LL - println!("{bar} {foo}", foo = "hello", bar = "world"); +LL + println!("world hello"); | error: literal with an empty format string - --> $DIR/print_literal.rs:48:35 + --> $DIR/print_literal.rs:56:20 | -LL | println!("{foo} {bar}", foo = "hello", bar = "world"); - | ^^^^^^^ +LL | println!("{}", "{} \x00 \u{ab123} \\\u{ab123} {:?}"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: try | -LL - println!("{foo} {bar}", foo = "hello", bar = "world"); -LL + println!("hello {bar}", bar = "world"); +LL - println!("{}", "{} \x00 \u{ab123} \\\u{ab123} {:?}"); +LL + println!("{{}} \x00 \u{ab123} \\\u{ab123} {{:?}}"); | error: literal with an empty format string - --> $DIR/print_literal.rs:48:50 + --> $DIR/print_literal.rs:57:20 | -LL | println!("{foo} {bar}", foo = "hello", bar = "world"); - | ^^^^^^^ +LL | println!("{}", "\\\u{1234}"); + | ^^^^^^^^^^^^ | help: try | -LL - println!("{foo} {bar}", foo = "hello", bar = "world"); -LL + println!("{foo} world", foo = "hello"); +LL - println!("{}", "\\\u{1234}"); +LL + println!("\\\u{1234}"); | error: literal with an empty format string - --> $DIR/print_literal.rs:51:50 + --> $DIR/print_literal.rs:61:20 | -LL | println!("{bar} {foo}", foo = "hello", bar = "world"); - | ^^^^^^^ +LL | println!("{}", r"\u{ab123} \u{{"); + | ^^^^^^^^^^^^^^^^^ | help: try | -LL - println!("{bar} {foo}", foo = "hello", bar = "world"); -LL + println!("world {foo}", foo = "hello"); +LL - println!("{}", r"\u{ab123} \u{{"); +LL + println!("\\u{{ab123}} \\u{{{{"); | error: literal with an empty format string - --> $DIR/print_literal.rs:51:35 + --> $DIR/print_literal.rs:62:21 | -LL | println!("{bar} {foo}", foo = "hello", bar = "world"); - | ^^^^^^^ +LL | println!(r"{}", r"\u{ab123} \u{{"); + | ^^^^^^^^^^^^^^^^^ | help: try | -LL - println!("{bar} {foo}", foo = "hello", bar = "world"); -LL + println!("{bar} hello", bar = "world"); +LL - println!(r"{}", r"\u{ab123} \u{{"); +LL + println!(r"\u{{ab123}} \u{{{{"); + | + +error: literal with an empty format string + --> $DIR/print_literal.rs:63:20 + | +LL | println!("{}", r"\{ab123} \u{{"); + | ^^^^^^^^^^^^^^^^ + | +help: try + | +LL - println!("{}", r"\{ab123} \u{{"); +LL + println!("\\{{ab123}} \\u{{{{"); + | + +error: literal with an empty format string + --> $DIR/print_literal.rs:64:20 + | +LL | println!("{}", "\\u{ab123}"); + | ^^^^^^^^^^^^ + | +help: try + | +LL - println!("{}", "\\u{ab123}"); +LL + println!("\\u{{ab123}}"); + | + +error: literal with an empty format string + --> $DIR/print_literal.rs:65:20 + | +LL | println!("{}", "\\\\u{1234}"); + | ^^^^^^^^^^^^^ + | +help: try + | +LL - println!("{}", "\\\\u{1234}"); +LL + println!("\\\\u{{1234}}"); + | + +error: literal with an empty format string + --> $DIR/print_literal.rs:67:35 + | +LL | println!("mixed: {} {world}", "{hello}"); + | ^^^^^^^^^ + | +help: try + | +LL - println!("mixed: {} {world}", "{hello}"); +LL + println!("mixed: {{hello}} {world}"); | -error: aborting due to 12 previous errors +error: aborting due to 16 previous errors diff --git a/tests/ui/redundant_locals.rs b/tests/ui/redundant_locals.rs index c5d93e4365d90..e81db300f15a2 100644 --- a/tests/ui/redundant_locals.rs +++ b/tests/ui/redundant_locals.rs @@ -118,3 +118,40 @@ fn macros() { let x = x; } } + +struct WithDrop(usize); +impl Drop for WithDrop { + fn drop(&mut self) {} +} + +struct InnerDrop(WithDrop); + +struct ComposeDrop { + d: WithDrop, +} + +struct WithoutDrop(usize); + +fn drop_trait() { + let a = WithDrop(1); + let b = WithDrop(2); + let a = a; +} + +fn without_drop() { + let a = WithoutDrop(1); + let b = WithoutDrop(2); + let a = a; +} + +fn drop_inner() { + let a = InnerDrop(WithDrop(1)); + let b = InnerDrop(WithDrop(2)); + let a = a; +} + +fn drop_compose() { + let a = ComposeDrop { d: WithDrop(1) }; + let b = ComposeDrop { d: WithDrop(1) }; + let a = a; +} diff --git a/tests/ui/redundant_locals.stderr b/tests/ui/redundant_locals.stderr index 13b872e9576d8..d794a87fe7df6 100644 --- a/tests/ui/redundant_locals.stderr +++ b/tests/ui/redundant_locals.stderr @@ -1,137 +1,172 @@ -error: redundant redefinition of a binding - --> $DIR/redundant_locals.rs:11:9 +error: redundant redefinition of a binding `x` + --> $DIR/redundant_locals.rs:12:5 | -LL | let x = 1; - | ^ LL | let x = x; | ^^^^^^^^^^ | - = help: remove the redefinition of `x` +help: `x` is initially defined here + --> $DIR/redundant_locals.rs:11:9 + | +LL | let x = 1; + | ^ = note: `-D clippy::redundant-locals` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::redundant_locals)]` -error: redundant redefinition of a binding - --> $DIR/redundant_locals.rs:16:9 +error: redundant redefinition of a binding `x` + --> $DIR/redundant_locals.rs:17:5 | -LL | let mut x = 1; - | ^^^^^ LL | let mut x = x; | ^^^^^^^^^^^^^^ | - = help: remove the redefinition of `x` +help: `x` is initially defined here + --> $DIR/redundant_locals.rs:16:9 + | +LL | let mut x = 1; + | ^^^^^ -error: redundant redefinition of a binding +error: redundant redefinition of a binding `x` + --> $DIR/redundant_locals.rs:47:5 + | +LL | let x = x; + | ^^^^^^^^^^ + | +help: `x` is initially defined here --> $DIR/redundant_locals.rs:46:14 | LL | fn parameter(x: i32) { | ^ + +error: redundant redefinition of a binding `x` + --> $DIR/redundant_locals.rs:52:5 + | LL | let x = x; | ^^^^^^^^^^ | - = help: remove the redefinition of `x` - -error: redundant redefinition of a binding +help: `x` is initially defined here --> $DIR/redundant_locals.rs:51:9 | LL | let x = 1; | ^ + +error: redundant redefinition of a binding `x` + --> $DIR/redundant_locals.rs:53:5 + | LL | let x = x; | ^^^^^^^^^^ | - = help: remove the redefinition of `x` - -error: redundant redefinition of a binding +help: `x` is initially defined here --> $DIR/redundant_locals.rs:52:9 | LL | let x = x; | ^ + +error: redundant redefinition of a binding `x` + --> $DIR/redundant_locals.rs:54:5 + | LL | let x = x; | ^^^^^^^^^^ | - = help: remove the redefinition of `x` - -error: redundant redefinition of a binding +help: `x` is initially defined here --> $DIR/redundant_locals.rs:53:9 | LL | let x = x; | ^ + +error: redundant redefinition of a binding `x` + --> $DIR/redundant_locals.rs:55:5 + | LL | let x = x; | ^^^^^^^^^^ | - = help: remove the redefinition of `x` - -error: redundant redefinition of a binding +help: `x` is initially defined here --> $DIR/redundant_locals.rs:54:9 | LL | let x = x; | ^ -LL | let x = x; + +error: redundant redefinition of a binding `a` + --> $DIR/redundant_locals.rs:61:5 + | +LL | let a = a; | ^^^^^^^^^^ | - = help: remove the redefinition of `x` - -error: redundant redefinition of a binding +help: `a` is initially defined here --> $DIR/redundant_locals.rs:59:9 | LL | let a = 1; | ^ -LL | let b = 2; -LL | let a = a; + +error: redundant redefinition of a binding `b` + --> $DIR/redundant_locals.rs:62:5 + | +LL | let b = b; | ^^^^^^^^^^ | - = help: remove the redefinition of `a` - -error: redundant redefinition of a binding +help: `b` is initially defined here --> $DIR/redundant_locals.rs:60:9 | LL | let b = 2; | ^ -LL | let a = a; -LL | let b = b; - | ^^^^^^^^^^ - | - = help: remove the redefinition of `b` -error: redundant redefinition of a binding +error: redundant redefinition of a binding `x` + --> $DIR/redundant_locals.rs:68:9 + | +LL | let x = x; + | ^^^^^^^^^^ + | +help: `x` is initially defined here --> $DIR/redundant_locals.rs:67:13 | LL | let x = 1; | ^ + +error: redundant redefinition of a binding `x` + --> $DIR/redundant_locals.rs:75:9 + | LL | let x = x; | ^^^^^^^^^^ | - = help: remove the redefinition of `x` - -error: redundant redefinition of a binding +help: `x` is initially defined here --> $DIR/redundant_locals.rs:74:13 | LL | let x = 1; | ^ + +error: redundant redefinition of a binding `x` + --> $DIR/redundant_locals.rs:78:9 + | LL | let x = x; | ^^^^^^^^^^ | - = help: remove the redefinition of `x` - -error: redundant redefinition of a binding +help: `x` is initially defined here --> $DIR/redundant_locals.rs:77:6 | LL | |x: i32| { | ^ + +error: redundant redefinition of a binding `x` + --> $DIR/redundant_locals.rs:97:9 + | LL | let x = x; | ^^^^^^^^^^ | - = help: remove the redefinition of `x` - -error: redundant redefinition of a binding +help: `x` is initially defined here --> $DIR/redundant_locals.rs:94:9 | LL | let x = 1; | ^ -... -LL | let x = x; - | ^^^^^^^^^^ + +error: redundant redefinition of a binding `a` + --> $DIR/redundant_locals.rs:144:5 + | +LL | let a = a; + | ^^^^^^^^^^ | - = help: remove the redefinition of `x` +help: `a` is initially defined here + --> $DIR/redundant_locals.rs:142:9 + | +LL | let a = WithoutDrop(1); + | ^ -error: aborting due to 13 previous errors +error: aborting due to 14 previous errors diff --git a/tests/ui/should_impl_trait/method_list_2.rs b/tests/ui/should_impl_trait/method_list_2.rs index 550ec00726817..33211b32d74b3 100644 --- a/tests/ui/should_impl_trait/method_list_2.rs +++ b/tests/ui/should_impl_trait/method_list_2.rs @@ -40,8 +40,6 @@ impl T { pub fn hash(&self, state: &mut T) { //~^ ERROR: method `hash` can be confused for the standard trait method `std::hash::Ha - //~| ERROR: this argument is a mutable reference, but not used mutably - //~| NOTE: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings` unimplemented!() } diff --git a/tests/ui/should_impl_trait/method_list_2.stderr b/tests/ui/should_impl_trait/method_list_2.stderr index 79afddea24798..c257f41134266 100644 --- a/tests/ui/should_impl_trait/method_list_2.stderr +++ b/tests/ui/should_impl_trait/method_list_2.stderr @@ -38,8 +38,6 @@ error: method `hash` can be confused for the standard trait method `std::hash::H | LL | / pub fn hash(&self, state: &mut T) { LL | | -LL | | -LL | | LL | | unimplemented!() LL | | } | |_____^ @@ -47,7 +45,7 @@ LL | | } = help: consider implementing the trait `std::hash::Hash` or choosing a less ambiguous method name error: method `index` can be confused for the standard trait method `std::ops::Index::index` - --> $DIR/method_list_2.rs:48:5 + --> $DIR/method_list_2.rs:46:5 | LL | / pub fn index(&self, index: usize) -> &Self { LL | | @@ -58,7 +56,7 @@ LL | | } = help: consider implementing the trait `std::ops::Index` or choosing a less ambiguous method name error: method `index_mut` can be confused for the standard trait method `std::ops::IndexMut::index_mut` - --> $DIR/method_list_2.rs:53:5 + --> $DIR/method_list_2.rs:51:5 | LL | / pub fn index_mut(&mut self, index: usize) -> &mut Self { LL | | @@ -69,7 +67,7 @@ LL | | } = help: consider implementing the trait `std::ops::IndexMut` or choosing a less ambiguous method name error: method `into_iter` can be confused for the standard trait method `std::iter::IntoIterator::into_iter` - --> $DIR/method_list_2.rs:58:5 + --> $DIR/method_list_2.rs:56:5 | LL | / pub fn into_iter(self) -> Self { LL | | @@ -80,7 +78,7 @@ LL | | } = help: consider implementing the trait `std::iter::IntoIterator` or choosing a less ambiguous method name error: method `mul` can be confused for the standard trait method `std::ops::Mul::mul` - --> $DIR/method_list_2.rs:63:5 + --> $DIR/method_list_2.rs:61:5 | LL | / pub fn mul(self, rhs: Self) -> Self { LL | | @@ -91,7 +89,7 @@ LL | | } = help: consider implementing the trait `std::ops::Mul` or choosing a less ambiguous method name error: method `neg` can be confused for the standard trait method `std::ops::Neg::neg` - --> $DIR/method_list_2.rs:68:5 + --> $DIR/method_list_2.rs:66:5 | LL | / pub fn neg(self) -> Self { LL | | @@ -102,7 +100,7 @@ LL | | } = help: consider implementing the trait `std::ops::Neg` or choosing a less ambiguous method name error: method `next` can be confused for the standard trait method `std::iter::Iterator::next` - --> $DIR/method_list_2.rs:73:5 + --> $DIR/method_list_2.rs:71:5 | LL | / pub fn next(&mut self) -> Option { LL | | @@ -113,7 +111,7 @@ LL | | } = help: consider implementing the trait `std::iter::Iterator` or choosing a less ambiguous method name error: method `not` can be confused for the standard trait method `std::ops::Not::not` - --> $DIR/method_list_2.rs:78:5 + --> $DIR/method_list_2.rs:76:5 | LL | / pub fn not(self) -> Self { LL | | @@ -124,7 +122,7 @@ LL | | } = help: consider implementing the trait `std::ops::Not` or choosing a less ambiguous method name error: method `rem` can be confused for the standard trait method `std::ops::Rem::rem` - --> $DIR/method_list_2.rs:83:5 + --> $DIR/method_list_2.rs:81:5 | LL | / pub fn rem(self, rhs: Self) -> Self { LL | | @@ -135,7 +133,7 @@ LL | | } = help: consider implementing the trait `std::ops::Rem` or choosing a less ambiguous method name error: method `shl` can be confused for the standard trait method `std::ops::Shl::shl` - --> $DIR/method_list_2.rs:88:5 + --> $DIR/method_list_2.rs:86:5 | LL | / pub fn shl(self, rhs: Self) -> Self { LL | | @@ -146,7 +144,7 @@ LL | | } = help: consider implementing the trait `std::ops::Shl` or choosing a less ambiguous method name error: method `shr` can be confused for the standard trait method `std::ops::Shr::shr` - --> $DIR/method_list_2.rs:93:5 + --> $DIR/method_list_2.rs:91:5 | LL | / pub fn shr(self, rhs: Self) -> Self { LL | | @@ -157,7 +155,7 @@ LL | | } = help: consider implementing the trait `std::ops::Shr` or choosing a less ambiguous method name error: method `sub` can be confused for the standard trait method `std::ops::Sub::sub` - --> $DIR/method_list_2.rs:98:5 + --> $DIR/method_list_2.rs:96:5 | LL | / pub fn sub(self, rhs: Self) -> Self { LL | | @@ -167,15 +165,5 @@ LL | | } | = help: consider implementing the trait `std::ops::Sub` or choosing a less ambiguous method name -error: this argument is a mutable reference, but not used mutably - --> $DIR/method_list_2.rs:41:31 - | -LL | pub fn hash(&self, state: &mut T) { - | ^^^^^^ help: consider changing to: `&T` - | - = warning: changing this function will impact semver compatibility - = note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::needless_pass_by_ref_mut)]` - -error: aborting due to 16 previous errors +error: aborting due to 15 previous errors diff --git a/tests/ui/slow_vector_initialization.rs b/tests/ui/slow_vector_initialization.rs index 5c3086c9d69ea..16f81019574fb 100644 --- a/tests/ui/slow_vector_initialization.rs +++ b/tests/ui/slow_vector_initialization.rs @@ -103,8 +103,6 @@ fn from_empty_vec() { } fn do_stuff(vec: &mut [u8]) {} -//~^ ERROR: this argument is a mutable reference, but not used mutably -//~| NOTE: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings` fn extend_vector_with_manipulations_between() { let len = 300; diff --git a/tests/ui/slow_vector_initialization.stderr b/tests/ui/slow_vector_initialization.stderr index 4d24400ecb596..16a7057653c10 100644 --- a/tests/ui/slow_vector_initialization.stderr +++ b/tests/ui/slow_vector_initialization.stderr @@ -105,14 +105,5 @@ LL | vec1 = vec![]; LL | vec1.resize(10, 0); | ^^^^^^^^^^^^^^^^^^ -error: this argument is a mutable reference, but not used mutably - --> $DIR/slow_vector_initialization.rs:105:18 - | -LL | fn do_stuff(vec: &mut [u8]) {} - | ^^^^^^^^^ help: consider changing to: `&[u8]` - | - = note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::needless_pass_by_ref_mut)]` - -error: aborting due to 14 previous errors +error: aborting due to 13 previous errors diff --git a/tests/ui/std_instead_of_core.fixed b/tests/ui/std_instead_of_core.fixed index 8027c053fb5b0..a7555704fbe01 100644 --- a/tests/ui/std_instead_of_core.fixed +++ b/tests/ui/std_instead_of_core.fixed @@ -1,8 +1,12 @@ +//@aux-build:proc_macro_derive.rs #![warn(clippy::std_instead_of_core)] #![allow(unused_imports)] extern crate alloc; +#[macro_use] +extern crate proc_macro_derive; + #[warn(clippy::std_instead_of_core)] fn std_instead_of_core() { // Regular import @@ -55,6 +59,13 @@ fn alloc_instead_of_core() { //~^ ERROR: used import from `alloc` instead of `core` } +mod std_in_proc_macro_derive { + #[warn(clippy::alloc_instead_of_core)] + #[allow(unused)] + #[derive(ImplStructWithStdDisplay)] + struct B {} +} + fn main() { std_instead_of_core(); std_instead_of_alloc(); diff --git a/tests/ui/std_instead_of_core.rs b/tests/ui/std_instead_of_core.rs index 63a096384d716..af7f3399f4923 100644 --- a/tests/ui/std_instead_of_core.rs +++ b/tests/ui/std_instead_of_core.rs @@ -1,8 +1,12 @@ +//@aux-build:proc_macro_derive.rs #![warn(clippy::std_instead_of_core)] #![allow(unused_imports)] extern crate alloc; +#[macro_use] +extern crate proc_macro_derive; + #[warn(clippy::std_instead_of_core)] fn std_instead_of_core() { // Regular import @@ -55,6 +59,13 @@ fn alloc_instead_of_core() { //~^ ERROR: used import from `alloc` instead of `core` } +mod std_in_proc_macro_derive { + #[warn(clippy::alloc_instead_of_core)] + #[allow(unused)] + #[derive(ImplStructWithStdDisplay)] + struct B {} +} + fn main() { std_instead_of_core(); std_instead_of_alloc(); diff --git a/tests/ui/std_instead_of_core.stderr b/tests/ui/std_instead_of_core.stderr index ca26f77bd37f9..4f7bdc4045e77 100644 --- a/tests/ui/std_instead_of_core.stderr +++ b/tests/ui/std_instead_of_core.stderr @@ -1,5 +1,5 @@ error: used import from `std` instead of `core` - --> $DIR/std_instead_of_core.rs:9:9 + --> $DIR/std_instead_of_core.rs:13:9 | LL | use std::hash::Hasher; | ^^^ help: consider importing the item from `core`: `core` @@ -8,49 +8,49 @@ LL | use std::hash::Hasher; = help: to override `-D warnings` add `#[allow(clippy::std_instead_of_core)]` error: used import from `std` instead of `core` - --> $DIR/std_instead_of_core.rs:12:11 + --> $DIR/std_instead_of_core.rs:16:11 | LL | use ::std::hash::Hash; | ^^^ help: consider importing the item from `core`: `core` error: used import from `std` instead of `core` - --> $DIR/std_instead_of_core.rs:18:9 + --> $DIR/std_instead_of_core.rs:22:9 | LL | use std::fmt::{Debug, Result}; | ^^^ help: consider importing the item from `core`: `core` error: used import from `std` instead of `core` - --> $DIR/std_instead_of_core.rs:22:15 + --> $DIR/std_instead_of_core.rs:26:15 | LL | let ptr = std::ptr::null::(); | ^^^ help: consider importing the item from `core`: `core` error: used import from `std` instead of `core` - --> $DIR/std_instead_of_core.rs:24:21 + --> $DIR/std_instead_of_core.rs:28:21 | LL | let ptr_mut = ::std::ptr::null_mut::(); | ^^^ help: consider importing the item from `core`: `core` error: used import from `std` instead of `core` - --> $DIR/std_instead_of_core.rs:28:16 + --> $DIR/std_instead_of_core.rs:32:16 | LL | let cell = std::cell::Cell::new(8u32); | ^^^ help: consider importing the item from `core`: `core` error: used import from `std` instead of `core` - --> $DIR/std_instead_of_core.rs:30:27 + --> $DIR/std_instead_of_core.rs:34:27 | LL | let cell_absolute = ::std::cell::Cell::new(8u32); | ^^^ help: consider importing the item from `core`: `core` error: used import from `std` instead of `core` - --> $DIR/std_instead_of_core.rs:39:9 + --> $DIR/std_instead_of_core.rs:43:9 | LL | use std::iter::Iterator; | ^^^ help: consider importing the item from `core`: `core` error: used import from `std` instead of `alloc` - --> $DIR/std_instead_of_core.rs:46:9 + --> $DIR/std_instead_of_core.rs:50:9 | LL | use std::vec; | ^^^ help: consider importing the item from `alloc`: `alloc` @@ -59,13 +59,13 @@ LL | use std::vec; = help: to override `-D warnings` add `#[allow(clippy::std_instead_of_alloc)]` error: used import from `std` instead of `alloc` - --> $DIR/std_instead_of_core.rs:48:9 + --> $DIR/std_instead_of_core.rs:52:9 | LL | use std::vec::Vec; | ^^^ help: consider importing the item from `alloc`: `alloc` error: used import from `alloc` instead of `core` - --> $DIR/std_instead_of_core.rs:54:9 + --> $DIR/std_instead_of_core.rs:58:9 | LL | use alloc::slice::from_ref; | ^^^^^ help: consider importing the item from `core`: `core` diff --git a/tests/ui/wildcard_imports.fixed b/tests/ui/wildcard_imports.fixed index 2828f9d048efc..6fdd728b9b72e 100644 --- a/tests/ui/wildcard_imports.fixed +++ b/tests/ui/wildcard_imports.fixed @@ -69,6 +69,34 @@ mod struct_mod { } } +// issue 9942 +mod underscore_mod { + // allow use of `deref` so that `clippy --fix` includes `Deref`. + #![allow(noop_method_call)] + + mod exports_underscore { + pub use std::ops::Deref as _; + pub fn dummy() {} + } + + mod exports_underscore_ish { + pub use std::ops::Deref as _Deref; + pub fn dummy() {} + } + + fn does_not_lint() { + use self::exports_underscore::*; + let _ = (&0).deref(); + dummy(); + } + + fn does_lint() { + use self::exports_underscore_ish::{_Deref, dummy}; + let _ = (&0).deref(); + dummy(); + } +} + fn main() { foo(); multi_foo(); diff --git a/tests/ui/wildcard_imports.rs b/tests/ui/wildcard_imports.rs index cbe70e505d8cd..20e06d4b36641 100644 --- a/tests/ui/wildcard_imports.rs +++ b/tests/ui/wildcard_imports.rs @@ -69,6 +69,34 @@ mod struct_mod { } } +// issue 9942 +mod underscore_mod { + // allow use of `deref` so that `clippy --fix` includes `Deref`. + #![allow(noop_method_call)] + + mod exports_underscore { + pub use std::ops::Deref as _; + pub fn dummy() {} + } + + mod exports_underscore_ish { + pub use std::ops::Deref as _Deref; + pub fn dummy() {} + } + + fn does_not_lint() { + use self::exports_underscore::*; + let _ = (&0).deref(); + dummy(); + } + + fn does_lint() { + use self::exports_underscore_ish::*; + let _ = (&0).deref(); + dummy(); + } +} + fn main() { foo(); multi_foo(); diff --git a/tests/ui/wildcard_imports.stderr b/tests/ui/wildcard_imports.stderr index 3c750815bafc9..01a5414778c10 100644 --- a/tests/ui/wildcard_imports.stderr +++ b/tests/ui/wildcard_imports.stderr @@ -38,55 +38,61 @@ LL | use wildcard_imports_helper::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:97:13 + --> $DIR/wildcard_imports.rs:94:13 + | +LL | use self::exports_underscore_ish::*; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `self::exports_underscore_ish::{_Deref, dummy}` + +error: usage of wildcard import + --> $DIR/wildcard_imports.rs:125:13 | LL | use crate::fn_mod::*; | ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:103:75 + --> $DIR/wildcard_imports.rs:131:75 | LL | use wildcard_imports_helper::inner::inner_for_self_import::{self, *}; | ^ help: try: `inner_extern_foo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:104:13 + --> $DIR/wildcard_imports.rs:132:13 | LL | use wildcard_imports_helper::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:116:20 + --> $DIR/wildcard_imports.rs:144:20 | LL | use self::{inner::*, inner2::*}; | ^^^^^^^^ help: try: `inner::inner_foo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:116:30 + --> $DIR/wildcard_imports.rs:144:30 | LL | use self::{inner::*, inner2::*}; | ^^^^^^^^^ help: try: `inner2::inner_bar` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:123:13 + --> $DIR/wildcard_imports.rs:151:13 | LL | use wildcard_imports_helper::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported}` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:152:9 + --> $DIR/wildcard_imports.rs:180:9 | LL | use crate::in_fn_test::*; | ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::in_fn_test::{ExportedEnum, ExportedStruct, exported}` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:161:9 + --> $DIR/wildcard_imports.rs:189:9 | LL | use crate:: in_fn_test:: * ; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate:: in_fn_test::exported` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:162:9 + --> $DIR/wildcard_imports.rs:190:9 | LL | use crate:: fn_mod:: | _________^ @@ -94,40 +100,40 @@ LL | | *; | |_________^ help: try: `crate:: fn_mod::foo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:173:13 + --> $DIR/wildcard_imports.rs:201:13 | LL | use super::*; | ^^^^^^^^ help: try: `super::foofoo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:208:17 + --> $DIR/wildcard_imports.rs:236:17 | LL | use super::*; | ^^^^^^^^ help: try: `super::insidefoo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:216:13 + --> $DIR/wildcard_imports.rs:244:13 | LL | use crate::super_imports::*; | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::super_imports::foofoo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:225:17 + --> $DIR/wildcard_imports.rs:253:17 | LL | use super::super::*; | ^^^^^^^^^^^^^^^ help: try: `super::super::foofoo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:234:13 + --> $DIR/wildcard_imports.rs:262:13 | LL | use super::super::super_imports::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `super::super::super_imports::foofoo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:242:13 + --> $DIR/wildcard_imports.rs:270:13 | LL | use super::*; | ^^^^^^^^ help: try: `super::foofoo` -error: aborting due to 21 previous errors +error: aborting due to 22 previous errors diff --git a/tests/ui/wildcard_imports_2021.edition2018.fixed b/tests/ui/wildcard_imports_2021.edition2018.fixed index b27281fa25c56..6a9fe007d654d 100644 --- a/tests/ui/wildcard_imports_2021.edition2018.fixed +++ b/tests/ui/wildcard_imports_2021.edition2018.fixed @@ -64,6 +64,34 @@ mod struct_mod { } } +// issue 9942 +mod underscore_mod { + // allow use of `deref` so that `clippy --fix` includes `Deref`. + #![allow(noop_method_call)] + + mod exports_underscore { + pub use std::ops::Deref as _; + pub fn dummy() {} + } + + mod exports_underscore_ish { + pub use std::ops::Deref as _Deref; + pub fn dummy() {} + } + + fn does_not_lint() { + use exports_underscore::*; + let _ = (&0).deref(); + dummy(); + } + + fn does_lint() { + use exports_underscore_ish::{_Deref, dummy}; + let _ = (&0).deref(); + dummy(); + } +} + fn main() { foo(); multi_foo(); diff --git a/tests/ui/wildcard_imports_2021.edition2018.stderr b/tests/ui/wildcard_imports_2021.edition2018.stderr index 709a665d65c2a..e39f240a4aa2a 100644 --- a/tests/ui/wildcard_imports_2021.edition2018.stderr +++ b/tests/ui/wildcard_imports_2021.edition2018.stderr @@ -38,55 +38,61 @@ LL | use wildcard_imports_helper::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:91:13 + --> $DIR/wildcard_imports_2021.rs:89:13 + | +LL | use exports_underscore_ish::*; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `exports_underscore_ish::{_Deref, dummy}` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:119:13 | LL | use crate::fn_mod::*; | ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:97:75 + --> $DIR/wildcard_imports_2021.rs:125:75 | LL | use wildcard_imports_helper::inner::inner_for_self_import::{self, *}; | ^ help: try: `inner_extern_foo` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:98:13 + --> $DIR/wildcard_imports_2021.rs:126:13 | LL | use wildcard_imports_helper::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:110:20 + --> $DIR/wildcard_imports_2021.rs:138:20 | LL | use self::{inner::*, inner2::*}; | ^^^^^^^^ help: try: `inner::inner_foo` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:110:30 + --> $DIR/wildcard_imports_2021.rs:138:30 | LL | use self::{inner::*, inner2::*}; | ^^^^^^^^^ help: try: `inner2::inner_bar` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:117:13 + --> $DIR/wildcard_imports_2021.rs:145:13 | LL | use wildcard_imports_helper::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported}` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:146:9 + --> $DIR/wildcard_imports_2021.rs:174:9 | LL | use crate::in_fn_test::*; | ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::in_fn_test::{ExportedEnum, ExportedStruct, exported}` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:155:9 + --> $DIR/wildcard_imports_2021.rs:183:9 | LL | use crate:: in_fn_test:: * ; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate:: in_fn_test::exported` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:156:9 + --> $DIR/wildcard_imports_2021.rs:184:9 | LL | use crate:: fn_mod:: | _________^ @@ -94,40 +100,40 @@ LL | | *; | |_________^ help: try: `crate:: fn_mod::foo` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:167:13 + --> $DIR/wildcard_imports_2021.rs:195:13 | LL | use super::*; | ^^^^^^^^ help: try: `super::foofoo` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:202:17 + --> $DIR/wildcard_imports_2021.rs:230:17 | LL | use super::*; | ^^^^^^^^ help: try: `super::insidefoo` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:210:13 + --> $DIR/wildcard_imports_2021.rs:238:13 | LL | use crate::super_imports::*; | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::super_imports::foofoo` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:219:17 + --> $DIR/wildcard_imports_2021.rs:247:17 | LL | use super::super::*; | ^^^^^^^^^^^^^^^ help: try: `super::super::foofoo` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:228:13 + --> $DIR/wildcard_imports_2021.rs:256:13 | LL | use super::super::super_imports::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `super::super::super_imports::foofoo` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:236:13 + --> $DIR/wildcard_imports_2021.rs:264:13 | LL | use super::*; | ^^^^^^^^ help: try: `super::foofoo` -error: aborting due to 21 previous errors +error: aborting due to 22 previous errors diff --git a/tests/ui/wildcard_imports_2021.edition2021.fixed b/tests/ui/wildcard_imports_2021.edition2021.fixed index b27281fa25c56..6a9fe007d654d 100644 --- a/tests/ui/wildcard_imports_2021.edition2021.fixed +++ b/tests/ui/wildcard_imports_2021.edition2021.fixed @@ -64,6 +64,34 @@ mod struct_mod { } } +// issue 9942 +mod underscore_mod { + // allow use of `deref` so that `clippy --fix` includes `Deref`. + #![allow(noop_method_call)] + + mod exports_underscore { + pub use std::ops::Deref as _; + pub fn dummy() {} + } + + mod exports_underscore_ish { + pub use std::ops::Deref as _Deref; + pub fn dummy() {} + } + + fn does_not_lint() { + use exports_underscore::*; + let _ = (&0).deref(); + dummy(); + } + + fn does_lint() { + use exports_underscore_ish::{_Deref, dummy}; + let _ = (&0).deref(); + dummy(); + } +} + fn main() { foo(); multi_foo(); diff --git a/tests/ui/wildcard_imports_2021.edition2021.stderr b/tests/ui/wildcard_imports_2021.edition2021.stderr index 709a665d65c2a..e39f240a4aa2a 100644 --- a/tests/ui/wildcard_imports_2021.edition2021.stderr +++ b/tests/ui/wildcard_imports_2021.edition2021.stderr @@ -38,55 +38,61 @@ LL | use wildcard_imports_helper::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:91:13 + --> $DIR/wildcard_imports_2021.rs:89:13 + | +LL | use exports_underscore_ish::*; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `exports_underscore_ish::{_Deref, dummy}` + +error: usage of wildcard import + --> $DIR/wildcard_imports_2021.rs:119:13 | LL | use crate::fn_mod::*; | ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:97:75 + --> $DIR/wildcard_imports_2021.rs:125:75 | LL | use wildcard_imports_helper::inner::inner_for_self_import::{self, *}; | ^ help: try: `inner_extern_foo` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:98:13 + --> $DIR/wildcard_imports_2021.rs:126:13 | LL | use wildcard_imports_helper::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:110:20 + --> $DIR/wildcard_imports_2021.rs:138:20 | LL | use self::{inner::*, inner2::*}; | ^^^^^^^^ help: try: `inner::inner_foo` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:110:30 + --> $DIR/wildcard_imports_2021.rs:138:30 | LL | use self::{inner::*, inner2::*}; | ^^^^^^^^^ help: try: `inner2::inner_bar` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:117:13 + --> $DIR/wildcard_imports_2021.rs:145:13 | LL | use wildcard_imports_helper::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported}` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:146:9 + --> $DIR/wildcard_imports_2021.rs:174:9 | LL | use crate::in_fn_test::*; | ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::in_fn_test::{ExportedEnum, ExportedStruct, exported}` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:155:9 + --> $DIR/wildcard_imports_2021.rs:183:9 | LL | use crate:: in_fn_test:: * ; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate:: in_fn_test::exported` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:156:9 + --> $DIR/wildcard_imports_2021.rs:184:9 | LL | use crate:: fn_mod:: | _________^ @@ -94,40 +100,40 @@ LL | | *; | |_________^ help: try: `crate:: fn_mod::foo` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:167:13 + --> $DIR/wildcard_imports_2021.rs:195:13 | LL | use super::*; | ^^^^^^^^ help: try: `super::foofoo` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:202:17 + --> $DIR/wildcard_imports_2021.rs:230:17 | LL | use super::*; | ^^^^^^^^ help: try: `super::insidefoo` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:210:13 + --> $DIR/wildcard_imports_2021.rs:238:13 | LL | use crate::super_imports::*; | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::super_imports::foofoo` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:219:17 + --> $DIR/wildcard_imports_2021.rs:247:17 | LL | use super::super::*; | ^^^^^^^^^^^^^^^ help: try: `super::super::foofoo` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:228:13 + --> $DIR/wildcard_imports_2021.rs:256:13 | LL | use super::super::super_imports::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `super::super::super_imports::foofoo` error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:236:13 + --> $DIR/wildcard_imports_2021.rs:264:13 | LL | use super::*; | ^^^^^^^^ help: try: `super::foofoo` -error: aborting due to 21 previous errors +error: aborting due to 22 previous errors diff --git a/tests/ui/wildcard_imports_2021.rs b/tests/ui/wildcard_imports_2021.rs index 7dd2103eca7e7..18ebc0f512741 100644 --- a/tests/ui/wildcard_imports_2021.rs +++ b/tests/ui/wildcard_imports_2021.rs @@ -64,6 +64,34 @@ mod struct_mod { } } +// issue 9942 +mod underscore_mod { + // allow use of `deref` so that `clippy --fix` includes `Deref`. + #![allow(noop_method_call)] + + mod exports_underscore { + pub use std::ops::Deref as _; + pub fn dummy() {} + } + + mod exports_underscore_ish { + pub use std::ops::Deref as _Deref; + pub fn dummy() {} + } + + fn does_not_lint() { + use exports_underscore::*; + let _ = (&0).deref(); + dummy(); + } + + fn does_lint() { + use exports_underscore_ish::*; + let _ = (&0).deref(); + dummy(); + } +} + fn main() { foo(); multi_foo(); diff --git a/tests/ui/write_literal.fixed b/tests/ui/write_literal.fixed index ee577574d2898..3d216b76cbf3d 100644 --- a/tests/ui/write_literal.fixed +++ b/tests/ui/write_literal.fixed @@ -43,16 +43,22 @@ fn main() { // throw a warning writeln!(v, "hello world"); //~^ ERROR: literal with an empty format string - //~| ERROR: literal with an empty format string writeln!(v, "world hello"); //~^ ERROR: literal with an empty format string - //~| ERROR: literal with an empty format string // named args shouldn't change anything either writeln!(v, "hello world"); //~^ ERROR: literal with an empty format string - //~| ERROR: literal with an empty format string writeln!(v, "world hello"); //~^ ERROR: literal with an empty format string - //~| ERROR: literal with an empty format string + + // #10128 + writeln!(v, "hello {0} world", 2); + //~^ ERROR: literal with an empty format string + writeln!(v, "world {0} hello", 2); + //~^ ERROR: literal with an empty format string + writeln!(v, "hello {0} {1}, {bar}", 2, 3, bar = 4); + //~^ ERROR: literal with an empty format string + writeln!(v, "hello {0} {1}, world {2}", 2, 3, 4); + //~^ ERROR: literal with an empty format string } diff --git a/tests/ui/write_literal.rs b/tests/ui/write_literal.rs index 588e8fd413a48..79d6daa2e3b5e 100644 --- a/tests/ui/write_literal.rs +++ b/tests/ui/write_literal.rs @@ -43,16 +43,22 @@ fn main() { // throw a warning writeln!(v, "{0} {1}", "hello", "world"); //~^ ERROR: literal with an empty format string - //~| ERROR: literal with an empty format string writeln!(v, "{1} {0}", "hello", "world"); //~^ ERROR: literal with an empty format string - //~| ERROR: literal with an empty format string // named args shouldn't change anything either writeln!(v, "{foo} {bar}", foo = "hello", bar = "world"); //~^ ERROR: literal with an empty format string - //~| ERROR: literal with an empty format string writeln!(v, "{bar} {foo}", foo = "hello", bar = "world"); //~^ ERROR: literal with an empty format string - //~| ERROR: literal with an empty format string + + // #10128 + writeln!(v, "{0} {1} {2}", "hello", 2, "world"); + //~^ ERROR: literal with an empty format string + writeln!(v, "{2} {1} {0}", "hello", 2, "world"); + //~^ ERROR: literal with an empty format string + writeln!(v, "{0} {1} {2}, {bar}", "hello", 2, 3, bar = 4); + //~^ ERROR: literal with an empty format string + writeln!(v, "{0} {1} {2}, {3} {4}", "hello", 2, 3, "world", 4); + //~^ ERROR: literal with an empty format string } diff --git a/tests/ui/write_literal.stderr b/tests/ui/write_literal.stderr index 372a54cf769fb..ee0d536e954f3 100644 --- a/tests/ui/write_literal.stderr +++ b/tests/ui/write_literal.stderr @@ -52,96 +52,96 @@ error: literal with an empty format string --> $DIR/write_literal.rs:44:28 | LL | writeln!(v, "{0} {1}", "hello", "world"); - | ^^^^^^^ + | ^^^^^^^^^^^^^^^^ | help: try | LL - writeln!(v, "{0} {1}", "hello", "world"); -LL + writeln!(v, "hello {1}", "world"); +LL + writeln!(v, "hello world"); | error: literal with an empty format string - --> $DIR/write_literal.rs:44:37 + --> $DIR/write_literal.rs:46:28 | -LL | writeln!(v, "{0} {1}", "hello", "world"); - | ^^^^^^^ +LL | writeln!(v, "{1} {0}", "hello", "world"); + | ^^^^^^^^^^^^^^^^ | help: try | -LL - writeln!(v, "{0} {1}", "hello", "world"); -LL + writeln!(v, "{0} world", "hello"); +LL - writeln!(v, "{1} {0}", "hello", "world"); +LL + writeln!(v, "world hello"); | error: literal with an empty format string - --> $DIR/write_literal.rs:47:37 + --> $DIR/write_literal.rs:50:38 | -LL | writeln!(v, "{1} {0}", "hello", "world"); - | ^^^^^^^ +LL | writeln!(v, "{foo} {bar}", foo = "hello", bar = "world"); + | ^^^^^^^^^^^^^^^^^^^^^^ | help: try | -LL - writeln!(v, "{1} {0}", "hello", "world"); -LL + writeln!(v, "world {0}", "hello"); +LL - writeln!(v, "{foo} {bar}", foo = "hello", bar = "world"); +LL + writeln!(v, "hello world"); | error: literal with an empty format string - --> $DIR/write_literal.rs:47:28 + --> $DIR/write_literal.rs:52:38 | -LL | writeln!(v, "{1} {0}", "hello", "world"); - | ^^^^^^^ +LL | writeln!(v, "{bar} {foo}", foo = "hello", bar = "world"); + | ^^^^^^^^^^^^^^^^^^^^^^ | help: try | -LL - writeln!(v, "{1} {0}", "hello", "world"); -LL + writeln!(v, "{1} hello", "world"); +LL - writeln!(v, "{bar} {foo}", foo = "hello", bar = "world"); +LL + writeln!(v, "world hello"); | error: literal with an empty format string - --> $DIR/write_literal.rs:52:38 + --> $DIR/write_literal.rs:56:32 | -LL | writeln!(v, "{foo} {bar}", foo = "hello", bar = "world"); - | ^^^^^^^ +LL | writeln!(v, "{0} {1} {2}", "hello", 2, "world"); + | ^^^^^^^^^^^^^^^^^^^ | help: try | -LL - writeln!(v, "{foo} {bar}", foo = "hello", bar = "world"); -LL + writeln!(v, "hello {bar}", bar = "world"); +LL - writeln!(v, "{0} {1} {2}", "hello", 2, "world"); +LL + writeln!(v, "hello {0} world", 2); | error: literal with an empty format string - --> $DIR/write_literal.rs:52:53 + --> $DIR/write_literal.rs:58:32 | -LL | writeln!(v, "{foo} {bar}", foo = "hello", bar = "world"); - | ^^^^^^^ +LL | writeln!(v, "{2} {1} {0}", "hello", 2, "world"); + | ^^^^^^^^^^^^^^^^^^^ | help: try | -LL - writeln!(v, "{foo} {bar}", foo = "hello", bar = "world"); -LL + writeln!(v, "{foo} world", foo = "hello"); +LL - writeln!(v, "{2} {1} {0}", "hello", 2, "world"); +LL + writeln!(v, "world {0} hello", 2); | error: literal with an empty format string - --> $DIR/write_literal.rs:55:53 + --> $DIR/write_literal.rs:60:39 | -LL | writeln!(v, "{bar} {foo}", foo = "hello", bar = "world"); - | ^^^^^^^ +LL | writeln!(v, "{0} {1} {2}, {bar}", "hello", 2, 3, bar = 4); + | ^^^^^^^ | help: try | -LL - writeln!(v, "{bar} {foo}", foo = "hello", bar = "world"); -LL + writeln!(v, "world {foo}", foo = "hello"); +LL - writeln!(v, "{0} {1} {2}, {bar}", "hello", 2, 3, bar = 4); +LL + writeln!(v, "hello {0} {1}, {bar}", 2, 3, bar = 4); | error: literal with an empty format string - --> $DIR/write_literal.rs:55:38 + --> $DIR/write_literal.rs:62:41 | -LL | writeln!(v, "{bar} {foo}", foo = "hello", bar = "world"); - | ^^^^^^^ +LL | writeln!(v, "{0} {1} {2}, {3} {4}", "hello", 2, 3, "world", 4); + | ^^^^^^^^^^^^^^^^^^^^^^ | help: try | -LL - writeln!(v, "{bar} {foo}", foo = "hello", bar = "world"); -LL + writeln!(v, "{bar} hello", bar = "world"); +LL - writeln!(v, "{0} {1} {2}, {3} {4}", "hello", 2, 3, "world", 4); +LL + writeln!(v, "hello {0} {1}, world {2}", 2, 3, 4); | error: aborting due to 12 previous errors diff --git a/tests/ui/write_literal_2.rs b/tests/ui/write_literal_2.rs index aa0c13c134080..b2ed552d46bcc 100644 --- a/tests/ui/write_literal_2.rs +++ b/tests/ui/write_literal_2.rs @@ -1,6 +1,6 @@ //@no-rustfix: overlapping suggestions #![allow(unused_must_use)] -#![warn(clippy::needless_raw_strings, clippy::write_literal)] +#![warn(clippy::write_literal)] use std::io::Write; @@ -11,9 +11,7 @@ fn main() { //~^ ERROR: literal with an empty format string //~| NOTE: `-D clippy::write-literal` implied by `-D warnings` writeln!(v, r"{}", r"{hello}"); - //~^ ERROR: unnecessary raw string literal - //~| NOTE: `-D clippy::needless-raw-strings` implied by `-D warnings` - //~| ERROR: literal with an empty format string + //~^ ERROR: literal with an empty format string writeln!(v, "{}", '\''); //~^ ERROR: literal with an empty format string writeln!(v, "{}", '"'); @@ -26,17 +24,14 @@ fn main() { v, "some {}", "hello \ - //~^ ERROR: literal with an empty format string - world!" + world!", + //~^^ ERROR: literal with an empty format string ); writeln!( v, "some {}\ {} \\ {}", - "1", - "2", - "3", - //~^ ERROR: literal with an empty format string + "1", "2", "3", ); writeln!(v, "{}", "\\"); //~^ ERROR: literal with an empty format string @@ -51,7 +46,6 @@ fn main() { // hard mode writeln!(v, r#"{}{}"#, '#', '"'); //~^ ERROR: literal with an empty format string - //~| ERROR: literal with an empty format string // should not lint writeln!(v, r"{}", "\r"); } diff --git a/tests/ui/write_literal_2.stderr b/tests/ui/write_literal_2.stderr index 6d382a267ad81..81ef49de082e7 100644 --- a/tests/ui/write_literal_2.stderr +++ b/tests/ui/write_literal_2.stderr @@ -1,14 +1,3 @@ -error: unnecessary raw string literal - --> $DIR/write_literal_2.rs:13:24 - | -LL | writeln!(v, r"{}", r"{hello}"); - | -^^^^^^^^^ - | | - | help: use a string literal instead: `"{hello}"` - | - = note: `-D clippy::needless-raw-strings` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::needless_raw_strings)]` - error: literal with an empty format string --> $DIR/write_literal_2.rs:10:23 | @@ -36,7 +25,7 @@ LL + writeln!(v, r"{{hello}}"); | error: literal with an empty format string - --> $DIR/write_literal_2.rs:17:23 + --> $DIR/write_literal_2.rs:15:23 | LL | writeln!(v, "{}", '\''); | ^^^^ @@ -48,7 +37,7 @@ LL + writeln!(v, "'"); | error: literal with an empty format string - --> $DIR/write_literal_2.rs:19:23 + --> $DIR/write_literal_2.rs:17:23 | LL | writeln!(v, "{}", '"'); | ^^^ @@ -60,13 +49,13 @@ LL + writeln!(v, "\""); | error: literal with an empty format string - --> $DIR/write_literal_2.rs:21:24 + --> $DIR/write_literal_2.rs:19:24 | LL | writeln!(v, r"{}", '"'); | ^^^ error: literal with an empty format string - --> $DIR/write_literal_2.rs:23:24 + --> $DIR/write_literal_2.rs:21:24 | LL | writeln!(v, r"{}", '\''); | ^^^^ @@ -78,59 +67,32 @@ LL + writeln!(v, r"'"); | error: literal with an empty format string - --> $DIR/write_literal_2.rs:28:9 + --> $DIR/write_literal_2.rs:26:9 | LL | / "hello \ -LL | | -LL | | world!" +LL | | world!", | |_______________^ | help: try | LL ~ "some hello \ -LL + -LL ~ world!" +LL ~ world!", | error: literal with an empty format string - --> $DIR/write_literal_2.rs:36:9 + --> $DIR/write_literal_2.rs:34:9 | -LL | "1", - | ^^^ +LL | "1", "2", "3", + | ^^^^^^^^^^^^^ | help: try | LL ~ "some 1\ -LL ~ {} \\ {}", +LL ~ 2 \\ 3", | error: literal with an empty format string - --> $DIR/write_literal_2.rs:37:9 - | -LL | "2", - | ^^^ - | -help: try - | -LL ~ 2 \\ {}", -LL ~ "1", - | - -error: literal with an empty format string - --> $DIR/write_literal_2.rs:38:9 - | -LL | "3", - | ^^^ - | -help: try - | -LL ~ {} \\ 3", -LL | "1", -LL ~ "2", - | - -error: literal with an empty format string - --> $DIR/write_literal_2.rs:41:23 + --> $DIR/write_literal_2.rs:36:23 | LL | writeln!(v, "{}", "\\"); | ^^^^ @@ -142,7 +104,7 @@ LL + writeln!(v, "\\"); | error: literal with an empty format string - --> $DIR/write_literal_2.rs:43:24 + --> $DIR/write_literal_2.rs:38:24 | LL | writeln!(v, r"{}", "\\"); | ^^^^ @@ -154,7 +116,7 @@ LL + writeln!(v, r"\"); | error: literal with an empty format string - --> $DIR/write_literal_2.rs:45:26 + --> $DIR/write_literal_2.rs:40:26 | LL | writeln!(v, r#"{}"#, "\\"); | ^^^^ @@ -166,7 +128,7 @@ LL + writeln!(v, r#"\"#); | error: literal with an empty format string - --> $DIR/write_literal_2.rs:47:23 + --> $DIR/write_literal_2.rs:42:23 | LL | writeln!(v, "{}", r"\"); | ^^^^ @@ -178,7 +140,7 @@ LL + writeln!(v, "\\"); | error: literal with an empty format string - --> $DIR/write_literal_2.rs:49:23 + --> $DIR/write_literal_2.rs:44:23 | LL | writeln!(v, "{}", "\r"); | ^^^^ @@ -190,16 +152,10 @@ LL + writeln!(v, "\r"); | error: literal with an empty format string - --> $DIR/write_literal_2.rs:52:28 - | -LL | writeln!(v, r#"{}{}"#, '#', '"'); - | ^^^ - -error: literal with an empty format string - --> $DIR/write_literal_2.rs:52:33 + --> $DIR/write_literal_2.rs:47:28 | LL | writeln!(v, r#"{}{}"#, '#', '"'); - | ^^^ + | ^^^^^^^^ -error: aborting due to 18 previous errors +error: aborting due to 14 previous errors From 70b8d15a854fb90d58a929f2b554f08a61c63b9a Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 6 Oct 2023 20:35:52 +0000 Subject: [PATCH 05/14] Extend impl's def_span to include where clauses --- tests/ui/crashes/ice-6252.stderr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ui/crashes/ice-6252.stderr b/tests/ui/crashes/ice-6252.stderr index cb65360d1291c..f929bec9583c5 100644 --- a/tests/ui/crashes/ice-6252.stderr +++ b/tests/ui/crashes/ice-6252.stderr @@ -31,7 +31,7 @@ LL | const VAL: T; | ------------ `VAL` from trait ... LL | impl TypeVal for Multiply where N: TypeVal {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `VAL` in implementation + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `VAL` in implementation error: aborting due to 3 previous errors From 359fa9822b4130a97197df0d9cf8a642013cd9a2 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 10 Oct 2023 14:02:42 +1100 Subject: [PATCH 06/14] Rejig some top-level `rustc_hir_pretty` functions. There are several that are unused and can be removed. And there are some calls to `to_string`, which can be expressed more nicely as a `foo_to_string` call, and then `to_string` need not be `pub`. (This requires adding `pat_to_string`). --- clippy_lints/src/matches/match_wild_err_arm.rs | 2 +- clippy_lints/src/mut_reference.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/matches/match_wild_err_arm.rs b/clippy_lints/src/matches/match_wild_err_arm.rs index de911f7a02803..a2903e52ae08d 100644 --- a/clippy_lints/src/matches/match_wild_err_arm.rs +++ b/clippy_lints/src/matches/match_wild_err_arm.rs @@ -19,7 +19,7 @@ pub(crate) fn check<'tcx>(cx: &LateContext<'tcx>, ex: &Expr<'tcx>, arms: &[Arm<' if is_type_diagnostic_item(cx, ex_ty, sym::Result) { for arm in arms { if let PatKind::TupleStruct(ref path, inner, _) = arm.pat.kind { - let path_str = rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_qpath(path, false)); + let path_str = rustc_hir_pretty::qpath_to_string(path); if path_str == "Err" { let mut matching_wild = inner.iter().any(is_wild); let mut ident_bind_name = kw::Underscore; diff --git a/clippy_lints/src/mut_reference.rs b/clippy_lints/src/mut_reference.rs index e53e146ec5dbe..01b850cdb1139 100644 --- a/clippy_lints/src/mut_reference.rs +++ b/clippy_lints/src/mut_reference.rs @@ -49,7 +49,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryMutPassed { cx, arguments.iter().collect(), cx.typeck_results().expr_ty(fn_expr), - &rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_qpath(path, false)), + &rustc_hir_pretty::qpath_to_string(path), "function", ); } From 1ffd09af2975b940fc83ad1dc6ee17ff36e564ba Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 13 Sep 2023 16:04:42 +0000 Subject: [PATCH 07/14] Stabilize AFIT and RPITIT --- tests/ui/implied_bounds_in_impls.fixed | 1 - tests/ui/implied_bounds_in_impls.rs | 1 - tests/ui/implied_bounds_in_impls.stderr | 32 ++++++++++++------------- tests/ui/unused_async.rs | 1 - tests/ui/unused_async.stderr | 10 ++++---- 5 files changed, 21 insertions(+), 24 deletions(-) diff --git a/tests/ui/implied_bounds_in_impls.fixed b/tests/ui/implied_bounds_in_impls.fixed index a50fa0ccf6e7f..fa117aaddcd60 100644 --- a/tests/ui/implied_bounds_in_impls.fixed +++ b/tests/ui/implied_bounds_in_impls.fixed @@ -1,6 +1,5 @@ #![warn(clippy::implied_bounds_in_impls)] #![allow(dead_code)] -#![feature(return_position_impl_trait_in_trait)] use std::ops::{Deref, DerefMut}; diff --git a/tests/ui/implied_bounds_in_impls.rs b/tests/ui/implied_bounds_in_impls.rs index e74ed4425b81e..c96aac151a7d0 100644 --- a/tests/ui/implied_bounds_in_impls.rs +++ b/tests/ui/implied_bounds_in_impls.rs @@ -1,6 +1,5 @@ #![warn(clippy::implied_bounds_in_impls)] #![allow(dead_code)] -#![feature(return_position_impl_trait_in_trait)] use std::ops::{Deref, DerefMut}; diff --git a/tests/ui/implied_bounds_in_impls.stderr b/tests/ui/implied_bounds_in_impls.stderr index 72dc2a183a383..fb44f2aba1744 100644 --- a/tests/ui/implied_bounds_in_impls.stderr +++ b/tests/ui/implied_bounds_in_impls.stderr @@ -1,5 +1,5 @@ error: this bound is already specified as the supertrait of `DerefMut` - --> $DIR/implied_bounds_in_impls.rs:13:36 + --> $DIR/implied_bounds_in_impls.rs:12:36 | LL | fn deref_derefmut(x: T) -> impl Deref + DerefMut { | ^^^^^^^^^^^^^^^^^ @@ -13,7 +13,7 @@ LL + fn deref_derefmut(x: T) -> impl DerefMut { | error: this bound is already specified as the supertrait of `GenericSubtrait` - --> $DIR/implied_bounds_in_impls.rs:30:37 + --> $DIR/implied_bounds_in_impls.rs:29:37 | LL | fn generics_implied() -> impl GenericTrait + GenericSubtrait | ^^^^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL + fn generics_implied() -> impl GenericSubtrait | error: this bound is already specified as the supertrait of `GenericSubtrait<(), i32, V>` - --> $DIR/implied_bounds_in_impls.rs:36:40 + --> $DIR/implied_bounds_in_impls.rs:35:40 | LL | fn generics_implied_multi() -> impl GenericTrait + GenericTrait2 + GenericSubtrait<(), i32, V> {} | ^^^^^^^^^^^^^^^^^ @@ -37,7 +37,7 @@ LL + fn generics_implied_multi() -> impl GenericTrait2 + GenericSubtrait<( | error: this bound is already specified as the supertrait of `GenericSubtrait<(), i32, V>` - --> $DIR/implied_bounds_in_impls.rs:36:60 + --> $DIR/implied_bounds_in_impls.rs:35:60 | LL | fn generics_implied_multi() -> impl GenericTrait + GenericTrait2 + GenericSubtrait<(), i32, V> {} | ^^^^^^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL + fn generics_implied_multi() -> impl GenericTrait + GenericSubtrait< | error: this bound is already specified as the supertrait of `GenericSubtrait<(), T, V>` - --> $DIR/implied_bounds_in_impls.rs:38:44 + --> $DIR/implied_bounds_in_impls.rs:37:44 | LL | fn generics_implied_multi2() -> impl GenericTrait + GenericTrait2 + GenericSubtrait<(), T, V> | ^^^^^^^^^^^^^^^ @@ -61,7 +61,7 @@ LL + fn generics_implied_multi2() -> impl GenericTrait2 + GenericSubtra | error: this bound is already specified as the supertrait of `GenericSubtrait<(), T, V>` - --> $DIR/implied_bounds_in_impls.rs:38:62 + --> $DIR/implied_bounds_in_impls.rs:37:62 | LL | fn generics_implied_multi2() -> impl GenericTrait + GenericTrait2 + GenericSubtrait<(), T, V> | ^^^^^^^^^^^^^^^^ @@ -73,7 +73,7 @@ LL + fn generics_implied_multi2() -> impl GenericTrait + GenericSubtrai | error: this bound is already specified as the supertrait of `GenericSubtrait<(), i32, ()>` - --> $DIR/implied_bounds_in_impls.rs:48:28 + --> $DIR/implied_bounds_in_impls.rs:47:28 | LL | fn generics_same() -> impl GenericTrait + GenericSubtrait<(), i32, ()> {} | ^^^^^^^^^^^^^^^^^ @@ -85,7 +85,7 @@ LL + fn generics_same() -> impl GenericSubtrait<(), i32, ()> {} | error: this bound is already specified as the supertrait of `DerefMut` - --> $DIR/implied_bounds_in_impls.rs:52:20 + --> $DIR/implied_bounds_in_impls.rs:51:20 | LL | fn f() -> impl Deref + DerefMut; | ^^^^^ @@ -97,7 +97,7 @@ LL + fn f() -> impl DerefMut; | error: this bound is already specified as the supertrait of `DerefMut` - --> $DIR/implied_bounds_in_impls.rs:57:20 + --> $DIR/implied_bounds_in_impls.rs:56:20 | LL | fn f() -> impl Deref + DerefMut { | ^^^^^ @@ -109,7 +109,7 @@ LL + fn f() -> impl DerefMut { | error: this bound is already specified as the supertrait of `DerefMut` - --> $DIR/implied_bounds_in_impls.rs:63:20 + --> $DIR/implied_bounds_in_impls.rs:62:20 | LL | fn f() -> impl Deref + DerefMut { | ^^^^^ @@ -121,7 +121,7 @@ LL + fn f() -> impl DerefMut { | error: this bound is already specified as the supertrait of `PartialOrd` - --> $DIR/implied_bounds_in_impls.rs:74:41 + --> $DIR/implied_bounds_in_impls.rs:73:41 | LL | fn default_generic_param1() -> impl PartialEq + PartialOrd + Debug {} | ^^^^^^^^^ @@ -133,7 +133,7 @@ LL + fn default_generic_param1() -> impl PartialOrd + Debug {} | error: this bound is already specified as the supertrait of `PartialOrd` - --> $DIR/implied_bounds_in_impls.rs:75:54 + --> $DIR/implied_bounds_in_impls.rs:74:54 | LL | fn default_generic_param2() -> impl PartialOrd + PartialEq + Debug {} | ^^^^^^^^^ @@ -145,7 +145,7 @@ LL + fn default_generic_param2() -> impl PartialOrd + Debug {} | error: this bound is already specified as the supertrait of `DoubleEndedIterator` - --> $DIR/implied_bounds_in_impls.rs:88:26 + --> $DIR/implied_bounds_in_impls.rs:87:26 | LL | fn my_iter() -> impl Iterator + DoubleEndedIterator { | ^^^^^^^^^^^^^^^^^^^^ @@ -157,7 +157,7 @@ LL + fn my_iter() -> impl DoubleEndedIterator { | error: this bound is already specified as the supertrait of `Copy` - --> $DIR/implied_bounds_in_impls.rs:93:27 + --> $DIR/implied_bounds_in_impls.rs:92:27 | LL | fn f() -> impl Copy + Clone { | ^^^^^ @@ -169,7 +169,7 @@ LL + fn f() -> impl Copy { | error: this bound is already specified as the supertrait of `Trait2` - --> $DIR/implied_bounds_in_impls.rs:107:21 + --> $DIR/implied_bounds_in_impls.rs:106:21 | LL | fn f2() -> impl Trait1 + Trait2 {} | ^^^^^^^^^^^^^^^^^^^^ @@ -181,7 +181,7 @@ LL + fn f2() -> impl Trait2 {} | error: this bound is already specified as the supertrait of `Trait4` - --> $DIR/implied_bounds_in_impls.rs:122:21 + --> $DIR/implied_bounds_in_impls.rs:121:21 | LL | fn f3() -> impl Trait3 + Trait4 {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/unused_async.rs b/tests/ui/unused_async.rs index 71722e9afd0b8..7ec8a3adb4cd5 100644 --- a/tests/ui/unused_async.rs +++ b/tests/ui/unused_async.rs @@ -1,5 +1,4 @@ #![warn(clippy::unused_async)] -#![feature(async_fn_in_trait)] #![allow(incomplete_features)] use std::future::Future; diff --git a/tests/ui/unused_async.stderr b/tests/ui/unused_async.stderr index 077e8cacce146..c97a76a55cbe1 100644 --- a/tests/ui/unused_async.stderr +++ b/tests/ui/unused_async.stderr @@ -1,5 +1,5 @@ error: unused `async` for function with no await statements - --> $DIR/unused_async.rs:13:5 + --> $DIR/unused_async.rs:12:5 | LL | / async fn async_block_await() { LL | | @@ -11,7 +11,7 @@ LL | | } | = help: consider removing the `async` from this function note: `await` used in an async block, which does not require the enclosing function to be `async` - --> $DIR/unused_async.rs:16:23 + --> $DIR/unused_async.rs:15:23 | LL | ready(()).await; | ^^^^^ @@ -19,7 +19,7 @@ LL | ready(()).await; = help: to override `-D warnings` add `#[allow(clippy::unused_async)]` error: unused `async` for function with no await statements - --> $DIR/unused_async.rs:46:5 + --> $DIR/unused_async.rs:45:5 | LL | async fn f3() {} | ^^^^^^^^^^^^^^^^ @@ -27,7 +27,7 @@ LL | async fn f3() {} = help: consider removing the `async` from this function error: unused `async` for function with no await statements - --> $DIR/unused_async.rs:59:1 + --> $DIR/unused_async.rs:58:1 | LL | / async fn foo() -> i32 { LL | | @@ -38,7 +38,7 @@ LL | | } = help: consider removing the `async` from this function error: unused `async` for function with no await statements - --> $DIR/unused_async.rs:71:5 + --> $DIR/unused_async.rs:70:5 | LL | / async fn unused(&self) -> i32 { LL | | From 9ee26d078db28d39f34ab2979a393be4b43019c8 Mon Sep 17 00:00:00 2001 From: Arthur Lafrance Date: Mon, 16 Oct 2023 13:52:50 -0700 Subject: [PATCH 08/14] fix lint failures in clippy --- clippy_lints/src/dereference.rs | 2 +- clippy_lints/src/entry.rs | 2 +- clippy_lints/src/formatting.rs | 2 +- clippy_lints/src/let_with_type_underscore.rs | 2 +- clippy_lints/src/manual_let_else.rs | 2 +- clippy_lints/src/matches/collapsible_match.rs | 2 +- clippy_lints/src/matches/manual_utils.rs | 4 ++-- clippy_lints/src/methods/map_unwrap_or.rs | 2 +- clippy_lints/src/needless_question_mark.rs | 2 +- clippy_lints/src/non_octal_unix_permissions.rs | 4 ++-- clippy_lints/src/redundant_async_block.rs | 2 +- clippy_lints/src/reference.rs | 2 +- clippy_lints/src/suspicious_xor_used_as_pow.rs | 2 +- clippy_utils/src/macros.rs | 2 +- 14 files changed, 16 insertions(+), 16 deletions(-) diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index 14877385646a0..5134cf66050c9 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -701,7 +701,7 @@ fn deref_method_same_type<'tcx>(result_ty: Ty<'tcx>, arg_ty: Ty<'tcx>) -> bool { fn in_postfix_position<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) -> bool { if let Some(parent) = get_parent_expr(cx, e) - && parent.span.ctxt() == e.span.ctxt() + && parent.span.eq_ctxt(e.span) { match parent.kind { ExprKind::Call(child, _) | ExprKind::MethodCall(_, child, _, _) | ExprKind::Index(child, _, _) diff --git a/clippy_lints/src/entry.rs b/clippy_lints/src/entry.rs index 6197b5b19eb4c..70a467dde6136 100644 --- a/clippy_lints/src/entry.rs +++ b/clippy_lints/src/entry.rs @@ -241,7 +241,7 @@ fn try_parse_contains<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Optio }, ], _, - ) if key_span.ctxt() == expr.span.ctxt() => { + ) if key_span.eq_ctxt(expr.span) => { let id = cx.typeck_results().type_dependent_def_id(expr.hir_id)?; let expr = ContainsExpr { negated, diff --git a/clippy_lints/src/formatting.rs b/clippy_lints/src/formatting.rs index d03480c21084c..4ebf0e9667dfe 100644 --- a/clippy_lints/src/formatting.rs +++ b/clippy_lints/src/formatting.rs @@ -274,7 +274,7 @@ fn check_array(cx: &EarlyContext<'_>, expr: &Expr) { for element in array { if_chain! { if let ExprKind::Binary(ref op, ref lhs, _) = element.kind; - if has_unary_equivalent(op.node) && lhs.span.ctxt() == op.span.ctxt(); + if has_unary_equivalent(op.node) && lhs.span.eq_ctxt(op.span); let space_span = lhs.span.between(op.span); if let Some(space_snippet) = snippet_opt(cx, space_span); let lint_span = lhs.span.with_lo(lhs.span.hi()); diff --git a/clippy_lints/src/let_with_type_underscore.rs b/clippy_lints/src/let_with_type_underscore.rs index 4e9d77ea156af..79d728a021c3c 100644 --- a/clippy_lints/src/let_with_type_underscore.rs +++ b/clippy_lints/src/let_with_type_underscore.rs @@ -31,7 +31,7 @@ impl LateLintPass<'_> for UnderscoreTyped { if !in_external_macro(cx.tcx.sess, local.span); if let Some(ty) = local.ty; // Ensure that it has a type defined if let TyKind::Infer = &ty.kind; // that type is '_' - if local.span.ctxt() == ty.span.ctxt(); + if local.span.eq_ctxt(ty.span); then { // NOTE: Using `is_from_proc_macro` on `init` will require that it's initialized, // this doesn't. Alternatively, `WithSearchPat` can be implemented for `Ty` diff --git a/clippy_lints/src/manual_let_else.rs b/clippy_lints/src/manual_let_else.rs index 2117308cd4009..86bbdb4ea1993 100644 --- a/clippy_lints/src/manual_let_else.rs +++ b/clippy_lints/src/manual_let_else.rs @@ -59,7 +59,7 @@ impl<'tcx> QuestionMark { let Some(init) = local.init && local.els.is_none() && local.ty.is_none() && - init.span.ctxt() == stmt.span.ctxt() && + init.span.eq_ctxt(stmt.span) && let Some(if_let_or_match) = IfLetOrMatch::parse(cx, init) { match if_let_or_match { diff --git a/clippy_lints/src/matches/collapsible_match.rs b/clippy_lints/src/matches/collapsible_match.rs index 33a052c41a38a..29b935fb61a8a 100644 --- a/clippy_lints/src/matches/collapsible_match.rs +++ b/clippy_lints/src/matches/collapsible_match.rs @@ -57,7 +57,7 @@ fn check_arm<'tcx>( } }, }; - if outer_pat.span.ctxt() == inner_scrutinee.span.ctxt(); + if outer_pat.span.eq_ctxt(inner_scrutinee.span); // match expression must be a local binding // match { .. } if let Some(binding_id) = path_to_local(peel_ref_operators(cx, inner_scrutinee)); diff --git a/clippy_lints/src/matches/manual_utils.rs b/clippy_lints/src/matches/manual_utils.rs index 6b611f567ae28..781ee138c76f7 100644 --- a/clippy_lints/src/matches/manual_utils.rs +++ b/clippy_lints/src/matches/manual_utils.rs @@ -119,7 +119,7 @@ where // it's being passed by value. let scrutinee = peel_hir_expr_refs(scrutinee).0; let (scrutinee_str, _) = snippet_with_context(cx, scrutinee.span, expr_ctxt, "..", &mut app); - let scrutinee_str = if scrutinee.span.ctxt() == expr.span.ctxt() && scrutinee.precedence().order() < PREC_POSTFIX { + let scrutinee_str = if scrutinee.span.eq_ctxt(expr.span) && scrutinee.precedence().order() < PREC_POSTFIX { format!("({scrutinee_str})") } else { scrutinee_str.into() @@ -130,7 +130,7 @@ where if_chain! { if !some_expr.needs_unsafe_block; if let Some(func) = can_pass_as_func(cx, id, some_expr.expr); - if func.span.ctxt() == some_expr.expr.span.ctxt(); + if func.span.eq_ctxt(some_expr.expr.span); then { snippet_with_applicability(cx, func.span, "..", &mut app).into_owned() } else { diff --git a/clippy_lints/src/methods/map_unwrap_or.rs b/clippy_lints/src/methods/map_unwrap_or.rs index 5464e455dea40..e70a1bc98799c 100644 --- a/clippy_lints/src/methods/map_unwrap_or.rs +++ b/clippy_lints/src/methods/map_unwrap_or.rs @@ -56,7 +56,7 @@ pub(super) fn check<'tcx>( // lint, with note if neither arg is > 1 line and both map() and // unwrap_or_else() have the same span let multiline = map_snippet.lines().count() > 1 || unwrap_snippet.lines().count() > 1; - let same_span = map_arg.span.ctxt() == unwrap_arg.span.ctxt(); + let same_span = map_arg.span.eq_ctxt(unwrap_arg.span); if same_span && !multiline { let var_snippet = snippet(cx, recv.span, ".."); span_lint_and_sugg( diff --git a/clippy_lints/src/needless_question_mark.rs b/clippy_lints/src/needless_question_mark.rs index 7b0f7eaf1f063..0e834fb3ac768 100644 --- a/clippy_lints/src/needless_question_mark.rs +++ b/clippy_lints/src/needless_question_mark.rs @@ -125,7 +125,7 @@ fn check(cx: &LateContext<'_>, expr: &Expr<'_>) { if let ExprKind::Match(inner_expr_with_q, _, MatchSource::TryDesugar(_)) = &arg.kind; if let ExprKind::Call(called, [inner_expr]) = &inner_expr_with_q.kind; if let ExprKind::Path(QPath::LangItem(LangItem::TryTraitBranch, ..)) = &called.kind; - if expr.span.ctxt() == inner_expr.span.ctxt(); + if expr.span.eq_ctxt(inner_expr.span); let expr_ty = cx.typeck_results().expr_ty(expr); let inner_ty = cx.typeck_results().expr_ty(inner_expr); if expr_ty == inner_ty; diff --git a/clippy_lints/src/non_octal_unix_permissions.rs b/clippy_lints/src/non_octal_unix_permissions.rs index d47728f190ab9..e94e458996601 100644 --- a/clippy_lints/src/non_octal_unix_permissions.rs +++ b/clippy_lints/src/non_octal_unix_permissions.rs @@ -51,7 +51,7 @@ impl<'tcx> LateLintPass<'tcx> for NonOctalUnixPermissions { || (path.ident.name == sym!(set_mode) && cx.tcx.is_diagnostic_item(sym::FsPermissions, adt.did())); if let ExprKind::Lit(_) = param.kind; - if param.span.ctxt() == expr.span.ctxt(); + if param.span.eq_ctxt(expr.span); then { let Some(snip) = snippet_opt(cx, param.span) else { @@ -70,7 +70,7 @@ impl<'tcx> LateLintPass<'tcx> for NonOctalUnixPermissions { if let Some(def_id) = cx.qpath_res(path, func.hir_id).opt_def_id(); if match_def_path(cx, def_id, &paths::PERMISSIONS_FROM_MODE); if let ExprKind::Lit(_) = param.kind; - if param.span.ctxt() == expr.span.ctxt(); + if param.span.eq_ctxt(expr.span); if let Some(snip) = snippet_opt(cx, param.span); if !snip.starts_with("0o"); then { diff --git a/clippy_lints/src/redundant_async_block.rs b/clippy_lints/src/redundant_async_block.rs index 534b2762ba769..8193057a6eb27 100644 --- a/clippy_lints/src/redundant_async_block.rs +++ b/clippy_lints/src/redundant_async_block.rs @@ -48,7 +48,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantAsyncBlock { let Some(body_expr) = desugar_async_block(cx, expr) && let Some(expr) = desugar_await(peel_blocks(body_expr)) && // The await prefix must not come from a macro as its content could change in the future. - expr.span.ctxt() == body_expr.span.ctxt() && + expr.span.eq_ctxt(body_expr.span) && // An async block does not have immediate side-effects from a `.await` point-of-view. (!expr.can_have_side_effects() || desugar_async_block(cx, expr).is_some()) && let Some(shortened_span) = walk_span_to_context(expr.span, span.ctxt()) diff --git a/clippy_lints/src/reference.rs b/clippy_lints/src/reference.rs index db870ec4c5b6d..12da29f11089c 100644 --- a/clippy_lints/src/reference.rs +++ b/clippy_lints/src/reference.rs @@ -50,7 +50,7 @@ impl EarlyLintPass for DerefAddrOf { if_chain! { if let ExprKind::Unary(UnOp::Deref, ref deref_target) = e.kind; if let ExprKind::AddrOf(_, ref mutability, ref addrof_target) = without_parens(deref_target).kind; - if deref_target.span.ctxt() == e.span.ctxt(); + if deref_target.span.eq_ctxt(e.span); if !addrof_target.span.from_expansion(); then { let mut applicability = Applicability::MachineApplicable; diff --git a/clippy_lints/src/suspicious_xor_used_as_pow.rs b/clippy_lints/src/suspicious_xor_used_as_pow.rs index 8e156b8829b9c..39cd289b67ad3 100644 --- a/clippy_lints/src/suspicious_xor_used_as_pow.rs +++ b/clippy_lints/src/suspicious_xor_used_as_pow.rs @@ -33,7 +33,7 @@ impl LateLintPass<'_> for ConfusingXorAndPow { if !in_external_macro(cx.sess(), expr.span) && let ExprKind::Binary(op, left, right) = &expr.kind && op.node == BinOpKind::BitXor - && left.span.ctxt() == right.span.ctxt() + && left.span.eq_ctxt(right.span) && let ExprKind::Lit(lit_left) = &left.kind && let ExprKind::Lit(lit_right) = &right.kind && matches!(lit_right.node, LitKind::Int(..) | LitKind::Float(..)) diff --git a/clippy_utils/src/macros.rs b/clippy_utils/src/macros.rs index eaf590f6ad77d..46ce4ffdce5d4 100644 --- a/clippy_utils/src/macros.rs +++ b/clippy_utils/src/macros.rs @@ -245,7 +245,7 @@ impl<'a> PanicExpn<'a> { return None; }; let result = match name { - "panic" if arg.span.ctxt() == expr.span.ctxt() => Self::Empty, + "panic" if arg.span.eq_ctxt(expr.span) => Self::Empty, "panic" | "panic_str" => Self::Str(arg), "panic_display" | "panic_cold_display" => { let ExprKind::AddrOf(_, _, e) = &arg.kind else { From 09535a5d303cd9a57719bf2128078edf82507d75 Mon Sep 17 00:00:00 2001 From: Urgau Date: Wed, 23 Aug 2023 17:58:21 +0200 Subject: [PATCH 09/14] [RFC 3127 - Trim Paths]: Fix building tools (rustdoc, clippy, ...) --- clippy_lints/src/utils/internal_lints/metadata_collector.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/utils/internal_lints/metadata_collector.rs b/clippy_lints/src/utils/internal_lints/metadata_collector.rs index c38a3e81b0f72..c8600badf18e8 100644 --- a/clippy_lints/src/utils/internal_lints/metadata_collector.rs +++ b/clippy_lints/src/utils/internal_lints/metadata_collector.rs @@ -494,7 +494,7 @@ impl SerializableSpan { let loc: Loc = cx.sess().source_map().lookup_char_pos(span.lo()); Self { - path: format!("{}", loc.file.name.prefer_remapped()), + path: format!("{}", loc.file.name.prefer_remapped_unconditionaly()), line: loc.line, } } From d9dc5ee072d102c6a75cdcedebc25b3babf37965 Mon Sep 17 00:00:00 2001 From: lcnr Date: Wed, 18 Oct 2023 13:57:19 +0200 Subject: [PATCH 10/14] AliasTy::new instead of tcx method --- clippy_utils/src/ty.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index 2d305a63eca12..673b259523e18 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -1133,7 +1133,7 @@ pub fn make_projection<'tcx>( #[cfg(debug_assertions)] assert_generic_args_match(tcx, assoc_item.def_id, args); - Some(tcx.mk_alias_ty(assoc_item.def_id, args)) + Some(ty::AliasTy::new(tcx, assoc_item.def_id, args)) } helper( tcx, From a07c032e96bdf12747cb0431fe2bfbd9db3fb0f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 18 Oct 2023 22:10:48 +0000 Subject: [PATCH 11/14] Tweak wording of type errors involving type params Fix #78206. --- tests/ui/builtin_type_shadow.stderr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ui/builtin_type_shadow.stderr b/tests/ui/builtin_type_shadow.stderr index cb8462182b895..e051c00eb8d2c 100644 --- a/tests/ui/builtin_type_shadow.stderr +++ b/tests/ui/builtin_type_shadow.stderr @@ -13,7 +13,7 @@ error[E0308]: mismatched types LL | fn foo(a: u32) -> u32 { | --- --- expected `u32` because of return type | | - | this type parameter + | expected this type parameter LL | 42 | ^^ expected type parameter `u32`, found integer | From 868e513935876bb9de4ce7e10d9d77ca5612b4a1 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 19 Oct 2023 16:06:43 +0000 Subject: [PATCH 12/14] s/Generator/Coroutine/ --- clippy_lints/src/async_yields_async.rs | 6 +++--- clippy_lints/src/await_holding_invalid.rs | 10 +++++----- clippy_lints/src/dereference.rs | 4 ++-- clippy_lints/src/doc.rs | 2 +- clippy_lints/src/large_futures.rs | 2 +- clippy_lints/src/manual_async_fn.rs | 4 ++-- clippy_lints/src/needless_question_mark.rs | 4 ++-- clippy_lints/src/redundant_async_block.rs | 4 ++-- clippy_lints/src/unused_async.rs | 2 +- clippy_utils/src/qualify_min_const_fn.rs | 2 +- 10 files changed, 20 insertions(+), 20 deletions(-) diff --git a/clippy_lints/src/async_yields_async.rs b/clippy_lints/src/async_yields_async.rs index 9464694a3b55a..99daec560e759 100644 --- a/clippy_lints/src/async_yields_async.rs +++ b/clippy_lints/src/async_yields_async.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::source::snippet; use clippy_utils::ty::implements_trait; use rustc_errors::Applicability; -use rustc_hir::{AsyncGeneratorKind, Body, BodyId, ExprKind, GeneratorKind, QPath}; +use rustc_hir::{AsyncCoroutineKind, Body, BodyId, ExprKind, CoroutineKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -45,10 +45,10 @@ declare_lint_pass!(AsyncYieldsAsync => [ASYNC_YIELDS_ASYNC]); impl<'tcx> LateLintPass<'tcx> for AsyncYieldsAsync { fn check_body(&mut self, cx: &LateContext<'tcx>, body: &'tcx Body<'_>) { - use AsyncGeneratorKind::{Block, Closure}; + use AsyncCoroutineKind::{Block, Closure}; // For functions, with explicitly defined types, don't warn. // XXXkhuey maybe we should? - if let Some(GeneratorKind::Async(Block | Closure)) = body.generator_kind { + if let Some(CoroutineKind::Async(Block | Closure)) = body.generator_kind { if let Some(future_trait_def_id) = cx.tcx.lang_items().future_trait() { let body_id = BodyId { hir_id: body.value.hir_id, diff --git a/clippy_lints/src/await_holding_invalid.rs b/clippy_lints/src/await_holding_invalid.rs index accff9b0a34c6..65d131c5751a0 100644 --- a/clippy_lints/src/await_holding_invalid.rs +++ b/clippy_lints/src/await_holding_invalid.rs @@ -2,9 +2,9 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::{match_def_path, paths}; use rustc_data_structures::fx::FxHashMap; use rustc_hir::def_id::DefId; -use rustc_hir::{AsyncGeneratorKind, Body, GeneratorKind}; +use rustc_hir::{AsyncCoroutineKind, Body, CoroutineKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::mir::GeneratorLayout; +use rustc_middle::mir::CoroutineLayout; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::{sym, Span}; @@ -195,8 +195,8 @@ impl LateLintPass<'_> for AwaitHolding { } fn check_body(&mut self, cx: &LateContext<'_>, body: &'_ Body<'_>) { - use AsyncGeneratorKind::{Block, Closure, Fn}; - if let Some(GeneratorKind::Async(Block | Closure | Fn)) = body.generator_kind { + use AsyncCoroutineKind::{Block, Closure, Fn}; + if let Some(CoroutineKind::Async(Block | Closure | Fn)) = body.generator_kind { let def_id = cx.tcx.hir().body_owner_def_id(body.id()); if let Some(generator_layout) = cx.tcx.mir_generator_witnesses(def_id) { self.check_interior_types(cx, generator_layout); @@ -206,7 +206,7 @@ impl LateLintPass<'_> for AwaitHolding { } impl AwaitHolding { - fn check_interior_types(&self, cx: &LateContext<'_>, generator: &GeneratorLayout<'_>) { + fn check_interior_types(&self, cx: &LateContext<'_>, generator: &CoroutineLayout<'_>) { for (ty_index, ty_cause) in generator.field_tys.iter_enumerated() { if let rustc_middle::ty::Adt(adt, _) = ty_cause.ty.kind() { let await_points = || { diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index 5134cf66050c9..efe82036dc802 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -842,8 +842,8 @@ impl TyCoercionStability { | ty::Adt(..) | ty::Foreign(_) | ty::FnDef(..) - | ty::Generator(..) - | ty::GeneratorWitness(..) + | ty::Coroutine(..) + | ty::CoroutineWitness(..) | ty::Closure(..) | ty::Never | ty::Tuple(_) diff --git a/clippy_lints/src/doc.rs b/clippy_lints/src/doc.rs index e789e0da6797a..ca9defc2bf35a 100644 --- a/clippy_lints/src/doc.rs +++ b/clippy_lints/src/doc.rs @@ -436,7 +436,7 @@ fn lint_for_missing_headers( let body = cx.tcx.hir().body(body_id); let ret_ty = typeck.expr_ty(body.value); if implements_trait(cx, ret_ty, future, &[]); - if let ty::Generator(_, subs, _) = ret_ty.kind(); + if let ty::Coroutine(_, subs, _) = ret_ty.kind(); if is_type_diagnostic_item(cx, subs.as_generator().return_ty(), sym::Result); then { span_lint( diff --git a/clippy_lints/src/large_futures.rs b/clippy_lints/src/large_futures.rs index 19f1e08b57ad1..90096f0f506d7 100644 --- a/clippy_lints/src/large_futures.rs +++ b/clippy_lints/src/large_futures.rs @@ -12,7 +12,7 @@ declare_clippy_lint! { /// It checks for the size of a `Future` created by `async fn` or `async {}`. /// /// ### Why is this bad? - /// Due to the current [unideal implementation](https://github.com/rust-lang/rust/issues/69826) of `Generator`, + /// Due to the current [unideal implementation](https://github.com/rust-lang/rust/issues/69826) of `Coroutine`, /// large size of a `Future` may cause stack overflows. /// /// ### Example diff --git a/clippy_lints/src/manual_async_fn.rs b/clippy_lints/src/manual_async_fn.rs index 577bc1d661dbd..4997633475172 100644 --- a/clippy_lints/src/manual_async_fn.rs +++ b/clippy_lints/src/manual_async_fn.rs @@ -4,7 +4,7 @@ use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; use rustc_hir::{ - AsyncGeneratorKind, Block, Body, Closure, Expr, ExprKind, FnDecl, FnRetTy, GeneratorKind, GenericArg, GenericBound, + AsyncCoroutineKind, Block, Body, Closure, Expr, ExprKind, FnDecl, FnRetTy, CoroutineKind, GenericArg, GenericBound, ImplItem, Item, ItemKind, LifetimeName, Node, Term, TraitRef, Ty, TyKind, TypeBindingKind, }; use rustc_lint::{LateContext, LateLintPass}; @@ -188,7 +188,7 @@ fn desugared_async_block<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) .. } = block_expr; let closure_body = cx.tcx.hir().body(body); - if closure_body.generator_kind == Some(GeneratorKind::Async(AsyncGeneratorKind::Block)); + if closure_body.generator_kind == Some(CoroutineKind::Async(AsyncCoroutineKind::Block)); then { return Some(closure_body); } diff --git a/clippy_lints/src/needless_question_mark.rs b/clippy_lints/src/needless_question_mark.rs index 0e834fb3ac768..f2c823323bbb3 100644 --- a/clippy_lints/src/needless_question_mark.rs +++ b/clippy_lints/src/needless_question_mark.rs @@ -4,7 +4,7 @@ use clippy_utils::source::snippet; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::{AsyncGeneratorKind, Block, Body, Expr, ExprKind, GeneratorKind, LangItem, MatchSource, QPath}; +use rustc_hir::{AsyncCoroutineKind, Block, Body, Expr, ExprKind, CoroutineKind, LangItem, MatchSource, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -87,7 +87,7 @@ impl LateLintPass<'_> for NeedlessQuestionMark { } fn check_body(&mut self, cx: &LateContext<'_>, body: &'_ Body<'_>) { - if let Some(GeneratorKind::Async(AsyncGeneratorKind::Fn)) = body.generator_kind { + if let Some(CoroutineKind::Async(AsyncCoroutineKind::Fn)) = body.generator_kind { if let ExprKind::Block( Block { expr: diff --git a/clippy_lints/src/redundant_async_block.rs b/clippy_lints/src/redundant_async_block.rs index 8193057a6eb27..59aecd2327836 100644 --- a/clippy_lints/src/redundant_async_block.rs +++ b/clippy_lints/src/redundant_async_block.rs @@ -5,7 +5,7 @@ use clippy_utils::peel_blocks; use clippy_utils::source::{snippet, walk_span_to_context}; use clippy_utils::visitors::for_each_expr; use rustc_errors::Applicability; -use rustc_hir::{AsyncGeneratorKind, Closure, Expr, ExprKind, GeneratorKind, MatchSource}; +use rustc_hir::{AsyncCoroutineKind, Closure, Expr, ExprKind, CoroutineKind, MatchSource}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::UpvarCapture; @@ -71,7 +71,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantAsyncBlock { fn desugar_async_block<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> { if let ExprKind::Closure(Closure { body, def_id, .. }) = expr.kind && let body = cx.tcx.hir().body(*body) && - matches!(body.generator_kind, Some(GeneratorKind::Async(AsyncGeneratorKind::Block))) + matches!(body.generator_kind, Some(CoroutineKind::Async(AsyncCoroutineKind::Block))) { cx .typeck_results() diff --git a/clippy_lints/src/unused_async.rs b/clippy_lints/src/unused_async.rs index bc7c3897a6e8d..5e1ba1b0dc062 100644 --- a/clippy_lints/src/unused_async.rs +++ b/clippy_lints/src/unused_async.rs @@ -86,7 +86,7 @@ impl<'a, 'tcx> Visitor<'tcx> for AsyncFnVisitor<'a, 'tcx> { } fn visit_body(&mut self, b: &'tcx Body<'tcx>) { - let is_async_block = matches!(b.generator_kind, Some(rustc_hir::GeneratorKind::Async(_))); + let is_async_block = matches!(b.generator_kind, Some(rustc_hir::CoroutineKind::Async(_))); if is_async_block { self.async_depth += 1; diff --git a/clippy_utils/src/qualify_min_const_fn.rs b/clippy_utils/src/qualify_min_const_fn.rs index 55f9cb27ad4db..0d8fd9d2adf10 100644 --- a/clippy_utils/src/qualify_min_const_fn.rs +++ b/clippy_utils/src/qualify_min_const_fn.rs @@ -305,7 +305,7 @@ fn check_terminator<'tcx>( Ok(()) }, TerminatorKind::SwitchInt { discr, targets: _ } => check_operand(tcx, discr, span, body), - TerminatorKind::GeneratorDrop | TerminatorKind::Yield { .. } => { + TerminatorKind::CoroutineDrop | TerminatorKind::Yield { .. } => { Err((span, "const fn generators are unstable".into())) }, TerminatorKind::Call { From d9259fdedd96d03a9226e899a853c97d391eb94d Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 19 Oct 2023 21:46:28 +0000 Subject: [PATCH 13/14] s/generator/coroutine/ --- clippy_lints/src/async_yields_async.rs | 2 +- clippy_lints/src/await_holding_invalid.rs | 14 +++++++------- clippy_lints/src/doc.rs | 2 +- clippy_lints/src/manual_async_fn.rs | 2 +- clippy_lints/src/methods/iter_kv_map.rs | 2 +- clippy_lints/src/needless_question_mark.rs | 2 +- clippy_lints/src/redundant_async_block.rs | 2 +- clippy_lints/src/redundant_closure_call.rs | 4 ++-- clippy_lints/src/unused_async.rs | 2 +- clippy_utils/src/qualify_min_const_fn.rs | 2 +- tests/ui/crashes/ice-5238.rs | 2 +- tests/ui/large_futures.fixed | 2 +- tests/ui/large_futures.rs | 2 +- 13 files changed, 20 insertions(+), 20 deletions(-) diff --git a/clippy_lints/src/async_yields_async.rs b/clippy_lints/src/async_yields_async.rs index 99daec560e759..96a90d599abaa 100644 --- a/clippy_lints/src/async_yields_async.rs +++ b/clippy_lints/src/async_yields_async.rs @@ -48,7 +48,7 @@ impl<'tcx> LateLintPass<'tcx> for AsyncYieldsAsync { use AsyncCoroutineKind::{Block, Closure}; // For functions, with explicitly defined types, don't warn. // XXXkhuey maybe we should? - if let Some(CoroutineKind::Async(Block | Closure)) = body.generator_kind { + if let Some(CoroutineKind::Async(Block | Closure)) = body.coroutine_kind { if let Some(future_trait_def_id) = cx.tcx.lang_items().future_trait() { let body_id = BodyId { hir_id: body.value.hir_id, diff --git a/clippy_lints/src/await_holding_invalid.rs b/clippy_lints/src/await_holding_invalid.rs index 65d131c5751a0..60f9bbd7458b3 100644 --- a/clippy_lints/src/await_holding_invalid.rs +++ b/clippy_lints/src/await_holding_invalid.rs @@ -196,25 +196,25 @@ impl LateLintPass<'_> for AwaitHolding { fn check_body(&mut self, cx: &LateContext<'_>, body: &'_ Body<'_>) { use AsyncCoroutineKind::{Block, Closure, Fn}; - if let Some(CoroutineKind::Async(Block | Closure | Fn)) = body.generator_kind { + if let Some(CoroutineKind::Async(Block | Closure | Fn)) = body.coroutine_kind { let def_id = cx.tcx.hir().body_owner_def_id(body.id()); - if let Some(generator_layout) = cx.tcx.mir_generator_witnesses(def_id) { - self.check_interior_types(cx, generator_layout); + if let Some(coroutine_layout) = cx.tcx.mir_coroutine_witnesses(def_id) { + self.check_interior_types(cx, coroutine_layout); } } } } impl AwaitHolding { - fn check_interior_types(&self, cx: &LateContext<'_>, generator: &CoroutineLayout<'_>) { - for (ty_index, ty_cause) in generator.field_tys.iter_enumerated() { + fn check_interior_types(&self, cx: &LateContext<'_>, coroutine: &CoroutineLayout<'_>) { + for (ty_index, ty_cause) in coroutine.field_tys.iter_enumerated() { if let rustc_middle::ty::Adt(adt, _) = ty_cause.ty.kind() { let await_points = || { - generator + coroutine .variant_source_info .iter_enumerated() .filter_map(|(variant, source_info)| { - generator.variant_fields[variant] + coroutine.variant_fields[variant] .raw .contains(&ty_index) .then_some(source_info.span) diff --git a/clippy_lints/src/doc.rs b/clippy_lints/src/doc.rs index ca9defc2bf35a..fc9b381664a30 100644 --- a/clippy_lints/src/doc.rs +++ b/clippy_lints/src/doc.rs @@ -437,7 +437,7 @@ fn lint_for_missing_headers( let ret_ty = typeck.expr_ty(body.value); if implements_trait(cx, ret_ty, future, &[]); if let ty::Coroutine(_, subs, _) = ret_ty.kind(); - if is_type_diagnostic_item(cx, subs.as_generator().return_ty(), sym::Result); + if is_type_diagnostic_item(cx, subs.as_coroutine().return_ty(), sym::Result); then { span_lint( cx, diff --git a/clippy_lints/src/manual_async_fn.rs b/clippy_lints/src/manual_async_fn.rs index 4997633475172..914ceca2995d4 100644 --- a/clippy_lints/src/manual_async_fn.rs +++ b/clippy_lints/src/manual_async_fn.rs @@ -188,7 +188,7 @@ fn desugared_async_block<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) .. } = block_expr; let closure_body = cx.tcx.hir().body(body); - if closure_body.generator_kind == Some(CoroutineKind::Async(AsyncCoroutineKind::Block)); + if closure_body.coroutine_kind == Some(CoroutineKind::Async(AsyncCoroutineKind::Block)); then { return Some(closure_body); } diff --git a/clippy_lints/src/methods/iter_kv_map.rs b/clippy_lints/src/methods/iter_kv_map.rs index 674d345174819..b44a2716dde14 100644 --- a/clippy_lints/src/methods/iter_kv_map.rs +++ b/clippy_lints/src/methods/iter_kv_map.rs @@ -26,7 +26,7 @@ pub(super) fn check<'tcx>( if_chain! { if !expr.span.from_expansion(); if let ExprKind::Closure(c) = m_arg.kind; - if let Body {params: [p], value: body_expr, generator_kind: _ } = cx.tcx.hir().body(c.body); + if let Body {params: [p], value: body_expr, coroutine_kind: _ } = cx.tcx.hir().body(c.body); if let PatKind::Tuple([key_pat, val_pat], _) = p.pat.kind; let (replacement_kind, annotation, bound_ident) = match (&key_pat.kind, &val_pat.kind) { diff --git a/clippy_lints/src/needless_question_mark.rs b/clippy_lints/src/needless_question_mark.rs index f2c823323bbb3..d267b3de7f25a 100644 --- a/clippy_lints/src/needless_question_mark.rs +++ b/clippy_lints/src/needless_question_mark.rs @@ -87,7 +87,7 @@ impl LateLintPass<'_> for NeedlessQuestionMark { } fn check_body(&mut self, cx: &LateContext<'_>, body: &'_ Body<'_>) { - if let Some(CoroutineKind::Async(AsyncCoroutineKind::Fn)) = body.generator_kind { + if let Some(CoroutineKind::Async(AsyncCoroutineKind::Fn)) = body.coroutine_kind { if let ExprKind::Block( Block { expr: diff --git a/clippy_lints/src/redundant_async_block.rs b/clippy_lints/src/redundant_async_block.rs index 59aecd2327836..b8f787e1f1fbd 100644 --- a/clippy_lints/src/redundant_async_block.rs +++ b/clippy_lints/src/redundant_async_block.rs @@ -71,7 +71,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantAsyncBlock { fn desugar_async_block<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> { if let ExprKind::Closure(Closure { body, def_id, .. }) = expr.kind && let body = cx.tcx.hir().body(*body) && - matches!(body.generator_kind, Some(CoroutineKind::Async(AsyncCoroutineKind::Block))) + matches!(body.coroutine_kind, Some(CoroutineKind::Async(AsyncCoroutineKind::Block))) { cx .typeck_results() diff --git a/clippy_lints/src/redundant_closure_call.rs b/clippy_lints/src/redundant_closure_call.rs index f42836611ca53..c18237e887db4 100644 --- a/clippy_lints/src/redundant_closure_call.rs +++ b/clippy_lints/src/redundant_closure_call.rs @@ -144,7 +144,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall { // without this check, we'd end up linting twice. && !matches!(recv.kind, hir::ExprKind::Call(..)) && let (full_expr, call_depth) = get_parent_call_exprs(cx, expr) - && let Some((body, fn_decl, generator_kind)) = find_innermost_closure(cx, recv, call_depth) + && let Some((body, fn_decl, coroutine_kind)) = find_innermost_closure(cx, recv, call_depth) { span_lint_and_then( cx, @@ -156,7 +156,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall { let mut applicability = Applicability::MachineApplicable; let mut hint = Sugg::hir_with_context(cx, body, full_expr.span.ctxt(), "..", &mut applicability); - if generator_kind.is_async() + if coroutine_kind.is_async() && let hir::ExprKind::Closure(closure) = body.kind { let async_closure_body = cx.tcx.hir().body(closure.body); diff --git a/clippy_lints/src/unused_async.rs b/clippy_lints/src/unused_async.rs index 5e1ba1b0dc062..3649f8792ae5f 100644 --- a/clippy_lints/src/unused_async.rs +++ b/clippy_lints/src/unused_async.rs @@ -86,7 +86,7 @@ impl<'a, 'tcx> Visitor<'tcx> for AsyncFnVisitor<'a, 'tcx> { } fn visit_body(&mut self, b: &'tcx Body<'tcx>) { - let is_async_block = matches!(b.generator_kind, Some(rustc_hir::CoroutineKind::Async(_))); + let is_async_block = matches!(b.coroutine_kind, Some(rustc_hir::CoroutineKind::Async(_))); if is_async_block { self.async_depth += 1; diff --git a/clippy_utils/src/qualify_min_const_fn.rs b/clippy_utils/src/qualify_min_const_fn.rs index 0d8fd9d2adf10..f6096ea546daa 100644 --- a/clippy_utils/src/qualify_min_const_fn.rs +++ b/clippy_utils/src/qualify_min_const_fn.rs @@ -306,7 +306,7 @@ fn check_terminator<'tcx>( }, TerminatorKind::SwitchInt { discr, targets: _ } => check_operand(tcx, discr, span, body), TerminatorKind::CoroutineDrop | TerminatorKind::Yield { .. } => { - Err((span, "const fn generators are unstable".into())) + Err((span, "const fn coroutines are unstable".into())) }, TerminatorKind::Call { func, diff --git a/tests/ui/crashes/ice-5238.rs b/tests/ui/crashes/ice-5238.rs index 989eb6d448557..b1fc3fb9d2511 100644 --- a/tests/ui/crashes/ice-5238.rs +++ b/tests/ui/crashes/ice-5238.rs @@ -1,6 +1,6 @@ // Regression test for #5238 / https://github.com/rust-lang/rust/pull/69562 -#![feature(generators, generator_trait)] +#![feature(coroutines, coroutine_trait)] fn main() { let _ = || { diff --git a/tests/ui/large_futures.fixed b/tests/ui/large_futures.fixed index 4c192d1c8d1bd..aa8c3021b9708 100644 --- a/tests/ui/large_futures.fixed +++ b/tests/ui/large_futures.fixed @@ -1,4 +1,4 @@ -#![feature(generators)] +#![feature(coroutines)] #![warn(clippy::large_futures)] #![allow(clippy::never_loop)] #![allow(clippy::future_not_send)] diff --git a/tests/ui/large_futures.rs b/tests/ui/large_futures.rs index 557d89a9cf99d..fc6ea458d3dbd 100644 --- a/tests/ui/large_futures.rs +++ b/tests/ui/large_futures.rs @@ -1,4 +1,4 @@ -#![feature(generators)] +#![feature(coroutines)] #![warn(clippy::large_futures)] #![allow(clippy::never_loop)] #![allow(clippy::future_not_send)] From a585cda701581a16894858dc088eacd5a02fc78b Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Sat, 21 Oct 2023 13:41:57 +0200 Subject: [PATCH 14/14] Bump nightly version -> 2023-10-21 --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index fe2c77ab47f00..7c5b5e97a5c71 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2023-10-06" +channel = "nightly-2023-10-21" components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]