From 765c6b865cc5bac5dc173bdfa9524ca210d1c10f Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Thu, 10 Nov 2022 11:37:28 -0500 Subject: [PATCH 1/7] A MIR transform that checks pointers are aligned --- clippy_utils/src/qualify_min_const_fn.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_utils/src/qualify_min_const_fn.rs b/clippy_utils/src/qualify_min_const_fn.rs index 9f6adf3e3fa..cd9cc8bccb6 100644 --- a/clippy_utils/src/qualify_min_const_fn.rs +++ b/clippy_utils/src/qualify_min_const_fn.rs @@ -169,7 +169,7 @@ fn check_rvalue<'tcx>( Err((span, "unsizing casts are not allowed in const fn".into())) } }, - Rvalue::Cast(CastKind::PointerExposeAddress, _, _) => { + Rvalue::Cast(CastKind::PointerExposeAddress | CastKind::PointerAddress, _, _) => { Err((span, "casting pointers to ints is unstable in const fn".into())) }, Rvalue::Cast(CastKind::DynStar, _, _) => { From f96e38becba21476460a8596f9af058f14f24339 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Thu, 23 Mar 2023 20:19:45 -0400 Subject: [PATCH 2/7] Fix clippy --- clippy_utils/src/qualify_min_const_fn.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_utils/src/qualify_min_const_fn.rs b/clippy_utils/src/qualify_min_const_fn.rs index cd9cc8bccb6..9f6adf3e3fa 100644 --- a/clippy_utils/src/qualify_min_const_fn.rs +++ b/clippy_utils/src/qualify_min_const_fn.rs @@ -169,7 +169,7 @@ fn check_rvalue<'tcx>( Err((span, "unsizing casts are not allowed in const fn".into())) } }, - Rvalue::Cast(CastKind::PointerExposeAddress | CastKind::PointerAddress, _, _) => { + Rvalue::Cast(CastKind::PointerExposeAddress, _, _) => { Err((span, "casting pointers to ints is unstable in const fn".into())) }, Rvalue::Cast(CastKind::DynStar, _, _) => { From 8df896c076fd993bad58878ee8a6ed29d8e586ba Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Fri, 24 Mar 2023 14:04:35 +0100 Subject: [PATCH 3/7] Merge commit 'd5e2a7aca55ed49fc943b7a07a8eba05ab5a0079' into clippyup --- CHANGELOG.md | 9 +- CONTRIBUTING.md | 2 +- book/src/lint_configuration.md | 1 + clippy_lints/src/allow_attributes.rs | 71 +++ clippy_lints/src/booleans.rs | 25 +- clippy_lints/src/copies.rs | 70 ++- clippy_lints/src/declared_lints.rs | 3 + clippy_lints/src/default.rs | 9 +- clippy_lints/src/derive.rs | 8 +- clippy_lints/src/functions/must_use.rs | 5 +- clippy_lints/src/if_then_some_else_none.rs | 17 +- clippy_lints/src/let_with_type_underscore.rs | 2 +- clippy_lints/src/lib.rs | 9 +- clippy_lints/src/loops/same_item_push.rs | 32 +- clippy_lints/src/manual_async_fn.rs | 15 +- clippy_lints/src/manual_clamp.rs | 7 +- clippy_lints/src/manual_main_separator_str.rs | 74 +++ clippy_lints/src/matches/manual_unwrap_or.rs | 12 +- clippy_lints/src/matches/match_bool.rs | 20 +- clippy_lints/src/matches/match_ref_pats.rs | 28 +- .../src/matches/match_single_binding.rs | 52 +- .../src/matches/redundant_pattern_match.rs | 17 +- clippy_lints/src/matches/single_match.rs | 18 +- .../src/methods/bind_instead_of_map.rs | 11 +- clippy_lints/src/methods/clone_on_ref_ptr.rs | 8 +- clippy_lints/src/methods/or_fun_call.rs | 28 +- clippy_lints/src/misc.rs | 17 +- clippy_lints/src/mut_key.rs | 60 +-- clippy_lints/src/needless_bool.rs | 13 +- clippy_lints/src/no_mangle_with_rust_abi.rs | 28 +- clippy_lints/src/option_if_let_else.rs | 28 +- clippy_lints/src/redundant_async_block.rs | 39 +- .../src/semicolon_if_nothing_returned.rs | 13 +- .../src/significant_drop_tightening.rs | 38 +- clippy_lints/src/swap.rs | 7 +- clippy_lints/src/unit_types/let_unit_value.rs | 7 +- .../src/unnecessary_struct_initialization.rs | 84 ++++ clippy_lints/src/useless_conversion.rs | 14 +- clippy_lints/src/utils/conf.rs | 2 +- clippy_lints/src/wildcard_imports.rs | 8 +- clippy_utils/src/attrs.rs | 2 +- clippy_utils/src/eager_or_lazy.rs | 7 +- clippy_utils/src/msrvs.rs | 1 + clippy_utils/src/paths.rs | 1 + clippy_utils/src/qualify_min_const_fn.rs | 7 +- clippy_utils/src/source.rs | 42 +- clippy_utils/src/sugg.rs | 10 +- clippy_utils/src/ty.rs | 63 ++- clippy_utils/src/visitors.rs | 4 +- rust-toolchain | 2 +- tests/dogfood.rs | 4 +- tests/ui-internal/custom_ice_message.stderr | 1 + tests/ui-toml/ifs_same_cond/clippy.toml | 1 + tests/ui-toml/ifs_same_cond/ifs_same_cond.rs | 18 + .../ifs_same_cond/ifs_same_cond.stderr | 15 + tests/ui/allow_attributes.fixed | 25 + tests/ui/allow_attributes.rs | 25 + tests/ui/allow_attributes.stderr | 16 + tests/ui/almost_complete_range.fixed | 49 +- tests/ui/almost_complete_range.rs | 49 +- tests/ui/almost_complete_range.stderr | 93 ++-- tests/ui/as_conversions.rs | 13 +- tests/ui/as_conversions.stderr | 6 +- tests/ui/auxiliary/doc_unsafe_macros.rs | 16 - tests/ui/auxiliary/implicit_hasher_macros.rs | 6 - tests/ui/auxiliary/macro_rules.rs | 141 +----- tests/ui/auxiliary/macro_use_helper.rs | 2 +- tests/ui/auxiliary/proc_macro_with_span.rs | 32 -- tests/ui/auxiliary/proc_macros.rs | 474 ++++++++++++++++++ .../auxiliary/helper.rs | 2 +- tests/ui/crashes/ice-10148.rs | 6 +- tests/ui/default_numeric_fallback_f64.fixed | 17 +- tests/ui/default_numeric_fallback_f64.rs | 17 +- tests/ui/default_numeric_fallback_f64.stderr | 11 +- tests/ui/default_numeric_fallback_i32.fixed | 17 +- tests/ui/default_numeric_fallback_i32.rs | 17 +- tests/ui/default_numeric_fallback_i32.stderr | 11 +- tests/ui/default_trait_access.fixed | 6 +- tests/ui/default_trait_access.rs | 6 +- tests/ui/deref_addrof.fixed | 24 +- tests/ui/deref_addrof.rs | 24 +- tests/ui/deref_addrof.stderr | 38 +- tests/ui/deref_addrof_macro.rs | 15 +- tests/ui/doc_unsafe.rs | 12 +- tests/ui/empty_loop.rs | 15 +- tests/ui/equatable_if_let.fixed | 16 +- tests/ui/equatable_if_let.rs | 16 +- tests/ui/equatable_if_let.stderr | 32 +- tests/ui/field_reassign_with_default.rs | 36 +- tests/ui/field_reassign_with_default.stderr | 44 +- tests/ui/ifs_same_cond.rs | 26 + tests/ui/ifs_same_cond.stderr | 14 +- tests/ui/implicit_hasher.rs | 25 +- tests/ui/implicit_hasher.stderr | 55 +- .../ui/inconsistent_struct_constructor.fixed | 21 +- tests/ui/inconsistent_struct_constructor.rs | 21 +- .../ui/inconsistent_struct_constructor.stderr | 4 +- tests/ui/large_enum_variant.rs | 13 +- tests/ui/macro_use_imports.fixed | 4 +- tests/ui/macro_use_imports.rs | 2 +- tests/ui/macro_use_imports.stderr | 2 +- tests/ui/macro_use_imports_expect.rs | 2 +- tests/ui/manual_async_fn.fixed | 6 + tests/ui/manual_async_fn.rs | 12 + tests/ui/manual_async_fn.stderr | 47 +- tests/ui/manual_clamp.rs | 19 + tests/ui/manual_main_separator_str.fixed | 39 ++ tests/ui/manual_main_separator_str.rs | 39 ++ tests/ui/manual_main_separator_str.stderr | 28 ++ tests/ui/manual_rem_euclid.fixed | 24 +- tests/ui/manual_rem_euclid.rs | 24 +- tests/ui/manual_rem_euclid.stderr | 17 +- tests/ui/match_single_binding.fixed | 41 +- tests/ui/match_single_binding.rs | 55 +- tests/ui/match_single_binding.stderr | 111 +++- tests/ui/match_single_binding2.fixed | 4 +- tests/ui/match_single_binding2.stderr | 4 +- tests/ui/mem_replace_macro.rs | 23 +- tests/ui/mem_replace_macro.stderr | 11 +- .../ui/missing_const_for_fn/cant_be_const.rs | 6 +- tests/ui/missing_doc.rs | 6 +- tests/ui/missing_doc_impl.rs | 6 +- tests/ui/mistyped_literal_suffix.fixed | 6 +- tests/ui/mistyped_literal_suffix.rs | 6 +- tests/ui/multiple_unsafe_ops_per_block.rs | 11 +- tests/ui/multiple_unsafe_ops_per_block.stderr | 18 +- tests/ui/must_use_unit.fixed | 11 +- tests/ui/must_use_unit.rs | 11 +- tests/ui/mut_mut.rs | 11 +- tests/ui/mut_mut.stderr | 25 +- tests/ui/needless_late_init.fixed | 36 +- tests/ui/needless_late_init.rs | 36 +- tests/ui/needless_late_init.stderr | 32 +- tests/ui/needless_lifetimes.fixed | 41 +- tests/ui/needless_lifetimes.rs | 41 +- tests/ui/needless_lifetimes.stderr | 15 +- tests/ui/needless_update.rs | 2 +- tests/ui/no_effect.rs | 7 +- tests/ui/no_effect.stderr | 58 +-- tests/ui/no_mangle_with_rust_abi.fixed | 48 -- tests/ui/no_mangle_with_rust_abi.rs | 2 - tests/ui/no_mangle_with_rust_abi.stderr | 74 ++- tests/ui/nonminimal_bool.rs | 29 ++ tests/ui/option_env_unwrap.rs | 24 +- tests/ui/option_env_unwrap.stderr | 42 +- tests/ui/ptr_as_ptr.fixed | 16 +- tests/ui/ptr_as_ptr.rs | 16 +- tests/ui/ptr_as_ptr.stderr | 25 +- tests/ui/redundant_async_block.fixed | 47 ++ tests/ui/redundant_async_block.rs | 47 ++ tests/ui/redundant_async_block.stderr | 22 +- .../redundant_pattern_matching_result.fixed | 4 +- .../redundant_pattern_matching_result.stderr | 4 +- tests/ui/single_match_else.rs | 6 +- tests/ui/string_add.rs | 11 +- tests/ui/swap.fixed | 15 +- tests/ui/swap.rs | 15 +- tests/ui/swap.stderr | 34 +- tests/ui/toplevel_ref_arg.fixed | 24 +- tests/ui/toplevel_ref_arg.rs | 24 +- tests/ui/toplevel_ref_arg.stderr | 21 +- tests/ui/toplevel_ref_arg_non_rustfix.rs | 22 +- tests/ui/toplevel_ref_arg_non_rustfix.stderr | 7 +- tests/ui/try_err.fixed | 67 +-- tests/ui/try_err.rs | 67 +-- tests/ui/try_err.stderr | 32 +- tests/ui/uninit.rs | 23 +- tests/ui/uninit.stderr | 16 +- tests/ui/uninit_vec.rs | 27 + tests/ui/uninit_vec.stderr | 33 +- tests/ui/uninlined_format_args.fixed | 6 +- tests/ui/uninlined_format_args.rs | 6 +- tests/ui/unit_arg.rs | 6 +- tests/ui/unnecessary_lazy_eval.fixed | 6 +- tests/ui/unnecessary_lazy_eval.rs | 6 +- tests/ui/unnecessary_operation.fixed | 8 +- tests/ui/unnecessary_operation.rs | 8 +- tests/ui/unnecessary_operation.stderr | 38 +- .../unnecessary_struct_initialization.fixed | 73 +++ tests/ui/unnecessary_struct_initialization.rs | 77 +++ .../unnecessary_struct_initialization.stderr | 46 ++ tests/ui/unnecessary_unsafety_doc.rs | 12 +- tests/ui/unnecessary_unsafety_doc.stderr | 2 +- triagebot.toml | 1 + 184 files changed, 3000 insertions(+), 1635 deletions(-) create mode 100644 clippy_lints/src/allow_attributes.rs create mode 100644 clippy_lints/src/manual_main_separator_str.rs create mode 100644 clippy_lints/src/unnecessary_struct_initialization.rs create mode 100644 tests/ui-toml/ifs_same_cond/clippy.toml create mode 100644 tests/ui-toml/ifs_same_cond/ifs_same_cond.rs create mode 100644 tests/ui-toml/ifs_same_cond/ifs_same_cond.stderr create mode 100644 tests/ui/allow_attributes.fixed create mode 100644 tests/ui/allow_attributes.rs create mode 100644 tests/ui/allow_attributes.stderr delete mode 100644 tests/ui/auxiliary/doc_unsafe_macros.rs delete mode 100644 tests/ui/auxiliary/implicit_hasher_macros.rs delete mode 100644 tests/ui/auxiliary/proc_macro_with_span.rs create mode 100644 tests/ui/auxiliary/proc_macros.rs create mode 100644 tests/ui/manual_main_separator_str.fixed create mode 100644 tests/ui/manual_main_separator_str.rs create mode 100644 tests/ui/manual_main_separator_str.stderr delete mode 100644 tests/ui/no_mangle_with_rust_abi.fixed create mode 100644 tests/ui/unnecessary_struct_initialization.fixed create mode 100644 tests/ui/unnecessary_struct_initialization.rs create mode 100644 tests/ui/unnecessary_struct_initialization.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 0abe234fc8f..1323f973ccf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -152,6 +152,8 @@ Current stable, released 2023-03-09 * `SYSROOT` and `--sysroot` can now be set at the same time [#10149](https://github.com/rust-lang/rust-clippy/pull/10149) +* Fix error when providing an `array-size-threshold` in `clippy.toml` + [#10423](https://github.com/rust-lang/rust-clippy/pull/10423) ## Rust 1.67 @@ -186,8 +188,6 @@ Released 2023-01-26 ### Moves and Deprecations -* Moved [`uninlined_format_args`] to `style` (Now warn-by-default) - [#9865](https://github.com/rust-lang/rust-clippy/pull/9865) * Moved [`needless_collect`] to `nursery` (Now allow-by-default) [#9705](https://github.com/rust-lang/rust-clippy/pull/9705) * Moved [`or_fun_call`] to `nursery` (Now allow-by-default) @@ -423,7 +423,7 @@ Released 2022-12-15 [#9490](https://github.com/rust-lang/rust-clippy/pull/9490) * [`almost_complete_letter_range`]: No longer lints in external macros [#9467](https://github.com/rust-lang/rust-clippy/pull/9467) -* [`drop_copy`]: No longer lints on idiomatic cases in match arms +* [`drop_copy`]: No longer lints on idiomatic cases in match arms [#9491](https://github.com/rust-lang/rust-clippy/pull/9491) * [`question_mark`]: No longer lints in const context [#9487](https://github.com/rust-lang/rust-clippy/pull/9487) @@ -4382,6 +4382,7 @@ Released 2018-09-13 [`absurd_extreme_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#absurd_extreme_comparisons [`alloc_instead_of_core`]: https://rust-lang.github.io/rust-clippy/master/index.html#alloc_instead_of_core +[`allow_attributes`]: https://rust-lang.github.io/rust-clippy/master/index.html#allow_attributes [`allow_attributes_without_reason`]: https://rust-lang.github.io/rust-clippy/master/index.html#allow_attributes_without_reason [`almost_complete_letter_range`]: https://rust-lang.github.io/rust-clippy/master/index.html#almost_complete_letter_range [`almost_complete_range`]: https://rust-lang.github.io/rust-clippy/master/index.html#almost_complete_range @@ -4661,6 +4662,7 @@ Released 2018-09-13 [`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_let_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_let_else +[`manual_main_separator_str`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_main_separator_str [`manual_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_map [`manual_memcpy`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_memcpy [`manual_non_exhaustive`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_non_exhaustive @@ -4985,6 +4987,7 @@ Released 2018-09-13 [`unnecessary_safety_doc`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_safety_doc [`unnecessary_self_imports`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_self_imports [`unnecessary_sort_by`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_sort_by +[`unnecessary_struct_initialization`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_struct_initialization [`unnecessary_to_owned`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_to_owned [`unnecessary_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_unwrap [`unnecessary_wraps`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_wraps diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3158080d2b3..3df13280369 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -50,7 +50,7 @@ a [developer guide] and is a good place to start your journey. All issues on Clippy are mentored, if you want help simply ask someone from the Clippy team directly by mentioning them in the issue or over on [Zulip]. All currently active team members can be found -[here](https://github.com/rust-lang/highfive/blob/master/highfive/configs/rust-lang/rust-clippy.json#L3) +[here](https://github.com/rust-lang/rust-clippy/blob/master/triagebot.toml#L18) Some issues are easier than others. The [`good-first-issue`] label can be used to find the easy issues. You can use `@rustbot claim` to assign the issue to yourself. diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md index 995dd2f04b1..9ed6627b741 100644 --- a/book/src/lint_configuration.md +++ b/book/src/lint_configuration.md @@ -519,6 +519,7 @@ for the generic parameters for determining interior mutability **Default Value:** `["bytes::Bytes"]` (`Vec`) * [mutable_key_type](https://rust-lang.github.io/rust-clippy/master/index.html#mutable_key_type) +* [ifs_same_cond](https://rust-lang.github.io/rust-clippy/master/index.html#ifs_same_cond) ### allow-mixed-uninlined-format-args diff --git a/clippy_lints/src/allow_attributes.rs b/clippy_lints/src/allow_attributes.rs new file mode 100644 index 00000000000..15d46e954a9 --- /dev/null +++ b/clippy_lints/src/allow_attributes.rs @@ -0,0 +1,71 @@ +use ast::AttrStyle; +use clippy_utils::diagnostics::span_lint_and_sugg; +use rustc_ast as ast; +use rustc_errors::Applicability; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; + +declare_clippy_lint! { + /// Detects uses of the `#[allow]` attribute and suggests replacing it with + /// the `#[expect]` (See [RFC 2383](https://rust-lang.github.io/rfcs/2383-lint-reasons.html)) + /// + /// The expect attribute is still unstable and requires the `lint_reasons` + /// on nightly. It can be enabled by adding `#![feature(lint_reasons)]` to + /// the crate root. + /// + /// This lint only warns outer attributes (`#[allow]`), as inner attributes + /// (`#![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. + /// + /// ### Example + /// ```rust,ignore + /// #[allow(unused_mut)] + /// fn foo() -> usize { + /// let mut a = Vec::new(); + /// a.len() + /// } + /// ``` + /// Use instead: + /// ```rust,ignore + /// #![feature(lint_reasons)] + /// #[expect(unused_mut)] + /// fn foo() -> usize { + /// let mut a = Vec::new(); + /// a.len() + /// } + /// ``` + #[clippy::version = "1.69.0"] + pub ALLOW_ATTRIBUTES, + restriction, + "`#[allow]` will not trigger if a warning isn't found. `#[expect]` triggers if there are no warnings." +} + +declare_lint_pass!(AllowAttribute => [ALLOW_ATTRIBUTES]); + +impl LateLintPass<'_> for AllowAttribute { + // Separate each crate's features. + fn check_attribute(&mut self, cx: &LateContext<'_>, attr: &ast::Attribute) { + if_chain! { + if cx.tcx.features().lint_reasons; + if let AttrStyle::Outer = attr.style; + if let Some(ident) = attr.ident(); + if ident.name == rustc_span::symbol::sym::allow; + then { + span_lint_and_sugg( + cx, + ALLOW_ATTRIBUTES, + ident.span, + "#[allow] attribute found", + "replace it with", + "expect".into(), + Applicability::MachineApplicable, + ); + } + } + } +} diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs index e8106beec37..29fde9336c0 100644 --- a/clippy_lints/src/booleans.rs +++ b/clippy_lints/src/booleans.rs @@ -495,18 +495,19 @@ struct NotSimplificationVisitor<'a, 'tcx> { impl<'a, 'tcx> Visitor<'tcx> for NotSimplificationVisitor<'a, 'tcx> { fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { - if let ExprKind::Unary(UnOp::Not, inner) = &expr.kind { - if let Some(suggestion) = simplify_not(self.cx, inner) { - span_lint_and_sugg( - self.cx, - NONMINIMAL_BOOL, - expr.span, - "this boolean expression can be simplified", - "try", - suggestion, - Applicability::MachineApplicable, - ); - } + if let ExprKind::Unary(UnOp::Not, inner) = &expr.kind && + !inner.span.from_expansion() && + let Some(suggestion) = simplify_not(self.cx, inner) + { + span_lint_and_sugg( + self.cx, + NONMINIMAL_BOOL, + expr.span, + "this boolean expression can be simplified", + "try", + suggestion, + Applicability::MachineApplicable, + ); } walk_expr(self, expr); diff --git a/clippy_lints/src/copies.rs b/clippy_lints/src/copies.rs index f10c35cde52..970f5004993 100644 --- a/clippy_lints/src/copies.rs +++ b/clippy_lints/src/copies.rs @@ -1,18 +1,20 @@ use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_then}; use clippy_utils::source::{first_line_of_span, indent_of, reindent_multiline, snippet, snippet_opt}; -use clippy_utils::ty::needs_ordered_drop; +use clippy_utils::ty::{is_interior_mut_ty, needs_ordered_drop}; use clippy_utils::visitors::for_each_expr; use clippy_utils::{ - capture_local_usage, eq_expr_value, get_enclosing_block, hash_expr, hash_stmt, if_sequence, is_else_clause, - is_lint_allowed, path_to_local, search_same, ContainsName, HirEqInterExpr, SpanlessEq, + capture_local_usage, def_path_def_ids, eq_expr_value, find_binding_init, get_enclosing_block, hash_expr, hash_stmt, + if_sequence, is_else_clause, is_lint_allowed, path_to_local, search_same, ContainsName, HirEqInterExpr, SpanlessEq, }; use core::iter; use core::ops::ControlFlow; use rustc_errors::Applicability; +use rustc_hir::def_id::DefIdSet; use rustc_hir::intravisit; use rustc_hir::{BinOpKind, Block, Expr, ExprKind, HirId, HirIdSet, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_middle::query::Key; +use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::hygiene::walk_chain; use rustc_span::source_map::SourceMap; use rustc_span::{BytePos, Span, Symbol}; @@ -159,7 +161,21 @@ declare_clippy_lint! { "`if` statement with shared code in all blocks" } -declare_lint_pass!(CopyAndPaste => [ +pub struct CopyAndPaste { + ignore_interior_mutability: Vec, + ignored_ty_ids: DefIdSet, +} + +impl CopyAndPaste { + pub fn new(ignore_interior_mutability: Vec) -> Self { + Self { + ignore_interior_mutability, + ignored_ty_ids: DefIdSet::new(), + } + } +} + +impl_lint_pass!(CopyAndPaste => [ IFS_SAME_COND, SAME_FUNCTIONS_IN_IF_CONDITION, IF_SAME_THEN_ELSE, @@ -167,10 +183,18 @@ declare_lint_pass!(CopyAndPaste => [ ]); impl<'tcx> LateLintPass<'tcx> for CopyAndPaste { + fn check_crate(&mut self, cx: &LateContext<'tcx>) { + for ignored_ty in &self.ignore_interior_mutability { + let path: Vec<&str> = ignored_ty.split("::").collect(); + for id in def_path_def_ids(cx, path.as_slice()) { + self.ignored_ty_ids.insert(id); + } + } + } fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if !expr.span.from_expansion() && matches!(expr.kind, ExprKind::If(..)) && !is_else_clause(cx.tcx, expr) { let (conds, blocks) = if_sequence(expr); - lint_same_cond(cx, &conds); + lint_same_cond(cx, &conds, &self.ignored_ty_ids); lint_same_fns_in_if_cond(cx, &conds); let all_same = !is_lint_allowed(cx, IF_SAME_THEN_ELSE, expr.hir_id) && lint_if_same_then_else(cx, &conds, &blocks); @@ -547,9 +571,39 @@ fn check_for_warn_of_moved_symbol(cx: &LateContext<'_>, symbols: &[(HirId, Symbo }) } +fn method_caller_is_mutable(cx: &LateContext<'_>, caller_expr: &Expr<'_>, ignored_ty_ids: &DefIdSet) -> bool { + let caller_ty = cx.typeck_results().expr_ty(caller_expr); + // Check if given type has inner mutability and was not set to ignored by the configuration + let is_inner_mut_ty = is_interior_mut_ty(cx, caller_ty) + && !matches!(caller_ty.ty_adt_id(), Some(adt_id) if ignored_ty_ids.contains(&adt_id)); + + is_inner_mut_ty + || caller_ty.is_mutable_ptr() + // `find_binding_init` will return the binding iff its not mutable + || path_to_local(caller_expr) + .and_then(|hid| find_binding_init(cx, hid)) + .is_none() +} + /// Implementation of `IFS_SAME_COND`. -fn lint_same_cond(cx: &LateContext<'_>, conds: &[&Expr<'_>]) { - for (i, j) in search_same(conds, |e| hash_expr(cx, e), |lhs, rhs| eq_expr_value(cx, lhs, rhs)) { +fn lint_same_cond(cx: &LateContext<'_>, conds: &[&Expr<'_>], ignored_ty_ids: &DefIdSet) { + for (i, j) in search_same( + conds, + |e| hash_expr(cx, e), + |lhs, rhs| { + // Ignore eq_expr side effects iff one of the expressin kind is a method call + // and the caller is not a mutable, including inner mutable type. + if let ExprKind::MethodCall(_, caller, _, _) = lhs.kind { + if method_caller_is_mutable(cx, caller, ignored_ty_ids) { + false + } else { + SpanlessEq::new(cx).eq_expr(lhs, rhs) + } + } else { + eq_expr_value(cx, lhs, rhs) + } + }, + ) { span_lint_and_note( cx, IFS_SAME_COND, diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index cc6024b87cd..8ca91301472 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -35,6 +35,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::utils::internal_lints::produce_ice::PRODUCE_ICE_INFO, #[cfg(feature = "internal")] crate::utils::internal_lints::unnecessary_def_path::UNNECESSARY_DEF_PATH_INFO, + crate::allow_attributes::ALLOW_ATTRIBUTES_INFO, crate::almost_complete_range::ALMOST_COMPLETE_RANGE_INFO, crate::approx_const::APPROX_CONSTANT_INFO, crate::as_conversions::AS_CONVERSIONS_INFO, @@ -262,6 +263,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::manual_clamp::MANUAL_CLAMP_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, crate::manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE_INFO, crate::manual_rem_euclid::MANUAL_REM_EUCLID_INFO, crate::manual_retain::MANUAL_RETAIN_INFO, @@ -616,6 +618,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::unnamed_address::VTABLE_ADDRESS_COMPARISONS_INFO, crate::unnecessary_owned_empty_strings::UNNECESSARY_OWNED_EMPTY_STRINGS_INFO, crate::unnecessary_self_imports::UNNECESSARY_SELF_IMPORTS_INFO, + crate::unnecessary_struct_initialization::UNNECESSARY_STRUCT_INITIALIZATION_INFO, crate::unnecessary_wraps::UNNECESSARY_WRAPS_INFO, crate::unnested_or_patterns::UNNESTED_OR_PATTERNS_INFO, crate::unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME_INFO, diff --git a/clippy_lints/src/default.rs b/clippy_lints/src/default.rs index 080d44e6398..80c22742ba4 100644 --- a/clippy_lints/src/default.rs +++ b/clippy_lints/src/default.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_sugg}; -use clippy_utils::source::snippet_with_macro_callsite; +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, @@ -160,6 +160,8 @@ impl<'tcx> LateLintPass<'tcx> for Default { } }; + let init_ctxt = local.span.ctxt(); + // find all "later statement"'s where the fields of the binding set as // Default::default() get reassigned, unless the reassignment refers to the original binding let mut first_assign = None; @@ -169,7 +171,7 @@ impl<'tcx> LateLintPass<'tcx> for Default { // find out if and which field was set by this `consecutive_statement` if let Some((field_ident, assign_rhs)) = field_reassigned_by_stmt(consecutive_statement, binding_name) { // interrupt and cancel lint if assign_rhs references the original binding - if contains_name(binding_name, assign_rhs, cx) { + if contains_name(binding_name, assign_rhs, cx) || init_ctxt != consecutive_statement.span.ctxt() { cancel_lint = true; break; } @@ -204,11 +206,12 @@ impl<'tcx> LateLintPass<'tcx> for Default { .iter() .all(|field| assigned_fields.iter().any(|(a, _)| a == &field.name)); + let mut app = Applicability::Unspecified; let field_list = assigned_fields .into_iter() .map(|(field, rhs)| { // extract and store the assigned value for help message - let value_snippet = snippet_with_macro_callsite(cx, rhs.span, ".."); + let value_snippet = snippet_with_context(cx, rhs.span, init_ctxt, "..", &mut app).0; format!("{field}: {value_snippet}") }) .collect::>() diff --git a/clippy_lints/src/derive.rs b/clippy_lints/src/derive.rs index 715348e869e..f425dd5fb70 100644 --- a/clippy_lints/src/derive.rs +++ b/clippy_lints/src/derive.rs @@ -24,8 +24,8 @@ use rustc_span::sym; declare_clippy_lint! { /// ### What it does - /// Checks for deriving `Hash` but implementing `PartialEq` - /// explicitly or vice versa. + /// Lints against manual `PartialEq` implementations for types with a derived `Hash` + /// implementation. /// /// ### Why is this bad? /// The implementation of these traits must agree (for @@ -54,8 +54,8 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for deriving `Ord` but implementing `PartialOrd` - /// explicitly or vice versa. + /// Lints against manual `PartialOrd` and `Ord` implementations for types with a derived `Ord` + /// or `PartialOrd` implementation. /// /// ### Why is this bad? /// The implementation of these traits must agree (for diff --git a/clippy_lints/src/functions/must_use.rs b/clippy_lints/src/functions/must_use.rs index 67877780c0e..1e9e826631c 100644 --- a/clippy_lints/src/functions/must_use.rs +++ b/clippy_lints/src/functions/must_use.rs @@ -50,10 +50,7 @@ pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Imp let attr = cx.tcx.get_attr(item.owner_id, sym::must_use); if let Some(attr) = attr { check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr); - } else if is_public - && !is_proc_macro(attrs) - && trait_ref_of_method(cx, item.owner_id.def_id).is_none() - { + } else if is_public && !is_proc_macro(attrs) && trait_ref_of_method(cx, item.owner_id.def_id).is_none() { check_must_use_candidate( cx, sig.decl, diff --git a/clippy_lints/src/if_then_some_else_none.rs b/clippy_lints/src/if_then_some_else_none.rs index 9cadaaa493e..725bd3d54bc 100644 --- a/clippy_lints/src/if_then_some_else_none.rs +++ b/clippy_lints/src/if_then_some_else_none.rs @@ -1,8 +1,10 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::eager_or_lazy::switch_to_eager_eval; use clippy_utils::msrvs::{self, Msrv}; -use clippy_utils::source::snippet_with_macro_callsite; +use clippy_utils::source::snippet_with_context; +use clippy_utils::sugg::Sugg; use clippy_utils::{contains_return, higher, is_else_clause, is_res_lang_ctor, path_res, peel_blocks}; +use rustc_errors::Applicability; use rustc_hir::LangItem::{OptionNone, OptionSome}; use rustc_hir::{Expr, ExprKind, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; @@ -72,21 +74,20 @@ impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone { return; } + let ctxt = expr.span.ctxt(); + if let Some(higher::If { cond, then, r#else: Some(els) }) = higher::If::hir(expr) && let ExprKind::Block(then_block, _) = then.kind && let Some(then_expr) = then_block.expr && let ExprKind::Call(then_call, [then_arg]) = then_expr.kind + && then_expr.span.ctxt() == ctxt && is_res_lang_ctor(cx, path_res(cx, then_call), OptionSome) && is_res_lang_ctor(cx, path_res(cx, peel_blocks(els)), OptionNone) && !stmts_contains_early_return(then_block.stmts) { - let cond_snip = snippet_with_macro_callsite(cx, cond.span, "[condition]"); - let cond_snip = if matches!(cond.kind, ExprKind::Unary(_, _) | ExprKind::Binary(_, _, _)) { - format!("({cond_snip})") - } else { - cond_snip.into_owned() - }; - let arg_snip = snippet_with_macro_callsite(cx, then_arg.span, ""); + let mut app = Applicability::Unspecified; + let cond_snip = Sugg::hir_with_context(cx, cond, expr.span.ctxt(), "[condition]", &mut app).maybe_par().to_string(); + let arg_snip = snippet_with_context(cx, then_arg.span, ctxt, "[body]", &mut app).0; let mut method_body = if then_block.stmts.is_empty() { arg_snip.into_owned() } else { diff --git a/clippy_lints/src/let_with_type_underscore.rs b/clippy_lints/src/let_with_type_underscore.rs index ba51973f2f9..c01e3882d52 100644 --- a/clippy_lints/src/let_with_type_underscore.rs +++ b/clippy_lints/src/let_with_type_underscore.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_help; -use rustc_hir::*; +use rustc_hir::{Local, TyKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 491732be208..c9210bf73f8 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -67,6 +67,7 @@ mod declared_lints; mod renamed_lints; // begin lints modules, do not remove this comment, it’s used in `update_lints` +mod allow_attributes; mod almost_complete_range; mod approx_const; mod as_conversions; @@ -179,6 +180,7 @@ mod manual_bits; mod manual_clamp; mod manual_is_ascii_check; mod manual_let_else; +mod manual_main_separator_str; mod manual_non_exhaustive; mod manual_rem_euclid; mod manual_retain; @@ -300,6 +302,7 @@ mod unit_types; mod unnamed_address; mod unnecessary_owned_empty_strings; mod unnecessary_self_imports; +mod unnecessary_struct_initialization; mod unnecessary_wraps; mod unnested_or_patterns; mod unsafe_removed_from_name; @@ -656,7 +659,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|_| Box::new(empty_enum::EmptyEnum)); store.register_late_pass(|_| Box::new(invalid_upcast_comparisons::InvalidUpcastComparisons)); store.register_late_pass(|_| Box::new(regex::Regex)); - store.register_late_pass(|_| Box::new(copies::CopyAndPaste)); + let ignore_interior_mutability = conf.ignore_interior_mutability.clone(); + store.register_late_pass(move |_| Box::new(copies::CopyAndPaste::new(ignore_interior_mutability.clone()))); store.register_late_pass(|_| Box::new(copy_iterator::CopyIterator)); store.register_late_pass(|_| Box::new(format::UselessFormat)); store.register_late_pass(|_| Box::new(swap::Swap)); @@ -933,6 +937,9 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|_| Box::new(missing_assert_message::MissingAssertMessage)); store.register_early_pass(|| Box::new(redundant_async_block::RedundantAsyncBlock)); store.register_late_pass(|_| Box::new(let_with_type_underscore::UnderscoreTyped)); + store.register_late_pass(|_| Box::new(allow_attributes::AllowAttribute)); + store.register_late_pass(move |_| Box::new(manual_main_separator_str::ManualMainSeparatorStr::new(msrv()))); + store.register_late_pass(|_| Box::new(unnecessary_struct_initialization::UnnecessaryStruct)); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/clippy_lints/src/loops/same_item_push.rs b/clippy_lints/src/loops/same_item_push.rs index 540656a2cd9..9d9341559ac 100644 --- a/clippy_lints/src/loops/same_item_push.rs +++ b/clippy_lints/src/loops/same_item_push.rs @@ -1,15 +1,17 @@ use super::SAME_ITEM_PUSH; use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::path_to_local; -use clippy_utils::source::snippet_with_macro_callsite; +use clippy_utils::source::snippet_with_context; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; use if_chain::if_chain; use rustc_data_structures::fx::FxHashSet; +use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit::{walk_expr, Visitor}; use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, HirId, Mutability, Node, Pat, PatKind, Stmt, StmtKind}; use rustc_lint::LateContext; use rustc_span::symbol::sym; +use rustc_span::SyntaxContext; use std::iter::Iterator; /// Detects for loop pushing the same item into a Vec @@ -20,9 +22,10 @@ pub(super) fn check<'tcx>( body: &'tcx Expr<'_>, _: &'tcx Expr<'_>, ) { - fn emit_lint(cx: &LateContext<'_>, vec: &Expr<'_>, pushed_item: &Expr<'_>) { - let vec_str = snippet_with_macro_callsite(cx, vec.span, ""); - let item_str = snippet_with_macro_callsite(cx, pushed_item.span, ""); + fn emit_lint(cx: &LateContext<'_>, vec: &Expr<'_>, pushed_item: &Expr<'_>, ctxt: SyntaxContext) { + let mut app = Applicability::Unspecified; + let vec_str = snippet_with_context(cx, vec.span, ctxt, "", &mut app).0; + let item_str = snippet_with_context(cx, pushed_item.span, ctxt, "", &mut app).0; span_lint_and_help( cx, @@ -43,7 +46,7 @@ pub(super) fn check<'tcx>( walk_expr(&mut same_item_push_visitor, body); if_chain! { if same_item_push_visitor.should_lint(); - if let Some((vec, pushed_item)) = same_item_push_visitor.vec_push; + if let Some((vec, pushed_item, ctxt)) = same_item_push_visitor.vec_push; let vec_ty = cx.typeck_results().expr_ty(vec); let ty = vec_ty.walk().nth(1).unwrap().expect_ty(); if cx @@ -69,11 +72,11 @@ pub(super) fn check<'tcx>( then { match init.kind { // immutable bindings that are initialized with literal - ExprKind::Lit(..) => emit_lint(cx, vec, pushed_item), + ExprKind::Lit(..) => emit_lint(cx, vec, pushed_item, ctxt), // immutable bindings that are initialized with constant ExprKind::Path(ref path) => { if let Res::Def(DefKind::Const, ..) = cx.qpath_res(path, init.hir_id) { - emit_lint(cx, vec, pushed_item); + emit_lint(cx, vec, pushed_item, ctxt); } } _ => {}, @@ -82,11 +85,11 @@ pub(super) fn check<'tcx>( } }, // constant - Res::Def(DefKind::Const, ..) => emit_lint(cx, vec, pushed_item), + Res::Def(DefKind::Const, ..) => emit_lint(cx, vec, pushed_item, ctxt), _ => {}, } }, - ExprKind::Lit(..) => emit_lint(cx, vec, pushed_item), + ExprKind::Lit(..) => emit_lint(cx, vec, pushed_item, ctxt), _ => {}, } } @@ -98,7 +101,7 @@ struct SameItemPushVisitor<'a, 'tcx> { non_deterministic_expr: bool, multiple_pushes: bool, // this field holds the last vec push operation visited, which should be the only push seen - vec_push: Option<(&'tcx Expr<'tcx>, &'tcx Expr<'tcx>)>, + vec_push: Option<(&'tcx Expr<'tcx>, &'tcx Expr<'tcx>, SyntaxContext)>, cx: &'a LateContext<'tcx>, used_locals: FxHashSet, } @@ -118,7 +121,7 @@ impl<'a, 'tcx> SameItemPushVisitor<'a, 'tcx> { if_chain! { if !self.non_deterministic_expr; if !self.multiple_pushes; - if let Some((vec, _)) = self.vec_push; + if let Some((vec, _, _)) = self.vec_push; if let Some(hir_id) = path_to_local(vec); then { !self.used_locals.contains(&hir_id) @@ -173,7 +176,10 @@ impl<'a, 'tcx> Visitor<'tcx> for SameItemPushVisitor<'a, 'tcx> { // Given some statement, determine if that statement is a push on a Vec. If it is, return // the Vec being pushed into and the item being pushed -fn get_vec_push<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) -> Option<(&'tcx Expr<'tcx>, &'tcx Expr<'tcx>)> { +fn get_vec_push<'tcx>( + cx: &LateContext<'tcx>, + stmt: &'tcx Stmt<'_>, +) -> Option<(&'tcx Expr<'tcx>, &'tcx Expr<'tcx>, SyntaxContext)> { if_chain! { // Extract method being called if let StmtKind::Semi(semi_stmt) = &stmt.kind; @@ -184,7 +190,7 @@ fn get_vec_push<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) -> Option<(& if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_expr), sym::Vec); if path.ident.name.as_str() == "push"; then { - return Some((self_expr, pushed_item)) + return Some((self_expr, pushed_item, semi_stmt.span.ctxt())) } } None diff --git a/clippy_lints/src/manual_async_fn.rs b/clippy_lints/src/manual_async_fn.rs index f97c6bcb5d1..577bc1d661d 100644 --- a/clippy_lints/src/manual_async_fn.rs +++ b/clippy_lints/src/manual_async_fn.rs @@ -5,7 +5,7 @@ use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; use rustc_hir::{ AsyncGeneratorKind, Block, Body, Closure, Expr, ExprKind, FnDecl, FnRetTy, GeneratorKind, GenericArg, GenericBound, - ItemKind, LifetimeName, Term, TraitRef, Ty, TyKind, TypeBindingKind, + ImplItem, Item, ItemKind, LifetimeName, Node, Term, TraitRef, Ty, TyKind, TypeBindingKind, }; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -45,7 +45,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualAsyncFn { decl: &'tcx FnDecl<'_>, body: &'tcx Body<'_>, span: Span, - _: LocalDefId, + def_id: LocalDefId, ) { if_chain! { if let Some(header) = kind.header(); @@ -59,6 +59,8 @@ impl<'tcx> LateLintPass<'tcx> for ManualAsyncFn { if let ExprKind::Block(block, _) = body.value.kind; if block.stmts.is_empty(); if let Some(closure_body) = desugared_async_block(cx, block); + if let Node::Item(Item {vis_span, ..}) | Node::ImplItem(ImplItem {vis_span, ..}) = + cx.tcx.hir().get_by_def_id(def_id); then { let header_span = span.with_hi(ret_ty.span.hi()); @@ -69,15 +71,22 @@ impl<'tcx> LateLintPass<'tcx> for ManualAsyncFn { "this function can be simplified using the `async fn` syntax", |diag| { if_chain! { + if let Some(vis_snip) = snippet_opt(cx, *vis_span); if let Some(header_snip) = snippet_opt(cx, header_span); if let Some(ret_pos) = position_before_rarrow(&header_snip); if let Some((ret_sugg, ret_snip)) = suggested_ret(cx, output); then { + let header_snip = if vis_snip.is_empty() { + format!("async {}", &header_snip[..ret_pos]) + } else { + format!("{} async {}", vis_snip, &header_snip[vis_snip.len() + 1..ret_pos]) + }; + let help = format!("make the function `async` and {ret_sugg}"); diag.span_suggestion( header_span, help, - format!("async {}{ret_snip}", &header_snip[..ret_pos]), + format!("{header_snip}{ret_snip}"), Applicability::MachineApplicable ); diff --git a/clippy_lints/src/manual_clamp.rs b/clippy_lints/src/manual_clamp.rs index f239736d38a..440362b96b4 100644 --- a/clippy_lints/src/manual_clamp.rs +++ b/clippy_lints/src/manual_clamp.rs @@ -6,7 +6,8 @@ use clippy_utils::ty::implements_trait; use clippy_utils::visitors::is_const_evaluatable; use clippy_utils::MaybePath; use clippy_utils::{ - eq_expr_value, is_diag_trait_item, is_trait_method, path_res, path_to_local_id, peel_blocks, peel_blocks_with_stmt, + eq_expr_value, in_constant, is_diag_trait_item, is_trait_method, path_res, path_to_local_id, peel_blocks, + peel_blocks_with_stmt, }; use itertools::Itertools; use rustc_errors::Applicability; @@ -117,7 +118,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualClamp { if !self.msrv.meets(msrvs::CLAMP) { return; } - if !expr.span.from_expansion() { + if !expr.span.from_expansion() && !in_constant(cx, expr.hir_id) { let suggestion = is_if_elseif_else_pattern(cx, expr) .or_else(|| is_max_min_pattern(cx, expr)) .or_else(|| is_call_max_min_pattern(cx, expr)) @@ -130,7 +131,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualClamp { } fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) { - if !self.msrv.meets(msrvs::CLAMP) { + if !self.msrv.meets(msrvs::CLAMP) || in_constant(cx, block.hir_id) { return; } for suggestion in is_two_if_pattern(cx, block) { diff --git a/clippy_lints/src/manual_main_separator_str.rs b/clippy_lints/src/manual_main_separator_str.rs new file mode 100644 index 00000000000..c292bbe4e93 --- /dev/null +++ b/clippy_lints/src/manual_main_separator_str.rs @@ -0,0 +1,74 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::msrvs::{self, Msrv}; +use clippy_utils::{is_trait_method, match_def_path, paths, peel_hir_expr_refs}; +use rustc_errors::Applicability; +use rustc_hir::def::{DefKind, Res}; +use rustc_hir::{Expr, ExprKind, Mutability, QPath}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty; +use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_span::sym; + +declare_clippy_lint! { + /// ### What it does + /// Checks for references on `std::path::MAIN_SEPARATOR.to_string()` used + /// to build a `&str`. + /// + /// ### Why is this bad? + /// There exists a `std::path::MAIN_SEPARATOR_STR` which does not require + /// an extra memory allocation. + /// + /// ### Example + /// ```rust + /// let s: &str = &std::path::MAIN_SEPARATOR.to_string(); + /// ``` + /// Use instead: + /// ```rust + /// let s: &str = std::path::MAIN_SEPARATOR_STR; + /// ``` + #[clippy::version = "1.70.0"] + pub MANUAL_MAIN_SEPARATOR_STR, + complexity, + "`&std::path::MAIN_SEPARATOR.to_string()` can be replaced by `std::path::MAIN_SEPARATOR_STR`" +} + +pub struct ManualMainSeparatorStr { + msrv: Msrv, +} + +impl ManualMainSeparatorStr { + #[must_use] + pub fn new(msrv: Msrv) -> Self { + Self { msrv } + } +} + +impl_lint_pass!(ManualMainSeparatorStr => [MANUAL_MAIN_SEPARATOR_STR]); + +impl LateLintPass<'_> for ManualMainSeparatorStr { + fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { + if self.msrv.meets(msrvs::PATH_MAIN_SEPARATOR_STR) && + let (target, _) = peel_hir_expr_refs(expr) && + is_trait_method(cx, target, sym::ToString) && + let ExprKind::MethodCall(path, receiver, &[], _) = target.kind && + path.ident.name == sym::to_string && + let ExprKind::Path(QPath::Resolved(None, path)) = receiver.kind && + let Res::Def(DefKind::Const, receiver_def_id) = path.res && + match_def_path(cx, receiver_def_id, &paths::PATH_MAIN_SEPARATOR) && + let ty::Ref(_, ty, Mutability::Not) = cx.typeck_results().expr_ty_adjusted(expr).kind() && + ty.is_str() + { + span_lint_and_sugg( + cx, + MANUAL_MAIN_SEPARATOR_STR, + expr.span, + "taking a reference on `std::path::MAIN_SEPARATOR` conversion to `String`", + "replace with", + "std::path::MAIN_SEPARATOR_STR".to_owned(), + Applicability::MachineApplicable, + ); + } + } + + extract_msrv_attr!(LateContext); +} diff --git a/clippy_lints/src/matches/manual_unwrap_or.rs b/clippy_lints/src/matches/manual_unwrap_or.rs index 6447899f2b9..b94501bf0ad 100644 --- a/clippy_lints/src/matches/manual_unwrap_or.rs +++ b/clippy_lints/src/matches/manual_unwrap_or.rs @@ -32,14 +32,8 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, scrutinee: let reindented_or_body = reindent_multiline(or_body_snippet.into(), true, Some(indent)); - let suggestion = if scrutinee.span.from_expansion() { - // we don't want parentheses around macro, e.g. `(some_macro!()).unwrap_or(0)` - sugg::Sugg::hir_with_macro_callsite(cx, scrutinee, "..") - } - else { - sugg::Sugg::hir(cx, scrutinee, "..").maybe_par() - }; - + let mut app = Applicability::MachineApplicable; + let suggestion = sugg::Sugg::hir_with_context(cx, scrutinee, expr.span.ctxt(), "..", &mut app).maybe_par(); span_lint_and_sugg( cx, MANUAL_UNWRAP_OR, expr.span, @@ -48,7 +42,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, scrutinee: format!( "{suggestion}.unwrap_or({reindented_or_body})", ), - Applicability::MachineApplicable, + app, ); } } diff --git a/clippy_lints/src/matches/match_bool.rs b/clippy_lints/src/matches/match_bool.rs index 1c216e13570..df1e585f10b 100644 --- a/clippy_lints/src/matches/match_bool.rs +++ b/clippy_lints/src/matches/match_bool.rs @@ -10,9 +10,9 @@ use rustc_middle::ty; use super::MATCH_BOOL; -pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: &Expr<'_>) { +pub(crate) fn check(cx: &LateContext<'_>, scrutinee: &Expr<'_>, arms: &[Arm<'_>], expr: &Expr<'_>) { // Type of expression is `bool`. - if *cx.typeck_results().expr_ty(ex).kind() == ty::Bool { + if *cx.typeck_results().expr_ty(scrutinee).kind() == ty::Bool { span_lint_and_then( cx, MATCH_BOOL, @@ -36,24 +36,26 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: }; if let Some((true_expr, false_expr)) = exprs { + let mut app = Applicability::HasPlaceholders; + let ctxt = expr.span.ctxt(); let sugg = match (is_unit_expr(true_expr), is_unit_expr(false_expr)) { (false, false) => Some(format!( "if {} {} else {}", - snippet(cx, ex.span, "b"), - expr_block(cx, true_expr, None, "..", Some(expr.span)), - expr_block(cx, false_expr, None, "..", Some(expr.span)) + snippet(cx, scrutinee.span, "b"), + expr_block(cx, true_expr, ctxt, "..", Some(expr.span), &mut app), + expr_block(cx, false_expr, ctxt, "..", Some(expr.span), &mut app) )), (false, true) => Some(format!( "if {} {}", - snippet(cx, ex.span, "b"), - expr_block(cx, true_expr, None, "..", Some(expr.span)) + snippet(cx, scrutinee.span, "b"), + expr_block(cx, true_expr, ctxt, "..", Some(expr.span), &mut app) )), (true, false) => { - let test = Sugg::hir(cx, ex, ".."); + let test = Sugg::hir(cx, scrutinee, ".."); Some(format!( "if {} {}", !test, - expr_block(cx, false_expr, None, "..", Some(expr.span)) + expr_block(cx, false_expr, ctxt, "..", Some(expr.span), &mut app) )) }, (true, true) => None, diff --git a/clippy_lints/src/matches/match_ref_pats.rs b/clippy_lints/src/matches/match_ref_pats.rs index 80f964ba1b7..aba4c85c59e 100644 --- a/clippy_lints/src/matches/match_ref_pats.rs +++ b/clippy_lints/src/matches/match_ref_pats.rs @@ -1,13 +1,14 @@ use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then}; -use clippy_utils::source::snippet; +use clippy_utils::source::{snippet, walk_span_to_context}; use clippy_utils::sugg::Sugg; use core::iter::once; +use rustc_errors::Applicability; use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, Pat, PatKind}; use rustc_lint::LateContext; use super::MATCH_REF_PATS; -pub(crate) fn check<'a, 'b, I>(cx: &LateContext<'_>, ex: &Expr<'_>, pats: I, expr: &Expr<'_>) +pub(crate) fn check<'a, 'b, I>(cx: &LateContext<'_>, scrutinee: &Expr<'_>, pats: I, expr: &Expr<'_>) where 'b: 'a, I: Clone + Iterator>, @@ -17,13 +18,28 @@ where } let (first_sugg, msg, title); - let span = ex.span.source_callsite(); - if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = ex.kind { - first_sugg = once((span, Sugg::hir_with_macro_callsite(cx, inner, "..").to_string())); + let ctxt = expr.span.ctxt(); + let mut app = Applicability::Unspecified; + if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = scrutinee.kind { + if scrutinee.span.ctxt() != ctxt { + return; + } + first_sugg = once(( + scrutinee.span, + Sugg::hir_with_context(cx, inner, ctxt, "..", &mut app).to_string(), + )); msg = "try"; title = "you don't need to add `&` to both the expression and the patterns"; } else { - first_sugg = once((span, Sugg::hir_with_macro_callsite(cx, ex, "..").deref().to_string())); + let Some(span) = walk_span_to_context(scrutinee.span, ctxt) else { + return; + }; + first_sugg = once(( + span, + Sugg::hir_with_context(cx, scrutinee, ctxt, "..", &mut app) + .deref() + .to_string(), + )); msg = "instead of prefixing all patterns with `&`, you can dereference the expression"; title = "you don't need to add `&` to all patterns"; } diff --git a/clippy_lints/src/matches/match_single_binding.rs b/clippy_lints/src/matches/match_single_binding.rs index 065a5c72621..89da7a55cbd 100644 --- a/clippy_lints/src/matches/match_single_binding.rs +++ b/clippy_lints/src/matches/match_single_binding.rs @@ -1,10 +1,9 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::macros::HirNode; -use clippy_utils::source::{indent_of, snippet, snippet_block, snippet_with_applicability}; -use clippy_utils::sugg::Sugg; +use clippy_utils::source::{indent_of, snippet, snippet_block_with_context, snippet_with_applicability}; use clippy_utils::{get_parent_expr, is_refutable, peel_blocks}; use rustc_errors::Applicability; -use rustc_hir::{Arm, Expr, ExprKind, Node, PatKind}; +use rustc_hir::{Arm, Expr, ExprKind, Node, PatKind, StmtKind}; use rustc_lint::LateContext; use rustc_span::Span; @@ -24,21 +23,30 @@ pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], e let matched_vars = ex.span; let bind_names = arms[0].pat.span; let match_body = peel_blocks(arms[0].body); - let mut snippet_body = if match_body.span.from_expansion() { - Sugg::hir_with_macro_callsite(cx, match_body, "..").to_string() - } else { - snippet_block(cx, match_body.span, "..", Some(expr.span)).to_string() - }; + let mut app = Applicability::MaybeIncorrect; + let mut snippet_body = snippet_block_with_context( + cx, + match_body.span, + arms[0].span.ctxt(), + "..", + Some(expr.span), + &mut app, + ) + .0 + .to_string(); // Do we need to add ';' to suggestion ? - if let ExprKind::Block(block, _) = match_body.kind { - // macro + expr_ty(body) == () - if block.span.from_expansion() && cx.typeck_results().expr_ty(match_body).is_unit() { - snippet_body.push(';'); + if let Node::Stmt(stmt) = cx.tcx.hir().get_parent(expr.hir_id) + && let StmtKind::Expr(_) = stmt.kind + && match match_body.kind { + // We don't need to add a ; to blocks, unless that block is from a macro expansion + ExprKind::Block(block, _) => block.span.from_expansion(), + _ => true, } + { + snippet_body.push(';'); } - let mut applicability = Applicability::MaybeIncorrect; match arms[0].pat.kind { PatKind::Binding(..) | PatKind::Tuple(_, _) | PatKind::Struct(..) => { let (target_span, sugg) = match opt_parent_assign_span(cx, ex) { @@ -48,7 +56,7 @@ pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], e (ex, expr), (bind_names, matched_vars), &snippet_body, - &mut applicability, + &mut app, Some(span), true, ); @@ -60,7 +68,7 @@ pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], e "this assignment could be simplified", "consider removing the `match` expression", sugg, - applicability, + app, ); return; @@ -69,10 +77,10 @@ pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], e span, format!( "let {} = {};\n{}let {} = {snippet_body};", - snippet_with_applicability(cx, bind_names, "..", &mut applicability), - snippet_with_applicability(cx, matched_vars, "..", &mut applicability), + snippet_with_applicability(cx, bind_names, "..", &mut app), + snippet_with_applicability(cx, matched_vars, "..", &mut app), " ".repeat(indent_of(cx, expr.span).unwrap_or(0)), - snippet_with_applicability(cx, pat_span, "..", &mut applicability) + snippet_with_applicability(cx, pat_span, "..", &mut app) ), ), None => { @@ -81,7 +89,7 @@ pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], e (ex, expr), (bind_names, matched_vars), &snippet_body, - &mut applicability, + &mut app, None, true, ); @@ -96,7 +104,7 @@ pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], e "this match could be written as a `let` statement", "consider using a `let` statement", sugg, - applicability, + app, ); }, PatKind::Wild => { @@ -106,7 +114,7 @@ pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], e (ex, expr), (bind_names, matched_vars), &snippet_body, - &mut applicability, + &mut app, None, false, ); @@ -118,7 +126,7 @@ pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], e "this match could be replaced by its scrutinee and body", "consider using the scrutinee and body instead", sugg, - applicability, + app, ); } else { span_lint_and_sugg( diff --git a/clippy_lints/src/matches/redundant_pattern_match.rs b/clippy_lints/src/matches/redundant_pattern_match.rs index df0ea7f5b86..7b609ff3df8 100644 --- a/clippy_lints/src/matches/redundant_pattern_match.rs +++ b/clippy_lints/src/matches/redundant_pattern_match.rs @@ -1,6 +1,6 @@ use super::REDUNDANT_PATTERN_MATCHING; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::snippet; +use clippy_utils::source::{snippet, walk_span_to_context}; use clippy_utils::sugg::Sugg; use clippy_utils::ty::{is_type_diagnostic_item, needs_ordered_drop}; use clippy_utils::visitors::any_temporaries_need_ordered_drop; @@ -150,22 +150,25 @@ fn find_sugg_for_if_let<'tcx>( // if/while let ... = ... { ... } // ^^^^^^^^^^^^^^^^^^^^^^^^^^^ let expr_span = expr.span; + let ctxt = expr.span.ctxt(); // if/while let ... = ... { ... } - // ^^^ - let op_span = result_expr.span.source_callsite(); + // ^^^ + let Some(res_span) = walk_span_to_context(result_expr.span.source_callsite(), ctxt) else { + return; + }; // if/while let ... = ... { ... } - // ^^^^^^^^^^^^^^^^^^^ - let span = expr_span.until(op_span.shrink_to_hi()); + // ^^^^^^^^^^^^^^^^^^^^^^ + let span = expr_span.until(res_span.shrink_to_hi()); - let app = if needs_drop { + let mut app = if needs_drop { Applicability::MaybeIncorrect } else { Applicability::MachineApplicable }; - let sugg = Sugg::hir_with_macro_callsite(cx, result_expr, "_") + let sugg = Sugg::hir_with_context(cx, result_expr, ctxt, "_", &mut app) .maybe_par() .to_string(); diff --git a/clippy_lints/src/matches/single_match.rs b/clippy_lints/src/matches/single_match.rs index 19b49c44d57..ad47c13896c 100644 --- a/clippy_lints/src/matches/single_match.rs +++ b/clippy_lints/src/matches/single_match.rs @@ -67,8 +67,10 @@ fn report_single_pattern( els: Option<&Expr<'_>>, ) { let lint = if els.is_some() { SINGLE_MATCH_ELSE } else { SINGLE_MATCH }; + let ctxt = expr.span.ctxt(); + let mut app = Applicability::HasPlaceholders; let els_str = els.map_or(String::new(), |els| { - format!(" else {}", expr_block(cx, els, None, "..", Some(expr.span))) + format!(" else {}", expr_block(cx, els, ctxt, "..", Some(expr.span), &mut app)) }); let (pat, pat_ref_count) = peel_hir_pat_refs(arms[0].pat); @@ -103,7 +105,7 @@ fn report_single_pattern( // PartialEq for different reference counts may not exist. "&".repeat(ref_count_diff), snippet(cx, arms[0].pat.span, ".."), - expr_block(cx, arms[0].body, None, "..", Some(expr.span)), + expr_block(cx, arms[0].body, ctxt, "..", Some(expr.span), &mut app), ); (msg, sugg) } else { @@ -112,21 +114,13 @@ fn report_single_pattern( "if let {} = {} {}{els_str}", snippet(cx, arms[0].pat.span, ".."), snippet(cx, ex.span, ".."), - expr_block(cx, arms[0].body, None, "..", Some(expr.span)), + expr_block(cx, arms[0].body, ctxt, "..", Some(expr.span), &mut app), ); (msg, sugg) } }; - span_lint_and_sugg( - cx, - lint, - expr.span, - msg, - "try this", - sugg, - Applicability::HasPlaceholders, - ); + span_lint_and_sugg(cx, lint, expr.span, msg, "try this", sugg, app); } fn check_opt_like<'a>( diff --git a/clippy_lints/src/methods/bind_instead_of_map.rs b/clippy_lints/src/methods/bind_instead_of_map.rs index 8e1130cf8df..00853348840 100644 --- a/clippy_lints/src/methods/bind_instead_of_map.rs +++ b/clippy_lints/src/methods/bind_instead_of_map.rs @@ -1,6 +1,6 @@ use super::{contains_return, BIND_INSTEAD_OF_MAP}; use clippy_utils::diagnostics::{multispan_sugg_with_applicability, span_lint_and_sugg, span_lint_and_then}; -use clippy_utils::source::{snippet, snippet_with_macro_callsite}; +use clippy_utils::source::{snippet, snippet_with_context}; use clippy_utils::{peel_blocks, visitors::find_all_ret_expressions}; use if_chain::if_chain; use rustc_errors::Applicability; @@ -76,11 +76,8 @@ pub(crate) trait BindInsteadOfMap { if !contains_return(inner_expr); if let Some(msg) = Self::lint_msg(cx); then { - let some_inner_snip = if inner_expr.span.from_expansion() { - snippet_with_macro_callsite(cx, inner_expr.span, "_") - } else { - snippet(cx, inner_expr.span, "_") - }; + let mut app = Applicability::MachineApplicable; + let some_inner_snip = snippet_with_context(cx, inner_expr.span, closure_expr.span.ctxt(), "_", &mut app).0; let closure_args_snip = snippet(cx, closure_args_span, ".."); let option_snip = snippet(cx, recv.span, ".."); @@ -92,7 +89,7 @@ pub(crate) trait BindInsteadOfMap { &msg, "try this", note, - Applicability::MachineApplicable, + app, ); true } else { diff --git a/clippy_lints/src/methods/clone_on_ref_ptr.rs b/clippy_lints/src/methods/clone_on_ref_ptr.rs index 355f53532e2..5e8ad0861f3 100644 --- a/clippy_lints/src/methods/clone_on_ref_ptr.rs +++ b/clippy_lints/src/methods/clone_on_ref_ptr.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::paths; -use clippy_utils::source::snippet_with_macro_callsite; +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; @@ -33,7 +33,9 @@ pub(super) fn check( return; }; - let snippet = snippet_with_macro_callsite(cx, receiver.span, ".."); + // Sometimes unnecessary ::<_> after Rc/Arc/Weak + let mut app = Applicability::Unspecified; + let snippet = snippet_with_context(cx, receiver.span, expr.span.ctxt(), "..", &mut app).0; span_lint_and_sugg( cx, @@ -42,7 +44,7 @@ pub(super) fn check( "using `.clone()` on a ref-counted pointer", "try this", format!("{caller_type}::<{}>::clone(&{snippet})", subst.type_at(0)), - Applicability::Unspecified, // Sometimes unnecessary ::<_> after Rc/Arc/Weak + app, ); } } diff --git a/clippy_lints/src/methods/or_fun_call.rs b/clippy_lints/src/methods/or_fun_call.rs index 4460f38fcc1..7ce28ea93e0 100644 --- a/clippy_lints/src/methods/or_fun_call.rs +++ b/clippy_lints/src/methods/or_fun_call.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::eager_or_lazy::switch_to_lazy_eval; -use clippy_utils::source::{snippet, snippet_with_macro_callsite}; +use clippy_utils::source::snippet_with_context; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; use clippy_utils::{contains_return, is_trait_item, last_path_segment}; use if_chain::if_chain; @@ -9,7 +9,6 @@ use rustc_hir as hir; use rustc_lint::LateContext; use rustc_span::source_map::Span; use rustc_span::symbol::{kw, sym, Symbol}; -use std::borrow::Cow; use super::OR_FUN_CALL; @@ -111,37 +110,24 @@ pub(super) fn check<'tcx>( if poss.contains(&name); then { + let ctxt = span.ctxt(); + let mut app = Applicability::HasPlaceholders; let sugg = { let (snippet_span, use_lambda) = match (fn_has_arguments, fun_span) { (false, Some(fun_span)) => (fun_span, false), _ => (arg.span, true), }; - let format_span = |span: Span| { - let not_macro_argument_snippet = snippet_with_macro_callsite(cx, span, ".."); - let snip = if not_macro_argument_snippet == "vec![]" { - let macro_expanded_snipped = snippet(cx, snippet_span, ".."); - match macro_expanded_snipped.strip_prefix("$crate::vec::") { - Some(stripped) => Cow::Owned(stripped.to_owned()), - None => macro_expanded_snipped, - } - } else { - not_macro_argument_snippet - }; - - snip.to_string() - }; - - let snip = format_span(snippet_span); + let snip = snippet_with_context(cx, snippet_span, ctxt, "..", &mut app).0; let snip = if use_lambda { let l_arg = if fn_has_arguments { "_" } else { "" }; format!("|{l_arg}| {snip}") } else { - snip + snip.into_owned() }; if let Some(f) = second_arg { - let f = format_span(f.span); + let f = snippet_with_context(cx, f.span, ctxt, "..", &mut app).0; format!("{snip}, {f}") } else { snip @@ -155,7 +141,7 @@ pub(super) fn check<'tcx>( &format!("use of `{name}` followed by a function call"), "try this", format!("{name}_{suffix}({sugg})"), - Applicability::HasPlaceholders, + app, ); } } diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index 0705029a613..3752b9a946f 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_hir_and_then}; -use clippy_utils::source::{snippet, snippet_opt}; +use clippy_utils::source::{snippet, snippet_opt, snippet_with_context}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; @@ -181,20 +181,17 @@ impl<'tcx> LateLintPass<'tcx> for LintPass { if let PatKind::Binding(BindingAnnotation(ByRef::Yes, mutabl), .., name, None) = local.pat.kind; if let Some(init) = local.init; then { - // use the macro callsite when the init span (but not the whole local span) - // comes from an expansion like `vec![1, 2, 3]` in `let ref _ = vec![1, 2, 3];` - let sugg_init = if init.span.from_expansion() && !local.span.from_expansion() { - Sugg::hir_with_macro_callsite(cx, init, "..") - } else { - Sugg::hir(cx, init, "..") - }; + let ctxt = local.span.ctxt(); + let mut app = Applicability::MachineApplicable; + let sugg_init = Sugg::hir_with_context(cx, init, ctxt, "..", &mut app); let (mutopt, initref) = if mutabl == Mutability::Mut { ("mut ", sugg_init.mut_addr()) } else { ("", sugg_init.addr()) }; let tyopt = if let Some(ty) = local.ty { - format!(": &{mutopt}{ty}", ty=snippet(cx, ty.span, "..")) + let ty_snip = snippet_with_context(cx, ty.span, ctxt, "_", &mut app).0; + format!(": &{mutopt}{ty_snip}") } else { String::new() }; @@ -212,7 +209,7 @@ impl<'tcx> LateLintPass<'tcx> for LintPass { "let {name}{tyopt} = {initref};", name=snippet(cx, name.span, ".."), ), - Applicability::MachineApplicable, + app, ); } ); diff --git a/clippy_lints/src/mut_key.rs b/clippy_lints/src/mut_key.rs index 8aa814b7405..309f67521a3 100644 --- a/clippy_lints/src/mut_key.rs +++ b/clippy_lints/src/mut_key.rs @@ -1,10 +1,11 @@ use clippy_utils::diagnostics::span_lint; +use clippy_utils::ty::is_interior_mut_ty; use clippy_utils::{def_path_def_ids, trait_ref_of_method}; use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty::TypeVisitableExt; -use rustc_middle::ty::{Adt, Array, Ref, Slice, Tuple, Ty}; +use rustc_middle::query::Key; +use rustc_middle::ty::{Adt, Ty}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::def_id::LocalDefId; use rustc_span::source_map::Span; @@ -153,53 +154,18 @@ impl MutableKeyType { let is_keyed_type = [sym::HashMap, sym::BTreeMap, sym::HashSet, sym::BTreeSet] .iter() .any(|diag_item| cx.tcx.is_diagnostic_item(*diag_item, def.did())); - if is_keyed_type && self.is_interior_mutable_type(cx, substs.type_at(0)) { + if !is_keyed_type { + return; + } + + let subst_ty = substs.type_at(0); + // Determines if a type contains interior mutability which would affect its implementation of + // [`Hash`] or [`Ord`]. + if is_interior_mut_ty(cx, subst_ty) + && !matches!(subst_ty.ty_adt_id(), Some(adt_id) if self.ignore_mut_def_ids.contains(&adt_id)) + { span_lint(cx, MUTABLE_KEY_TYPE, span, "mutable key type"); } } } - - /// Determines if a type contains interior mutability which would affect its implementation of - /// [`Hash`] or [`Ord`]. - fn is_interior_mutable_type<'tcx>(&self, cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { - match *ty.kind() { - Ref(_, inner_ty, mutbl) => mutbl == hir::Mutability::Mut || self.is_interior_mutable_type(cx, inner_ty), - Slice(inner_ty) => self.is_interior_mutable_type(cx, inner_ty), - Array(inner_ty, size) => { - size.try_eval_target_usize(cx.tcx, cx.param_env) - .map_or(true, |u| u != 0) - && self.is_interior_mutable_type(cx, inner_ty) - }, - Tuple(fields) => fields.iter().any(|ty| self.is_interior_mutable_type(cx, ty)), - Adt(def, substs) => { - // Special case for collections in `std` who's impl of `Hash` or `Ord` delegates to - // that of their type parameters. Note: we don't include `HashSet` and `HashMap` - // because they have no impl for `Hash` or `Ord`. - let def_id = def.did(); - let is_std_collection = [ - sym::Option, - sym::Result, - sym::LinkedList, - sym::Vec, - sym::VecDeque, - sym::BTreeMap, - sym::BTreeSet, - sym::Rc, - sym::Arc, - ] - .iter() - .any(|diag_item| cx.tcx.is_diagnostic_item(*diag_item, def_id)); - let is_box = Some(def_id) == cx.tcx.lang_items().owned_box(); - if is_std_collection || is_box || self.ignore_mut_def_ids.contains(&def_id) { - // The type is mutable if any of its type parameters are - substs.types().any(|ty| self.is_interior_mutable_type(cx, ty)) - } else { - !ty.has_escaping_bound_vars() - && cx.tcx.layout_of(cx.param_env.and(ty)).is_ok() - && !ty.is_freeze(cx.tcx, cx.param_env) - } - }, - _ => false, - } - } } diff --git a/clippy_lints/src/needless_bool.rs b/clippy_lints/src/needless_bool.rs index a4eec95b371..c87059bf61d 100644 --- a/clippy_lints/src/needless_bool.rs +++ b/clippy_lints/src/needless_bool.rs @@ -340,18 +340,11 @@ fn suggest_bool_comparison<'a, 'tcx>( cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, expr: &Expr<'_>, - mut applicability: Applicability, + mut app: Applicability, message: &str, conv_hint: impl FnOnce(Sugg<'a>) -> Sugg<'a>, ) { - let hint = if expr.span.from_expansion() { - if applicability != Applicability::Unspecified { - applicability = Applicability::MaybeIncorrect; - } - Sugg::hir_with_macro_callsite(cx, expr, "..") - } else { - Sugg::hir_with_applicability(cx, expr, "..", &mut applicability) - }; + let hint = Sugg::hir_with_context(cx, expr, e.span.ctxt(), "..", &mut app); span_lint_and_sugg( cx, BOOL_COMPARISON, @@ -359,7 +352,7 @@ fn suggest_bool_comparison<'a, 'tcx>( message, "try simplifying it as shown", conv_hint(hint).to_string(), - applicability, + app, ); } diff --git a/clippy_lints/src/no_mangle_with_rust_abi.rs b/clippy_lints/src/no_mangle_with_rust_abi.rs index bc64ccb295c..8fd9ae351a0 100644 --- a/clippy_lints/src/no_mangle_with_rust_abi.rs +++ b/clippy_lints/src/no_mangle_with_rust_abi.rs @@ -1,9 +1,10 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet_with_applicability; use rustc_errors::Applicability; use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::{BytePos, Pos}; use rustc_target::spec::abi::Abi; declare_clippy_lint! { @@ -38,25 +39,28 @@ impl<'tcx> LateLintPass<'tcx> for NoMangleWithRustAbi { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { if let ItemKind::Fn(fn_sig, _, _) = &item.kind { let attrs = cx.tcx.hir().attrs(item.hir_id()); - let mut applicability = Applicability::MachineApplicable; - let snippet = snippet_with_applicability(cx, fn_sig.span, "..", &mut applicability); + let mut app = Applicability::MaybeIncorrect; + let snippet = snippet_with_applicability(cx, fn_sig.span, "..", &mut app); for attr in attrs { if let Some(ident) = attr.ident() && ident.name == rustc_span::sym::no_mangle && fn_sig.header.abi == Abi::Rust - && !snippet.contains("extern") { + && let Some((fn_attrs, _)) = snippet.split_once("fn") + && !fn_attrs.contains("extern") + { + let sugg_span = fn_sig.span + .with_lo(fn_sig.span.lo() + BytePos::from_usize(fn_attrs.len())) + .shrink_to_lo(); - let suggestion = snippet.split_once("fn") - .map_or(String::new(), |(first, second)| format!(r#"{first}extern "C" fn{second}"#)); - - span_lint_and_sugg( + span_lint_and_then( cx, NO_MANGLE_WITH_RUST_ABI, fn_sig.span, - "attribute #[no_mangle] set on a Rust ABI function", - "try", - suggestion, - applicability + "`#[no_mangle]` set on a function with the default (`Rust`) ABI", + |diag| { + diag.span_suggestion(sugg_span, "set an ABI", "extern \"C\" ", app) + .span_suggestion(sugg_span, "or explicitly set the default", "extern \"Rust\" ", app); + }, ); } } diff --git a/clippy_lints/src/option_if_let_else.rs b/clippy_lints/src/option_if_let_else.rs index c5ea09590d3..bbbcda069c5 100644 --- a/clippy_lints/src/option_if_let_else.rs +++ b/clippy_lints/src/option_if_let_else.rs @@ -12,6 +12,7 @@ use rustc_hir::{ }; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::SyntaxContext; declare_clippy_lint! { /// ### What it does @@ -95,10 +96,10 @@ struct OptionOccurrence { none_expr: String, } -fn format_option_in_sugg(cx: &LateContext<'_>, cond_expr: &Expr<'_>, as_ref: bool, as_mut: bool) -> String { +fn format_option_in_sugg(cond_sugg: Sugg<'_>, as_ref: bool, as_mut: bool) -> String { format!( "{}{}", - Sugg::hir_with_macro_callsite(cx, cond_expr, "..").maybe_par(), + cond_sugg.maybe_par(), if as_mut { ".as_mut()" } else if as_ref { @@ -111,6 +112,7 @@ fn format_option_in_sugg(cx: &LateContext<'_>, cond_expr: &Expr<'_>, as_ref: boo fn try_get_option_occurrence<'tcx>( cx: &LateContext<'tcx>, + ctxt: SyntaxContext, pat: &Pat<'tcx>, expr: &Expr<'_>, if_then: &'tcx Expr<'_>, @@ -160,11 +162,23 @@ fn try_get_option_occurrence<'tcx>( } } + let mut app = Applicability::Unspecified; return Some(OptionOccurrence { - option: format_option_in_sugg(cx, cond_expr, as_ref, as_mut), + option: format_option_in_sugg( + Sugg::hir_with_context(cx, cond_expr, ctxt, "..", &mut app), + as_ref, + as_mut, + ), method_sugg: method_sugg.to_string(), - some_expr: format!("|{capture_mut}{capture_name}| {}", Sugg::hir_with_macro_callsite(cx, some_body, "..")), - none_expr: format!("{}{}", if method_sugg == "map_or" { "" } else { "|| " }, Sugg::hir_with_macro_callsite(cx, none_body, "..")), + some_expr: format!( + "|{capture_mut}{capture_name}| {}", + Sugg::hir_with_context(cx, some_body, ctxt, "..", &mut app), + ), + none_expr: format!( + "{}{}", + if method_sugg == "map_or" { "" } else { "|| " }, + Sugg::hir_with_context(cx, none_body, ctxt, "..", &mut app), + ), }); } } @@ -194,7 +208,7 @@ fn detect_option_if_let_else<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> }) = higher::IfLet::hir(cx, expr) { if !is_else_clause(cx.tcx, expr) { - return try_get_option_occurrence(cx, let_pat, let_expr, if_then, if_else); + return try_get_option_occurrence(cx, expr.span.ctxt(), let_pat, let_expr, if_then, if_else); } } None @@ -203,7 +217,7 @@ fn detect_option_if_let_else<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> fn detect_option_match<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> Option { if let ExprKind::Match(ex, arms, MatchSource::Normal) = expr.kind { if let Some((let_pat, if_then, if_else)) = try_convert_match(cx, arms) { - return try_get_option_occurrence(cx, let_pat, ex, if_then, if_else); + return try_get_option_occurrence(cx, expr.span.ctxt(), let_pat, ex, if_then, if_else); } } None diff --git a/clippy_lints/src/redundant_async_block.rs b/clippy_lints/src/redundant_async_block.rs index 27ad4308637..2d30e77d55d 100644 --- a/clippy_lints/src/redundant_async_block.rs +++ b/clippy_lints/src/redundant_async_block.rs @@ -1,5 +1,5 @@ use clippy_utils::{diagnostics::span_lint_and_sugg, source::snippet}; -use rustc_ast::ast::*; +use rustc_ast::ast::{Expr, ExprKind, Stmt, StmtKind}; use rustc_ast::visit::Visitor as AstVisitor; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; @@ -32,7 +32,7 @@ declare_clippy_lint! { /// ``` #[clippy::version = "1.69.0"] pub REDUNDANT_ASYNC_BLOCK, - complexity, + nursery, "`async { future.await }` can be replaced by `future`" } declare_lint_pass!(RedundantAsyncBlock => [REDUNDANT_ASYNC_BLOCK]); @@ -48,6 +48,11 @@ impl EarlyLintPass for RedundantAsyncBlock { !future.span.from_expansion() && !await_in_expr(future) { + if captures_value(last) { + // If the async block captures variables then there is no equivalence. + return; + } + span_lint_and_sugg( cx, REDUNDANT_ASYNC_BLOCK, @@ -82,3 +87,33 @@ impl<'ast> AstVisitor<'ast> for AwaitDetector { } } } + +/// Check whether an expression may have captured a local variable. +/// This is done by looking for paths with only one segment, except as +/// a prefix of `.await` since this would be captured by value. +/// +/// This function will sometimes return `true` even tough there are no +/// captures happening: at the AST level, it is impossible to +/// dinstinguish a function call from a call to a closure which comes +/// from the local environment. +fn captures_value(expr: &Expr) -> bool { + let mut detector = CaptureDetector::default(); + detector.visit_expr(expr); + detector.capture_found +} + +#[derive(Default)] +struct CaptureDetector { + capture_found: bool, +} + +impl<'ast> AstVisitor<'ast> for CaptureDetector { + fn visit_expr(&mut self, ex: &'ast Expr) { + match (&ex.kind, self.capture_found) { + (ExprKind::Await(fut), _) if matches!(fut.kind, ExprKind::Path(..)) => (), + (ExprKind::Path(_, path), _) if path.segments.len() == 1 => self.capture_found = true, + (_, false) => rustc_ast::visit::walk_expr(self, ex), + _ => (), + } + } +} diff --git a/clippy_lints/src/semicolon_if_nothing_returned.rs b/clippy_lints/src/semicolon_if_nothing_returned.rs index 66638eed998..355f907e257 100644 --- a/clippy_lints/src/semicolon_if_nothing_returned.rs +++ b/clippy_lints/src/semicolon_if_nothing_returned.rs @@ -1,7 +1,6 @@ use crate::rustc_lint::LintContext; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet_with_macro_callsite; -use clippy_utils::sugg; +use clippy_utils::source::snippet_with_context; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Block, ExprKind}; @@ -44,7 +43,8 @@ impl<'tcx> LateLintPass<'tcx> for SemicolonIfNothingReturned { if let Some(expr) = block.expr; let t_expr = cx.typeck_results().expr_ty(expr); if t_expr.is_unit(); - if let snippet = snippet_with_macro_callsite(cx, expr.span, "}"); + let mut app = Applicability::MaybeIncorrect; + if let snippet = snippet_with_context(cx, expr.span, block.span.ctxt(), "}", &mut app).0; if !snippet.ends_with('}') && !snippet.ends_with(';'); if cx.sess().source_map().is_multiline(block.span); then { @@ -52,17 +52,14 @@ impl<'tcx> LateLintPass<'tcx> for SemicolonIfNothingReturned { if let ExprKind::DropTemps(..) = &expr.kind { return; } - - let sugg = sugg::Sugg::hir_with_macro_callsite(cx, expr, ".."); - let suggestion = format!("{sugg};"); span_lint_and_sugg( cx, SEMICOLON_IF_NOTHING_RETURNED, expr.span.source_callsite(), "consider adding a `;` to the last statement for consistent formatting", "add a `;` here", - suggestion, - Applicability::MaybeIncorrect, + format!("{snippet};"), + app, ); } } diff --git a/clippy_lints/src/significant_drop_tightening.rs b/clippy_lints/src/significant_drop_tightening.rs index e12681c0a0c..869358fb1ba 100644 --- a/clippy_lints/src/significant_drop_tightening.rs +++ b/clippy_lints/src/significant_drop_tightening.rs @@ -1,9 +1,9 @@ -use crate::FxHashSet; use clippy_utils::{ diagnostics::span_lint_and_then, get_attr, source::{indent_of, snippet}, }; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::{Applicability, Diagnostic}; use rustc_hir::{ self as hir, @@ -58,6 +58,7 @@ impl_lint_pass!(SignificantDropTightening<'_> => [SIGNIFICANT_DROP_TIGHTENING]); pub struct SignificantDropTightening<'tcx> { /// Auxiliary structure used to avoid having to verify the same type multiple times. seen_types: FxHashSet>, + type_cache: FxHashMap, bool>, } impl<'tcx> SignificantDropTightening<'tcx> { @@ -118,7 +119,7 @@ impl<'tcx> SignificantDropTightening<'tcx> { stmt: &hir::Stmt<'_>, cb: impl Fn(&mut SigDropAuxParams), ) { - let mut sig_drop_finder = SigDropFinder::new(cx, &mut self.seen_types); + let mut sig_drop_finder = SigDropFinder::new(cx, &mut self.seen_types, &mut self.type_cache); sig_drop_finder.visit_expr(expr); if sig_drop_finder.has_sig_drop { cb(sdap); @@ -296,15 +297,24 @@ impl Default for SigDropAuxParams { struct SigDropChecker<'cx, 'sdt, 'tcx> { cx: &'cx LateContext<'tcx>, seen_types: &'sdt mut FxHashSet>, + type_cache: &'sdt mut FxHashMap, bool>, } impl<'cx, 'sdt, 'tcx> SigDropChecker<'cx, 'sdt, 'tcx> { - pub(crate) fn new(cx: &'cx LateContext<'tcx>, seen_types: &'sdt mut FxHashSet>) -> Self { + pub(crate) fn new( + cx: &'cx LateContext<'tcx>, + seen_types: &'sdt mut FxHashSet>, + type_cache: &'sdt mut FxHashMap, bool>, + ) -> Self { seen_types.clear(); - Self { cx, seen_types } + Self { + cx, + seen_types, + type_cache, + } } - pub(crate) fn has_sig_drop_attr(&mut self, ty: Ty<'tcx>) -> bool { + pub(crate) fn has_sig_drop_attr_uncached(&mut self, ty: Ty<'tcx>) -> bool { if let Some(adt) = ty.ty_adt_def() { let mut iter = get_attr( self.cx.sess(), @@ -340,6 +350,16 @@ impl<'cx, 'sdt, 'tcx> SigDropChecker<'cx, 'sdt, 'tcx> { } } + pub(crate) fn has_sig_drop_attr(&mut self, ty: Ty<'tcx>) -> bool { + // The borrow checker prevents us from using something fancier like or_insert_with. + if let Some(ty) = self.type_cache.get(&ty) { + return *ty; + } + let value = self.has_sig_drop_attr_uncached(ty); + self.type_cache.insert(ty, value); + value + } + fn has_seen_ty(&mut self, ty: Ty<'tcx>) -> bool { !self.seen_types.insert(ty) } @@ -353,11 +373,15 @@ struct SigDropFinder<'cx, 'sdt, 'tcx> { } impl<'cx, 'sdt, 'tcx> SigDropFinder<'cx, 'sdt, 'tcx> { - fn new(cx: &'cx LateContext<'tcx>, seen_types: &'sdt mut FxHashSet>) -> Self { + fn new( + cx: &'cx LateContext<'tcx>, + seen_types: &'sdt mut FxHashSet>, + type_cache: &'sdt mut FxHashMap, bool>, + ) -> Self { Self { cx, has_sig_drop: false, - sig_drop_checker: SigDropChecker::new(cx, seen_types), + sig_drop_checker: SigDropChecker::new(cx, seen_types, type_cache), } } } diff --git a/clippy_lints/src/swap.rs b/clippy_lints/src/swap.rs index 1aeac724ab1..f7eef03d1d4 100644 --- a/clippy_lints/src/swap.rs +++ b/clippy_lints/src/swap.rs @@ -6,7 +6,8 @@ use clippy_utils::{can_mut_borrow_both, eq_expr_value, in_constant, std_or_core} use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Block, Expr, ExprKind, PatKind, QPath, Stmt, StmtKind}; -use rustc_lint::{LateContext, LateLintPass}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_middle::lint::in_external_macro; use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Spanned; @@ -188,8 +189,10 @@ fn check_suspicious_swap(cx: &LateContext<'_>, block: &Block<'_>) { if let Some((lhs0, rhs0)) = parse(first) && let Some((lhs1, rhs1)) = parse(second) && first.span.eq_ctxt(second.span) + && !in_external_macro(cx.sess(), first.span) && is_same(cx, lhs0, rhs1) && is_same(cx, lhs1, rhs0) + && !is_same(cx, lhs1, rhs1) // Ignore a = b; a = a (#10421) && let Some(lhs_sugg) = match &lhs0 { ExprOrIdent::Expr(expr) => Sugg::hir_opt(cx, expr), ExprOrIdent::Ident(ident) => Some(Sugg::NonParen(ident.as_str().into())), @@ -257,8 +260,8 @@ fn parse<'a, 'hir>(stmt: &'a Stmt<'hir>) -> Option<(ExprOrIdent<'hir>, &'a Expr< /// Implementation of the xor case for `MANUAL_SWAP` lint. fn check_xor_swap(cx: &LateContext<'_>, block: &Block<'_>) { for [s1, s2, s3] in block.stmts.array_windows::<3>() { + let ctxt = s1.span.ctxt(); if_chain! { - let ctxt = s1.span.ctxt(); if let Some((lhs0, rhs0)) = extract_sides_of_xor_assign(s1, ctxt); if let Some((lhs1, rhs1)) = extract_sides_of_xor_assign(s2, ctxt); if let Some((lhs2, rhs2)) = extract_sides_of_xor_assign(s3, ctxt); diff --git a/clippy_lints/src/unit_types/let_unit_value.rs b/clippy_lints/src/unit_types/let_unit_value.rs index 3430b6e3734..cc7c2b039f2 100644 --- a/clippy_lints/src/unit_types/let_unit_value.rs +++ b/clippy_lints/src/unit_types/let_unit_value.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::get_parent_node; -use clippy_utils::source::snippet_with_macro_callsite; +use clippy_utils::source::snippet_with_context; use clippy_utils::visitors::{for_each_local_assignment, for_each_value_source}; use core::ops::ControlFlow; use rustc_errors::Applicability; @@ -52,12 +52,13 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, local: &'tcx Local<'_>) { "this let-binding has unit value", |diag| { if let Some(expr) = &local.init { - let snip = snippet_with_macro_callsite(cx, expr.span, "()"); + let mut app = Applicability::MachineApplicable; + let snip = snippet_with_context(cx, expr.span, local.span.ctxt(), "()", &mut app).0; diag.span_suggestion( local.span, "omit the `let` binding", format!("{snip};"), - Applicability::MachineApplicable, // snippet + app, ); } }, diff --git a/clippy_lints/src/unnecessary_struct_initialization.rs b/clippy_lints/src/unnecessary_struct_initialization.rs new file mode 100644 index 00000000000..af0b4b1592f --- /dev/null +++ b/clippy_lints/src/unnecessary_struct_initialization.rs @@ -0,0 +1,84 @@ +use clippy_utils::{diagnostics::span_lint_and_sugg, get_parent_expr, path_to_local, source::snippet, ty::is_copy}; +use rustc_hir::{BindingAnnotation, Expr, ExprKind, Node, PatKind, UnOp}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; + +declare_clippy_lint! { + /// ### What it does + /// Checks for initialization of a `struct` by copying a base without setting + /// any field. + /// + /// ### Why is this bad? + /// Readibility suffers from unnecessary struct building. + /// + /// ### Example + /// ```rust + /// struct S { s: String } + /// + /// let a = S { s: String::from("Hello, world!") }; + /// let b = S { ..a }; + /// ``` + /// Use instead: + /// ```rust + /// struct S { s: String } + /// + /// let a = S { s: String::from("Hello, world!") }; + /// let b = a; + /// ``` + #[clippy::version = "1.70.0"] + pub UNNECESSARY_STRUCT_INITIALIZATION, + complexity, + "struct built from a base that can be written mode concisely" +} +declare_lint_pass!(UnnecessaryStruct => [UNNECESSARY_STRUCT_INITIALIZATION]); + +impl LateLintPass<'_> for UnnecessaryStruct { + fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { + if let ExprKind::Struct(_, &[], Some(base)) = expr.kind { + if let Some(parent) = get_parent_expr(cx, expr) && + let parent_ty = cx.typeck_results().expr_ty_adjusted(parent) && + parent_ty.is_any_ptr() + { + if is_copy(cx, cx.typeck_results().expr_ty(expr)) && path_to_local(base).is_some() { + // When the type implements `Copy`, a reference to the new struct works on the + // copy. Using the original would borrow it. + return; + } + + if parent_ty.is_mutable_ptr() && !is_mutable(cx, base) { + // The original can be used in a mutable reference context only if it is mutable. + return; + } + } + + // TODO: do not propose to replace *XX if XX is not Copy + if let ExprKind::Unary(UnOp::Deref, target) = base.kind && + matches!(target.kind, ExprKind::Path(..)) && + !is_copy(cx, cx.typeck_results().expr_ty(expr)) + { + // `*base` cannot be used instead of the struct in the general case if it is not Copy. + return; + } + + span_lint_and_sugg( + cx, + UNNECESSARY_STRUCT_INITIALIZATION, + expr.span, + "unnecessary struct building", + "replace with", + snippet(cx, base.span, "..").into_owned(), + rustc_errors::Applicability::MachineApplicable, + ); + } + } +} + +fn is_mutable(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { + if let Some(hir_id) = path_to_local(expr) && + let Node::Pat(pat) = cx.tcx.hir().get(hir_id) + { + matches!(pat.kind, PatKind::Binding(BindingAnnotation::MUT, ..)) + } else { + true + } +} diff --git a/clippy_lints/src/useless_conversion.rs b/clippy_lints/src/useless_conversion.rs index fede625f72a..ddbe6b2c790 100644 --- a/clippy_lints/src/useless_conversion.rs +++ b/clippy_lints/src/useless_conversion.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg}; -use clippy_utils::source::{snippet, snippet_with_macro_callsite}; +use clippy_utils::source::{snippet, 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, match_def_path, path_to_local, paths}; @@ -68,15 +68,16 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { let a = cx.typeck_results().expr_ty(e); let b = cx.typeck_results().expr_ty(recv); if same_type_and_consts(a, b) { - let sugg = snippet_with_macro_callsite(cx, recv.span, "").to_string(); + let mut app = Applicability::MachineApplicable; + let sugg = snippet_with_context(cx, recv.span, e.span.ctxt(), "", &mut app).0; span_lint_and_sugg( cx, USELESS_CONVERSION, e.span, &format!("useless conversion to the same type: `{b}`"), "consider removing `.into()`", - sugg, - Applicability::MachineApplicable, // snippet + sugg.into_owned(), + app, ); } } @@ -165,7 +166,8 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { if same_type_and_consts(a, b); then { - let sugg = Sugg::hir_with_macro_callsite(cx, arg, "").maybe_par(); + let mut app = Applicability::MachineApplicable; + let sugg = Sugg::hir_with_context(cx, arg, e.span.ctxt(), "", &mut app).maybe_par(); let sugg_msg = format!("consider removing `{}()`", snippet(cx, path.span, "From::from")); span_lint_and_sugg( @@ -175,7 +177,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { &format!("useless conversion to the same type: `{b}`"), &sugg_msg, sugg.to_string(), - Applicability::MachineApplicable, // snippet + app, ); } } diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index 1c7f3e96db8..8ba252425a3 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -437,7 +437,7 @@ define_Conf! { /// /// The maximum size of the `Err`-variant in a `Result` returned from a function (large_error_threshold: u64 = 128), - /// Lint: MUTABLE_KEY_TYPE. + /// Lint: MUTABLE_KEY_TYPE, IFS_SAME_COND. /// /// A list of paths to types that should be treated like `Arc`, i.e. ignored but /// for the generic parameters for determining interior mutability diff --git a/clippy_lints/src/wildcard_imports.rs b/clippy_lints/src/wildcard_imports.rs index e105452e1c5..36f910c983f 100644 --- a/clippy_lints/src/wildcard_imports.rs +++ b/clippy_lints/src/wildcard_imports.rs @@ -158,12 +158,10 @@ impl LateLintPass<'_> for WildcardImports { let mut imports = used_imports.items().map(ToString::to_string).into_sorted_stable_ord(false); let imports_string = if imports.len() == 1 { imports.pop().unwrap() + } else if braced_glob { + imports.join(", ") } else { - if braced_glob { - imports.join(", ") - } else { - format!("{{{}}}", imports.join(", ")) - } + format!("{{{}}}", imports.join(", ")) }; let sugg = if braced_glob { diff --git a/clippy_utils/src/attrs.rs b/clippy_utils/src/attrs.rs index bc3d774540a..b4ad42a5027 100644 --- a/clippy_utils/src/attrs.rs +++ b/clippy_utils/src/attrs.rs @@ -146,7 +146,7 @@ pub fn get_unique_attr<'a>( /// Return true if the attributes contain any of `proc_macro`, /// `proc_macro_derive` or `proc_macro_attribute`, false otherwise pub fn is_proc_macro(attrs: &[ast::Attribute]) -> bool { - attrs.iter().any(|attr| attr.is_proc_macro_attr()) + attrs.iter().any(rustc_ast::Attribute::is_proc_macro_attr) } /// Return true if the attributes contain `#[doc(hidden)]` diff --git a/clippy_utils/src/eager_or_lazy.rs b/clippy_utils/src/eager_or_lazy.rs index babbc7294a1..28c85717061 100644 --- a/clippy_utils/src/eager_or_lazy.rs +++ b/clippy_utils/src/eager_or_lazy.rs @@ -199,10 +199,9 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS }, // Memory allocation, custom operator, loop, or call to an unknown function - ExprKind::Unary(..) - | ExprKind::Binary(..) - | ExprKind::Loop(..) - | ExprKind::Call(..) => self.eagerness = Lazy, + ExprKind::Unary(..) | ExprKind::Binary(..) | ExprKind::Loop(..) | ExprKind::Call(..) => { + self.eagerness = Lazy; + }, ExprKind::ConstBlock(_) | ExprKind::Array(_) diff --git a/clippy_utils/src/msrvs.rs b/clippy_utils/src/msrvs.rs index dbf9f3b621d..e05de2dc99c 100644 --- a/clippy_utils/src/msrvs.rs +++ b/clippy_utils/src/msrvs.rs @@ -19,6 +19,7 @@ macro_rules! msrv_aliases { // names may refer to stabilized feature flags or library items msrv_aliases! { + 1,68,0 { PATH_MAIN_SEPARATOR_STR } 1,65,0 { LET_ELSE } 1,62,0 { BOOL_THEN_SOME, DEFAULT_ENUM_ATTRIBUTE } 1,58,0 { FORMAT_ARGS_CAPTURE, PATTERN_TRAIT_CHAR_ARRAY } diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index 4aae0f7284e..c919575bfe9 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -67,6 +67,7 @@ pub const PARKING_LOT_MUTEX_GUARD: [&str; 3] = ["lock_api", "mutex", "MutexGuard pub const PARKING_LOT_RWLOCK_READ_GUARD: [&str; 3] = ["lock_api", "rwlock", "RwLockReadGuard"]; pub const PARKING_LOT_RWLOCK_WRITE_GUARD: [&str; 3] = ["lock_api", "rwlock", "RwLockWriteGuard"]; 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"]; diff --git a/clippy_utils/src/qualify_min_const_fn.rs b/clippy_utils/src/qualify_min_const_fn.rs index 9f6adf3e3fa..d66640ba0b7 100644 --- a/clippy_utils/src/qualify_min_const_fn.rs +++ b/clippy_utils/src/qualify_min_const_fn.rs @@ -176,9 +176,10 @@ fn check_rvalue<'tcx>( // FIXME(dyn-star) unimplemented!() }, - Rvalue::Cast(CastKind::Transmute, _, _) => { - Err((span, "transmute can attempt to turn pointers into integers, so is unstable in const fn".into())) - }, + Rvalue::Cast(CastKind::Transmute, _, _) => Err(( + span, + "transmute can attempt to turn pointers into integers, so is unstable in const fn".into(), + )), // binops are fine on integers Rvalue::BinaryOp(_, box (lhs, rhs)) | Rvalue::CheckedBinaryOp(_, box (lhs, rhs)) => { check_operand(tcx, lhs, span, body)?; diff --git a/clippy_utils/src/source.rs b/clippy_utils/src/source.rs index cd5dcfdaca3..62fa37660fa 100644 --- a/clippy_utils/src/source.rs +++ b/clippy_utils/src/source.rs @@ -12,24 +12,21 @@ use rustc_span::{BytePos, Pos, Span, SpanData, SyntaxContext, DUMMY_SP}; use std::borrow::Cow; /// Like `snippet_block`, but add braces if the expr is not an `ExprKind::Block`. -/// Also takes an `Option` which can be put inside the braces. -pub fn expr_block<'a, T: LintContext>( +pub fn expr_block( cx: &T, expr: &Expr<'_>, - option: Option, - default: &'a str, + outer: SyntaxContext, + default: &str, indent_relative_to: Option, -) -> Cow<'a, str> { - let code = snippet_block(cx, expr.span, default, indent_relative_to); - let string = option.unwrap_or_default(); - if expr.span.from_expansion() { - Cow::Owned(format!("{{ {} }}", snippet_with_macro_callsite(cx, expr.span, default))) + app: &mut Applicability, +) -> String { + let (code, from_macro) = snippet_block_with_context(cx, expr.span, outer, default, indent_relative_to, app); + if from_macro { + format!("{{ {code} }}") } else if let ExprKind::Block(_, _) = expr.kind { - Cow::Owned(format!("{code}{string}")) - } else if string.is_empty() { - Cow::Owned(format!("{{ {code} }}")) + format!("{code}") } else { - Cow::Owned(format!("{{\n{code};\n{string}\n}}")) + format!("{{ {code} }}") } } @@ -229,12 +226,6 @@ fn snippet_with_applicability_sess<'a>( ) } -/// Same as `snippet`, but should only be used when it's clear that the input span is -/// not a macro argument. -pub fn snippet_with_macro_callsite<'a, T: LintContext>(cx: &T, span: Span, default: &'a str) -> Cow<'a, str> { - snippet(cx, span.source_callsite(), default) -} - /// Converts a span to a code snippet. Returns `None` if not available. pub fn snippet_opt(cx: &impl LintContext, span: Span) -> Option { snippet_opt_sess(cx.sess(), span) @@ -303,6 +294,19 @@ pub fn snippet_block_with_applicability<'a>( reindent_multiline(snip, true, indent) } +pub fn snippet_block_with_context<'a>( + cx: &impl LintContext, + span: Span, + outer: SyntaxContext, + default: &'a str, + indent_relative_to: Option, + app: &mut Applicability, +) -> (Cow<'a, str>, bool) { + let (snip, from_macro) = snippet_with_context(cx, span, outer, default, app); + let indent = indent_relative_to.and_then(|s| indent_of(cx, s)); + (reindent_multiline(snip, true, indent), from_macro) +} + /// Same as `snippet_with_applicability`, but first walks the span up to the given context. This /// will result in the macro call, rather then the expansion, if the span is from a child context. /// If the span is not from a child context, it will be used directly instead. diff --git a/clippy_utils/src/sugg.rs b/clippy_utils/src/sugg.rs index 44cb5d5756a..a5a4a921d94 100644 --- a/clippy_utils/src/sugg.rs +++ b/clippy_utils/src/sugg.rs @@ -1,9 +1,7 @@ //! Contains utility functions to generate suggestions. #![deny(clippy::missing_docs_in_private_items)] -use crate::source::{ - snippet, snippet_opt, snippet_with_applicability, snippet_with_context, snippet_with_macro_callsite, -}; +use crate::source::{snippet, snippet_opt, snippet_with_applicability, snippet_with_context}; use crate::ty::expr_sig; use crate::{get_parent_expr_for_hir, higher}; use rustc_ast::util::parser::AssocOp; @@ -89,12 +87,6 @@ impl<'a> Sugg<'a> { }) } - /// Same as `hir`, but will use the pre expansion span if the `expr` was in a macro. - pub fn hir_with_macro_callsite(cx: &LateContext<'_>, expr: &hir::Expr<'_>, default: &'a str) -> Self { - let get_snippet = |span| snippet_with_macro_callsite(cx, span, default); - Self::hir_from_snippet(expr, get_snippet) - } - /// Same as `hir`, but first walks the span up to the given context. This will result in the /// macro call, rather then the expansion, if the span is from a child context. If the span is /// not from a child context, it will be used directly instead. diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index e0ea3952785..0b47234647f 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -16,9 +16,9 @@ use rustc_infer::infer::{ use rustc_lint::LateContext; use rustc_middle::mir::interpret::{ConstValue, Scalar}; use rustc_middle::ty::{ - self, AdtDef, AliasTy, AssocKind, Binder, BoundRegion, FnSig, IntTy, List, ParamEnv, Predicate, PredicateKind, - Region, RegionKind, SubstsRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, - UintTy, VariantDef, VariantDiscr, + self, layout::ValidityRequirement, AdtDef, AliasTy, AssocKind, Binder, BoundRegion, FnSig, IntTy, List, ParamEnv, + Predicate, PredicateKind, Region, RegionKind, SubstsRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, + TypeVisitableExt, TypeVisitor, UintTy, VariantDef, VariantDiscr, }; use rustc_middle::ty::{GenericArg, GenericArgKind}; use rustc_span::symbol::Ident; @@ -538,13 +538,12 @@ pub fn same_type_and_consts<'tcx>(a: Ty<'tcx>, b: Ty<'tcx>) -> bool { } /// Checks if a given type looks safe to be uninitialized. -pub fn is_uninit_value_valid_for_ty(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { - match *ty.kind() { - ty::Array(component, _) => is_uninit_value_valid_for_ty(cx, component), - ty::Tuple(types) => types.iter().all(|ty| is_uninit_value_valid_for_ty(cx, ty)), - ty::Adt(adt, _) => cx.tcx.lang_items().maybe_uninit() == Some(adt.did()), - _ => false, - } +pub fn is_uninit_value_valid_for_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { + cx.tcx + .check_validity_requirement((ValidityRequirement::Uninit, cx.param_env.and(ty))) + // For types containing generic parameters we cannot get a layout to check. + // Therefore, we are conservative and assume that they don't allow uninit. + .unwrap_or(false) } /// Gets an iterator over all predicates which apply to the given item. @@ -1121,3 +1120,47 @@ pub fn make_normalized_projection<'tcx>( } helper(tcx, param_env, make_projection(tcx, container_id, assoc_ty, substs)?) } + +/// Check if given type has inner mutability such as [`std::cell::Cell`] or [`std::cell::RefCell`] +/// etc. +pub fn is_interior_mut_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { + match *ty.kind() { + ty::Ref(_, inner_ty, mutbl) => mutbl == Mutability::Mut || is_interior_mut_ty(cx, inner_ty), + ty::Slice(inner_ty) => is_interior_mut_ty(cx, inner_ty), + ty::Array(inner_ty, size) => { + size.try_eval_target_usize(cx.tcx, cx.param_env) + .map_or(true, |u| u != 0) + && is_interior_mut_ty(cx, inner_ty) + }, + ty::Tuple(fields) => fields.iter().any(|ty| is_interior_mut_ty(cx, ty)), + ty::Adt(def, substs) => { + // Special case for collections in `std` who's impl of `Hash` or `Ord` delegates to + // that of their type parameters. Note: we don't include `HashSet` and `HashMap` + // because they have no impl for `Hash` or `Ord`. + let def_id = def.did(); + let is_std_collection = [ + sym::Option, + sym::Result, + sym::LinkedList, + sym::Vec, + sym::VecDeque, + sym::BTreeMap, + sym::BTreeSet, + sym::Rc, + sym::Arc, + ] + .iter() + .any(|diag_item| cx.tcx.is_diagnostic_item(*diag_item, def_id)); + let is_box = Some(def_id) == cx.tcx.lang_items().owned_box(); + if is_std_collection || is_box { + // The type is mutable if any of its type parameters are + substs.types().any(|ty| is_interior_mut_ty(cx, ty)) + } else { + !ty.has_escaping_bound_vars() + && cx.tcx.layout_of(cx.param_env.and(ty)).is_ok() + && !ty.is_freeze(cx.tcx, cx.param_env) + } + }, + _ => false, + } +} diff --git a/clippy_utils/src/visitors.rs b/clippy_utils/src/visitors.rs index 86a93f64fb7..1dc19bac984 100644 --- a/clippy_utils/src/visitors.rs +++ b/clippy_utils/src/visitors.rs @@ -599,9 +599,7 @@ pub fn for_each_unconsumed_temporary<'tcx, B>( | ExprKind::Let(&Let { init: e, .. }) => { helper(typeck, false, e, f)?; }, - ExprKind::Block(&Block { expr: Some(e), .. }, _) - | ExprKind::Cast(e, _) - | ExprKind::Unary(_, e) => { + ExprKind::Block(&Block { expr: Some(e), .. }, _) | ExprKind::Cast(e, _) | ExprKind::Unary(_, e) => { helper(typeck, true, e, f)?; }, ExprKind::Call(callee, args) => { diff --git a/rust-toolchain b/rust-toolchain index d788c6359d7..0b2458ea007 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2023-03-10" +channel = "nightly-2023-03-24" components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] diff --git a/tests/dogfood.rs b/tests/dogfood.rs index 9643c2c9707..3a5d478fa31 100644 --- a/tests/dogfood.rs +++ b/tests/dogfood.rs @@ -37,10 +37,10 @@ fn dogfood_clippy() { } assert!( - !failed_packages.is_empty(), + failed_packages.is_empty(), "Dogfood failed for packages `{}`", failed_packages.iter().format(", "), - ) + ); } #[test] diff --git a/tests/ui-internal/custom_ice_message.stderr b/tests/ui-internal/custom_ice_message.stderr index 7ed0ef0274f..b4619e980f3 100644 --- a/tests/ui-internal/custom_ice_message.stderr +++ b/tests/ui-internal/custom_ice_message.stderr @@ -9,3 +9,4 @@ note: we would appreciate a bug report: https://github.com/rust-lang/rust-clippy note: Clippy version: foo +thread panicked while panicking. aborting. diff --git a/tests/ui-toml/ifs_same_cond/clippy.toml b/tests/ui-toml/ifs_same_cond/clippy.toml new file mode 100644 index 00000000000..90a36ecd920 --- /dev/null +++ b/tests/ui-toml/ifs_same_cond/clippy.toml @@ -0,0 +1 @@ +ignore-interior-mutability = ["std::cell::Cell"] diff --git a/tests/ui-toml/ifs_same_cond/ifs_same_cond.rs b/tests/ui-toml/ifs_same_cond/ifs_same_cond.rs new file mode 100644 index 00000000000..d623ac7e020 --- /dev/null +++ b/tests/ui-toml/ifs_same_cond/ifs_same_cond.rs @@ -0,0 +1,18 @@ +#![warn(clippy::ifs_same_cond)] +#![allow(clippy::if_same_then_else, clippy::comparison_chain)] + +fn main() {} + +fn issue10272() { + use std::cell::Cell; + + // Because the `ignore-interior-mutability` configuration + // is set to ignore for `std::cell::Cell`, the following `get()` calls + // should trigger warning + let x = Cell::new(true); + if x.get() { + } else if !x.take() { + } else if x.get() { + } else { + } +} diff --git a/tests/ui-toml/ifs_same_cond/ifs_same_cond.stderr b/tests/ui-toml/ifs_same_cond/ifs_same_cond.stderr new file mode 100644 index 00000000000..2841f62bc94 --- /dev/null +++ b/tests/ui-toml/ifs_same_cond/ifs_same_cond.stderr @@ -0,0 +1,15 @@ +error: this `if` has the same condition as a previous `if` + --> $DIR/ifs_same_cond.rs:15:15 + | +LL | } else if x.get() { + | ^^^^^^^ + | +note: same as this + --> $DIR/ifs_same_cond.rs:13:8 + | +LL | if x.get() { + | ^^^^^^^ + = note: `-D clippy::ifs-same-cond` implied by `-D warnings` + +error: aborting due to previous error + diff --git a/tests/ui/allow_attributes.fixed b/tests/ui/allow_attributes.fixed new file mode 100644 index 00000000000..b8dd0619e6d --- /dev/null +++ b/tests/ui/allow_attributes.fixed @@ -0,0 +1,25 @@ +// run-rustfix +#![allow(unused)] +#![warn(clippy::allow_attributes)] +#![feature(lint_reasons)] + +fn main() {} + +// Using clippy::needless_borrow just as a placeholder, it isn't relevant. + +// Should lint +#[expect(dead_code)] +struct T1; + +struct T2; // Should not lint +#[deny(clippy::needless_borrow)] // Should not lint +struct T3; +#[warn(clippy::needless_borrow)] // Should not lint +struct T4; +// `panic = "unwind"` should always be true +#[cfg_attr(panic = "unwind", expect(dead_code))] +struct CfgT; + +fn ignore_inner_attr() { + #![allow(unused)] // Should not lint +} diff --git a/tests/ui/allow_attributes.rs b/tests/ui/allow_attributes.rs new file mode 100644 index 00000000000..295f560906a --- /dev/null +++ b/tests/ui/allow_attributes.rs @@ -0,0 +1,25 @@ +// run-rustfix +#![allow(unused)] +#![warn(clippy::allow_attributes)] +#![feature(lint_reasons)] + +fn main() {} + +// Using clippy::needless_borrow just as a placeholder, it isn't relevant. + +// Should lint +#[allow(dead_code)] +struct T1; + +struct T2; // Should not lint +#[deny(clippy::needless_borrow)] // Should not lint +struct T3; +#[warn(clippy::needless_borrow)] // Should not lint +struct T4; +// `panic = "unwind"` should always be true +#[cfg_attr(panic = "unwind", allow(dead_code))] +struct CfgT; + +fn ignore_inner_attr() { + #![allow(unused)] // Should not lint +} diff --git a/tests/ui/allow_attributes.stderr b/tests/ui/allow_attributes.stderr new file mode 100644 index 00000000000..681837e9ed7 --- /dev/null +++ b/tests/ui/allow_attributes.stderr @@ -0,0 +1,16 @@ +error: #[allow] attribute found + --> $DIR/allow_attributes.rs:11:3 + | +LL | #[allow(dead_code)] + | ^^^^^ help: replace it with: `expect` + | + = note: `-D clippy::allow-attributes` implied by `-D warnings` + +error: #[allow] attribute found + --> $DIR/allow_attributes.rs:20:30 + | +LL | #[cfg_attr(panic = "unwind", allow(dead_code))] + | ^^^^^ help: replace it with: `expect` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/almost_complete_range.fixed b/tests/ui/almost_complete_range.fixed index 6046addf719..a4bf7fe18d5 100644 --- a/tests/ui/almost_complete_range.fixed +++ b/tests/ui/almost_complete_range.fixed @@ -1,6 +1,6 @@ // run-rustfix // edition:2018 -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs #![feature(exclusive_range_pattern)] #![feature(stmt_expr_attributes)] @@ -9,33 +9,10 @@ #![allow(clippy::needless_parens_on_range_literals)] #![allow(clippy::double_parens)] -#[macro_use] -extern crate macro_rules; - -macro_rules! a { - () => { - 'a' - }; -} -macro_rules! A { - () => { - 'A' - }; -} -macro_rules! zero { - () => { - '0' - }; -} - -macro_rules! b { - () => { - let _ = 'a'..='z'; - let _ = 'A'..='Z'; - let _ = '0'..='9'; - }; -} +extern crate proc_macros; +use proc_macros::{external, inline_macros}; +#[inline_macros] fn main() { #[rustfmt::skip] { @@ -56,9 +33,9 @@ fn main() { let _ = b'B'..b'Z'; let _ = b'1'..b'9'; - let _ = a!()..='z'; - let _ = A!()..='Z'; - let _ = zero!()..='9'; + let _ = inline!('a')..='z'; + let _ = inline!('A')..='Z'; + let _ = inline!('0')..='9'; let _ = match 0u8 { b'a'..=b'z' if true => 1, @@ -80,8 +57,16 @@ fn main() { _ => 7, }; - almost_complete_range!(); - b!(); + external!( + let _ = 'a'..'z'; + let _ = 'A'..'Z'; + let _ = '0'..'9'; + ); + inline!( + let _ = 'a'..='z'; + let _ = 'A'..='Z'; + let _ = '0'..='9'; + ); } #[clippy::msrv = "1.25"] diff --git a/tests/ui/almost_complete_range.rs b/tests/ui/almost_complete_range.rs index ae7e07ab872..8237c3a1361 100644 --- a/tests/ui/almost_complete_range.rs +++ b/tests/ui/almost_complete_range.rs @@ -1,6 +1,6 @@ // run-rustfix // edition:2018 -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs #![feature(exclusive_range_pattern)] #![feature(stmt_expr_attributes)] @@ -9,33 +9,10 @@ #![allow(clippy::needless_parens_on_range_literals)] #![allow(clippy::double_parens)] -#[macro_use] -extern crate macro_rules; - -macro_rules! a { - () => { - 'a' - }; -} -macro_rules! A { - () => { - 'A' - }; -} -macro_rules! zero { - () => { - '0' - }; -} - -macro_rules! b { - () => { - let _ = 'a'..'z'; - let _ = 'A'..'Z'; - let _ = '0'..'9'; - }; -} +extern crate proc_macros; +use proc_macros::{external, inline_macros}; +#[inline_macros] fn main() { #[rustfmt::skip] { @@ -56,9 +33,9 @@ fn main() { let _ = b'B'..b'Z'; let _ = b'1'..b'9'; - let _ = a!()..'z'; - let _ = A!()..'Z'; - let _ = zero!()..'9'; + let _ = inline!('a')..'z'; + let _ = inline!('A')..'Z'; + let _ = inline!('0')..'9'; let _ = match 0u8 { b'a'..b'z' if true => 1, @@ -80,8 +57,16 @@ fn main() { _ => 7, }; - almost_complete_range!(); - b!(); + external!( + let _ = 'a'..'z'; + let _ = 'A'..'Z'; + let _ = '0'..'9'; + ); + inline!( + let _ = 'a'..'z'; + let _ = 'A'..'Z'; + let _ = '0'..'9'; + ); } #[clippy::msrv = "1.25"] diff --git a/tests/ui/almost_complete_range.stderr b/tests/ui/almost_complete_range.stderr index a7a53287850..34521c13ab3 100644 --- a/tests/ui/almost_complete_range.stderr +++ b/tests/ui/almost_complete_range.stderr @@ -1,5 +1,5 @@ error: almost complete ascii range - --> $DIR/almost_complete_range.rs:42:17 + --> $DIR/almost_complete_range.rs:19:17 | LL | let _ = ('a') ..'z'; | ^^^^^^--^^^ @@ -9,7 +9,7 @@ LL | let _ = ('a') ..'z'; = note: `-D clippy::almost-complete-range` implied by `-D warnings` error: almost complete ascii range - --> $DIR/almost_complete_range.rs:43:17 + --> $DIR/almost_complete_range.rs:20:17 | LL | let _ = 'A' .. ('Z'); | ^^^^--^^^^^^ @@ -17,7 +17,7 @@ LL | let _ = 'A' .. ('Z'); | help: use an inclusive range: `..=` error: almost complete ascii range - --> $DIR/almost_complete_range.rs:44:17 + --> $DIR/almost_complete_range.rs:21:17 | LL | let _ = ((('0'))) .. ('9'); | ^^^^^^^^^^--^^^^^^ @@ -25,7 +25,7 @@ LL | let _ = ((('0'))) .. ('9'); | help: use an inclusive range: `..=` error: almost complete ascii range - --> $DIR/almost_complete_range.rs:51:13 + --> $DIR/almost_complete_range.rs:28:13 | LL | let _ = (b'a')..(b'z'); | ^^^^^^--^^^^^^ @@ -33,7 +33,7 @@ LL | let _ = (b'a')..(b'z'); | help: use an inclusive range: `..=` error: almost complete ascii range - --> $DIR/almost_complete_range.rs:52:13 + --> $DIR/almost_complete_range.rs:29:13 | LL | let _ = b'A'..b'Z'; | ^^^^--^^^^ @@ -41,7 +41,7 @@ LL | let _ = b'A'..b'Z'; | help: use an inclusive range: `..=` error: almost complete ascii range - --> $DIR/almost_complete_range.rs:53:13 + --> $DIR/almost_complete_range.rs:30:13 | LL | let _ = b'0'..b'9'; | ^^^^--^^^^ @@ -49,31 +49,31 @@ LL | let _ = b'0'..b'9'; | help: use an inclusive range: `..=` error: almost complete ascii range - --> $DIR/almost_complete_range.rs:59:13 + --> $DIR/almost_complete_range.rs:36:13 | -LL | let _ = a!()..'z'; - | ^^^^--^^^ - | | - | help: use an inclusive range: `..=` +LL | let _ = inline!('a')..'z'; + | ^^^^^^^^^^^^--^^^ + | | + | help: use an inclusive range: `..=` error: almost complete ascii range - --> $DIR/almost_complete_range.rs:60:13 + --> $DIR/almost_complete_range.rs:37:13 | -LL | let _ = A!()..'Z'; - | ^^^^--^^^ - | | - | help: use an inclusive range: `..=` +LL | let _ = inline!('A')..'Z'; + | ^^^^^^^^^^^^--^^^ + | | + | help: use an inclusive range: `..=` error: almost complete ascii range - --> $DIR/almost_complete_range.rs:61:13 + --> $DIR/almost_complete_range.rs:38:13 | -LL | let _ = zero!()..'9'; - | ^^^^^^^--^^^ - | | - | help: use an inclusive range: `..=` +LL | let _ = inline!('0')..'9'; + | ^^^^^^^^^^^^--^^^ + | | + | help: use an inclusive range: `..=` error: almost complete ascii range - --> $DIR/almost_complete_range.rs:64:9 + --> $DIR/almost_complete_range.rs:41:9 | LL | b'a'..b'z' if true => 1, | ^^^^--^^^^ @@ -81,7 +81,7 @@ LL | b'a'..b'z' if true => 1, | help: use an inclusive range: `..=` error: almost complete ascii range - --> $DIR/almost_complete_range.rs:65:9 + --> $DIR/almost_complete_range.rs:42:9 | LL | b'A'..b'Z' if true => 2, | ^^^^--^^^^ @@ -89,7 +89,7 @@ LL | b'A'..b'Z' if true => 2, | help: use an inclusive range: `..=` error: almost complete ascii range - --> $DIR/almost_complete_range.rs:66:9 + --> $DIR/almost_complete_range.rs:43:9 | LL | b'0'..b'9' if true => 3, | ^^^^--^^^^ @@ -97,7 +97,7 @@ LL | b'0'..b'9' if true => 3, | help: use an inclusive range: `..=` error: almost complete ascii range - --> $DIR/almost_complete_range.rs:74:9 + --> $DIR/almost_complete_range.rs:51:9 | LL | 'a'..'z' if true => 1, | ^^^--^^^ @@ -105,7 +105,7 @@ LL | 'a'..'z' if true => 1, | help: use an inclusive range: `..=` error: almost complete ascii range - --> $DIR/almost_complete_range.rs:75:9 + --> $DIR/almost_complete_range.rs:52:9 | LL | 'A'..'Z' if true => 2, | ^^^--^^^ @@ -113,7 +113,7 @@ LL | 'A'..'Z' if true => 2, | help: use an inclusive range: `..=` error: almost complete ascii range - --> $DIR/almost_complete_range.rs:76:9 + --> $DIR/almost_complete_range.rs:53:9 | LL | '0'..'9' if true => 3, | ^^^--^^^ @@ -121,46 +121,37 @@ LL | '0'..'9' if true => 3, | help: use an inclusive range: `..=` error: almost complete ascii range - --> $DIR/almost_complete_range.rs:33:17 + --> $DIR/almost_complete_range.rs:66:17 | LL | let _ = 'a'..'z'; | ^^^--^^^ | | | help: use an inclusive range: `..=` -... -LL | b!(); - | ---- in this macro invocation | - = note: this error originates in the macro `b` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info) error: almost complete ascii range - --> $DIR/almost_complete_range.rs:34:17 + --> $DIR/almost_complete_range.rs:67:17 | LL | let _ = 'A'..'Z'; | ^^^--^^^ | | | help: use an inclusive range: `..=` -... -LL | b!(); - | ---- in this macro invocation | - = note: this error originates in the macro `b` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info) error: almost complete ascii range - --> $DIR/almost_complete_range.rs:35:17 + --> $DIR/almost_complete_range.rs:68:17 | LL | let _ = '0'..'9'; | ^^^--^^^ | | | help: use an inclusive range: `..=` -... -LL | b!(); - | ---- in this macro invocation | - = note: this error originates in the macro `b` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info) error: almost complete ascii range - --> $DIR/almost_complete_range.rs:90:9 + --> $DIR/almost_complete_range.rs:75:9 | LL | 'a'..'z' => 1, | ^^^--^^^ @@ -168,7 +159,7 @@ LL | 'a'..'z' => 1, | help: use an inclusive range: `...` error: almost complete ascii range - --> $DIR/almost_complete_range.rs:91:9 + --> $DIR/almost_complete_range.rs:76:9 | LL | 'A'..'Z' => 2, | ^^^--^^^ @@ -176,7 +167,7 @@ LL | 'A'..'Z' => 2, | help: use an inclusive range: `...` error: almost complete ascii range - --> $DIR/almost_complete_range.rs:92:9 + --> $DIR/almost_complete_range.rs:77:9 | LL | '0'..'9' => 3, | ^^^--^^^ @@ -184,7 +175,7 @@ LL | '0'..'9' => 3, | help: use an inclusive range: `...` error: almost complete ascii range - --> $DIR/almost_complete_range.rs:99:13 + --> $DIR/almost_complete_range.rs:84:13 | LL | let _ = 'a'..'z'; | ^^^--^^^ @@ -192,7 +183,7 @@ LL | let _ = 'a'..'z'; | help: use an inclusive range: `..=` error: almost complete ascii range - --> $DIR/almost_complete_range.rs:100:13 + --> $DIR/almost_complete_range.rs:85:13 | LL | let _ = 'A'..'Z'; | ^^^--^^^ @@ -200,7 +191,7 @@ LL | let _ = 'A'..'Z'; | help: use an inclusive range: `..=` error: almost complete ascii range - --> $DIR/almost_complete_range.rs:101:13 + --> $DIR/almost_complete_range.rs:86:13 | LL | let _ = '0'..'9'; | ^^^--^^^ @@ -208,7 +199,7 @@ LL | let _ = '0'..'9'; | help: use an inclusive range: `..=` error: almost complete ascii range - --> $DIR/almost_complete_range.rs:103:9 + --> $DIR/almost_complete_range.rs:88:9 | LL | 'a'..'z' => 1, | ^^^--^^^ @@ -216,7 +207,7 @@ LL | 'a'..'z' => 1, | help: use an inclusive range: `..=` error: almost complete ascii range - --> $DIR/almost_complete_range.rs:104:9 + --> $DIR/almost_complete_range.rs:89:9 | LL | 'A'..'Z' => 1, | ^^^--^^^ @@ -224,7 +215,7 @@ LL | 'A'..'Z' => 1, | help: use an inclusive range: `..=` error: almost complete ascii range - --> $DIR/almost_complete_range.rs:105:9 + --> $DIR/almost_complete_range.rs:90:9 | LL | '0'..'9' => 3, | ^^^--^^^ diff --git a/tests/ui/as_conversions.rs b/tests/ui/as_conversions.rs index ba4394defbf..c50d4088b5e 100644 --- a/tests/ui/as_conversions.rs +++ b/tests/ui/as_conversions.rs @@ -1,20 +1,15 @@ -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs #![warn(clippy::as_conversions)] #![allow(clippy::borrow_as_ptr)] -#[macro_use] -extern crate macro_rules; - -fn with_external_macro() { - as_conv_with_arg!(0u32 as u64); - as_conv!(); -} +extern crate proc_macros; +use proc_macros::external; fn main() { let i = 0u32 as u64; let j = &i as *const u64 as *mut u64; - with_external_macro(); + external!(0u32 as u64); } diff --git a/tests/ui/as_conversions.stderr b/tests/ui/as_conversions.stderr index f5d59e1e5d8..54037a64997 100644 --- a/tests/ui/as_conversions.stderr +++ b/tests/ui/as_conversions.stderr @@ -1,5 +1,5 @@ error: using a potentially dangerous silent `as` conversion - --> $DIR/as_conversions.rs:15:13 + --> $DIR/as_conversions.rs:10:13 | LL | let i = 0u32 as u64; | ^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | let i = 0u32 as u64; = note: `-D clippy::as-conversions` implied by `-D warnings` error: using a potentially dangerous silent `as` conversion - --> $DIR/as_conversions.rs:17:13 + --> $DIR/as_conversions.rs:12:13 | LL | let j = &i as *const u64 as *mut u64; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -16,7 +16,7 @@ LL | let j = &i as *const u64 as *mut u64; = help: consider using a safe wrapper for this conversion error: using a potentially dangerous silent `as` conversion - --> $DIR/as_conversions.rs:17:13 + --> $DIR/as_conversions.rs:12:13 | LL | let j = &i as *const u64 as *mut u64; | ^^^^^^^^^^^^^^^^ diff --git a/tests/ui/auxiliary/doc_unsafe_macros.rs b/tests/ui/auxiliary/doc_unsafe_macros.rs deleted file mode 100644 index 3d917e3dc75..00000000000 --- a/tests/ui/auxiliary/doc_unsafe_macros.rs +++ /dev/null @@ -1,16 +0,0 @@ -#[macro_export] -macro_rules! undocd_unsafe { - () => { - pub unsafe fn oy_vey() { - unimplemented!(); - } - }; -} -#[macro_export] -macro_rules! undocd_safe { - () => { - pub fn vey_oy() { - unimplemented!(); - } - }; -} diff --git a/tests/ui/auxiliary/implicit_hasher_macros.rs b/tests/ui/auxiliary/implicit_hasher_macros.rs deleted file mode 100644 index 1eb77c53183..00000000000 --- a/tests/ui/auxiliary/implicit_hasher_macros.rs +++ /dev/null @@ -1,6 +0,0 @@ -#[macro_export] -macro_rules! implicit_hasher_fn { - () => { - pub fn f(input: &HashMap) {} - }; -} diff --git a/tests/ui/auxiliary/macro_rules.rs b/tests/ui/auxiliary/macro_rules.rs index a13af565203..a9bb61451dc 100644 --- a/tests/ui/auxiliary/macro_rules.rs +++ b/tests/ui/auxiliary/macro_rules.rs @@ -2,21 +2,6 @@ //! Used to test that certain lints don't trigger in imported external macros -#[macro_export] -macro_rules! foofoo { - () => { - loop {} - }; -} - -#[macro_export] -macro_rules! must_use_unit { - () => { - #[must_use] - fn foo() {} - }; -} - #[macro_export] macro_rules! try_err { () => { @@ -36,84 +21,6 @@ macro_rules! string_add { }; } -#[macro_export] -macro_rules! take_external { - ($s:expr) => { - std::mem::replace($s, Default::default()) - }; -} - -#[macro_export] -macro_rules! option_env_unwrap_external { - ($env: expr) => { - option_env!($env).unwrap() - }; - ($env: expr, $message: expr) => { - option_env!($env).expect($message) - }; -} - -#[macro_export] -macro_rules! ref_arg_binding { - () => { - let ref _y = 42; - }; -} - -#[macro_export] -macro_rules! ref_arg_function { - () => { - fn fun_example(ref _x: usize) {} - }; -} - -#[macro_export] -macro_rules! as_conv_with_arg { - (0u32 as u64) => { - () - }; -} - -#[macro_export] -macro_rules! as_conv { - () => { - 0u32 as u64 - }; -} - -#[macro_export] -macro_rules! large_enum_variant { - () => { - enum LargeEnumInMacro { - A(i32), - B([i32; 8000]), - } - }; -} - -#[macro_export] -macro_rules! field_reassign_with_default { - () => { - #[derive(Default)] - struct A { - pub i: i32, - pub j: i64, - } - fn lint() { - let mut a: A = Default::default(); - a.i = 42; - a; - } - }; -} - -#[macro_export] -macro_rules! default_numeric_fallback { - () => { - let x = 22; - }; -} - #[macro_export] macro_rules! mut_mut { () => { @@ -122,49 +29,11 @@ macro_rules! mut_mut { } #[macro_export] -macro_rules! ptr_as_ptr_cast { - ($ptr: ident) => { - $ptr as *const i32 - }; -} - -#[macro_export] -macro_rules! manual_rem_euclid { +macro_rules! issue_10421 { () => { - let value: i32 = 5; - let _: i32 = ((value % 4) + 4) % 4; - }; -} - -#[macro_export] -macro_rules! equatable_if_let { - ($a:ident) => {{ if let 2 = $a {} }}; -} - -#[macro_export] -macro_rules! almost_complete_range { - () => { - let _ = 'a'..'z'; - let _ = 'A'..'Z'; - let _ = '0'..'9'; - }; -} - -#[macro_export] -macro_rules! unsafe_macro { - () => { - unsafe { - *core::ptr::null::<()>(); - *core::ptr::null::<()>(); - } - }; -} - -#[macro_export] -macro_rules! needless_lifetime { - () => { - fn needless_lifetime<'a>(x: &'a u8) -> &'a u8 { - unimplemented!() - } + let mut a = 1; + let mut b = 2; + a = b; + b = a; }; } diff --git a/tests/ui/auxiliary/macro_use_helper.rs b/tests/ui/auxiliary/macro_use_helper.rs index ecb55d8cb48..7ed8a28dbd9 100644 --- a/tests/ui/auxiliary/macro_use_helper.rs +++ b/tests/ui/auxiliary/macro_use_helper.rs @@ -13,7 +13,7 @@ pub mod inner { // RE-EXPORT // this will stick in `inner` module - pub use macro_rules::foofoo; + pub use macro_rules::mut_mut; pub use macro_rules::try_err; pub mod nested { diff --git a/tests/ui/auxiliary/proc_macro_with_span.rs b/tests/ui/auxiliary/proc_macro_with_span.rs deleted file mode 100644 index 8ea631f2bbd..00000000000 --- a/tests/ui/auxiliary/proc_macro_with_span.rs +++ /dev/null @@ -1,32 +0,0 @@ -// compile-flags: --emit=link -// no-prefer-dynamic - -#![crate_type = "proc-macro"] - -extern crate proc_macro; - -use proc_macro::{token_stream::IntoIter, Group, Span, TokenStream, TokenTree}; - -#[proc_macro] -pub fn with_span(input: TokenStream) -> TokenStream { - let mut iter = input.into_iter(); - let span = iter.next().unwrap().span(); - let mut res = TokenStream::new(); - write_with_span(span, iter, &mut res); - res -} - -fn write_with_span(s: Span, input: IntoIter, out: &mut TokenStream) { - for mut tt in input { - if let TokenTree::Group(g) = tt { - let mut stream = TokenStream::new(); - write_with_span(s, g.stream().into_iter(), &mut stream); - let mut group = Group::new(g.delimiter(), stream); - group.set_span(s); - out.extend([TokenTree::Group(group)]); - } else { - tt.set_span(s); - out.extend([tt]); - } - } -} diff --git a/tests/ui/auxiliary/proc_macros.rs b/tests/ui/auxiliary/proc_macros.rs new file mode 100644 index 00000000000..325be83a0d7 --- /dev/null +++ b/tests/ui/auxiliary/proc_macros.rs @@ -0,0 +1,474 @@ +// compile-flags: --emit=link +// no-prefer-dynamic + +#![crate_type = "proc-macro"] +#![feature(let_chains)] +#![feature(proc_macro_span)] +#![allow(dead_code)] + +extern crate proc_macro; + +use core::mem; +use proc_macro::{ + token_stream::IntoIter, + Delimiter::{self, Brace, Parenthesis}, + Group, Ident, Literal, Punct, + Spacing::{self, Alone, Joint}, + Span, TokenStream, TokenTree as TT, +}; + +type Result = core::result::Result; + +/// Make a `compile_error!` pointing to the given span. +fn make_error(msg: &str, span: Span) -> TokenStream { + TokenStream::from_iter([ + TT::Ident(Ident::new("compile_error", span)), + TT::Punct(punct_with_span('!', Alone, span)), + TT::Group({ + let mut msg = Literal::string(msg); + msg.set_span(span); + group_with_span(Parenthesis, TokenStream::from_iter([TT::Literal(msg)]), span) + }), + ]) +} + +fn expect_tt(tt: Option, f: impl FnOnce(TT) -> Option, expected: &str, span: Span) -> Result { + match tt { + None => Err(make_error( + &format!("unexpected end of input, expected {expected}"), + span, + )), + Some(tt) => { + let span = tt.span(); + match f(tt) { + Some(x) => Ok(x), + None => Err(make_error(&format!("unexpected token, expected {expected}"), span)), + } + }, + } +} + +fn punct_with_span(c: char, spacing: Spacing, span: Span) -> Punct { + let mut p = Punct::new(c, spacing); + p.set_span(span); + p +} + +fn group_with_span(delimiter: Delimiter, stream: TokenStream, span: Span) -> Group { + let mut g = Group::new(delimiter, stream); + g.set_span(span); + g +} + +/// Token used to escape the following token from the macro's span rules. +const ESCAPE_CHAR: char = '$'; + +/// Takes a single token followed by a sequence tokens. Returns the sequence of tokens with their +/// span set to that of the first token. Tokens may be escaped with either `#ident` or `#(tokens)`. +#[proc_macro] +pub fn with_span(input: TokenStream) -> TokenStream { + let mut iter = input.into_iter(); + let span = iter.next().unwrap().span(); + let mut res = TokenStream::new(); + if let Err(e) = write_with_span(span, iter, &mut res) { + e + } else { + res + } +} + +/// Takes a sequence of tokens and return the tokens with the span set such that they appear to be +/// from an external macro. Tokens may be escaped with either `#ident` or `#(tokens)`. +#[proc_macro] +pub fn external(input: TokenStream) -> TokenStream { + let mut res = TokenStream::new(); + if let Err(e) = write_with_span(Span::mixed_site(), input.into_iter(), &mut res) { + e + } else { + res + } +} + +/// Copies all the tokens, replacing all their spans with the given span. Tokens can be escaped +/// either by `#ident` or `#(tokens)`. +fn write_with_span(s: Span, mut input: IntoIter, out: &mut TokenStream) -> Result<()> { + while let Some(tt) = input.next() { + match tt { + TT::Punct(p) if p.as_char() == ESCAPE_CHAR => { + expect_tt( + input.next(), + |tt| match tt { + tt @ (TT::Ident(_) | TT::Literal(_)) => { + out.extend([tt]); + Some(()) + }, + TT::Punct(mut p) if p.as_char() == ESCAPE_CHAR => { + p.set_span(s); + out.extend([TT::Punct(p)]); + Some(()) + }, + TT::Group(g) if g.delimiter() == Parenthesis => { + out.extend([TT::Group(group_with_span(Delimiter::None, g.stream(), g.span()))]); + Some(()) + }, + _ => None, + }, + "an ident, a literal, or parenthesized tokens", + p.span(), + )?; + }, + TT::Group(g) => { + let mut stream = TokenStream::new(); + write_with_span(s, g.stream().into_iter(), &mut stream)?; + out.extend([TT::Group(group_with_span(g.delimiter(), stream, s))]); + }, + mut tt => { + tt.set_span(s); + out.extend([tt]); + }, + } + } + Ok(()) +} + +/// Within the item this attribute is attached to, an `inline!` macro is available which expands the +/// contained tokens as though they came from a macro expansion. +/// +/// Within the `inline!` macro, any token preceded by `$` is passed as though it were an argument +/// with an automatically chosen fragment specifier. `$ident` will be passed as `ident`, `$1` or +/// `$"literal"` will be passed as `literal`, `$'lt` will be passed as `lifetime`, and `$(...)` will +/// pass the contained tokens as a `tt` sequence (the wrapping parenthesis are removed). If another +/// specifier is required it can be specified within parenthesis like `$(@expr ...)`. This will +/// expand the remaining tokens as a single argument. +/// +/// Multiple `inline!` macros may be nested within each other. This will expand as nested macro +/// calls. However, any arguments will be passed as though they came from the outermost context. +#[proc_macro_attribute] +pub fn inline_macros(args: TokenStream, input: TokenStream) -> TokenStream { + let mut args = args.into_iter(); + let mac_name = match args.next() { + Some(TT::Ident(name)) => Some(name), + Some(tt) => { + return make_error( + "unexpected argument, expected either an ident or no arguments", + tt.span(), + ); + }, + None => None, + }; + if let Some(tt) = args.next() { + return make_error( + "unexpected argument, expected either an ident or no arguments", + tt.span(), + ); + }; + + let mac_name = if let Some(mac_name) = mac_name { + Ident::new(&format!("__inline_mac_{mac_name}"), Span::call_site()) + } else { + let mut input = match LookaheadIter::new(input.clone().into_iter()) { + Some(x) => x, + None => return input, + }; + loop { + match input.next() { + None => break Ident::new("__inline_mac", Span::call_site()), + Some(TT::Ident(kind)) => match &*kind.to_string() { + "impl" => break Ident::new("__inline_mac_impl", Span::call_site()), + kind @ ("struct" | "enum" | "union" | "fn" | "mod" | "trait" | "type" | "const" | "static") => { + if let TT::Ident(name) = &input.tt { + break Ident::new(&format!("__inline_mac_{kind}_{name}"), Span::call_site()); + } else { + break Ident::new(&format!("__inline_mac_{kind}"), Span::call_site()); + } + }, + _ => {}, + }, + _ => {}, + } + } + }; + + let mut expander = Expander::default(); + let mut mac = MacWriter::new(mac_name); + if let Err(e) = expander.expand(input.into_iter(), &mut mac) { + return e; + } + let mut out = TokenStream::new(); + mac.finish(&mut out); + out.extend(expander.expn); + out +} + +/// Wraps a `TokenStream` iterator with a single token lookahead. +struct LookaheadIter { + tt: TT, + iter: IntoIter, +} +impl LookaheadIter { + fn new(mut iter: IntoIter) -> Option { + iter.next().map(|tt| Self { tt, iter }) + } + + /// Get's the lookahead token, replacing it with the next token in the stream. + /// Note: If there isn't a next token, this will not return the lookahead token. + fn next(&mut self) -> Option { + self.iter.next().map(|tt| mem::replace(&mut self.tt, tt)) + } +} + +/// Builds the macro used to implement all the `inline!` macro calls. +struct MacWriter { + name: Ident, + macros: TokenStream, + next_idx: usize, +} +impl MacWriter { + fn new(name: Ident) -> Self { + Self { + name, + macros: TokenStream::new(), + next_idx: 0, + } + } + + /// Inserts a new `inline!` call. + fn insert(&mut self, name_span: Span, bang_span: Span, body: Group, expander: &mut Expander) -> Result<()> { + let idx = self.next_idx; + self.next_idx += 1; + + let mut inner = Expander::for_arm(idx); + inner.expand(body.stream().into_iter(), self)?; + let new_arm = inner.arm.unwrap(); + + self.macros.extend([ + TT::Group(Group::new(Parenthesis, new_arm.args_def)), + TT::Punct(Punct::new('=', Joint)), + TT::Punct(Punct::new('>', Alone)), + TT::Group(Group::new(Parenthesis, inner.expn)), + TT::Punct(Punct::new(';', Alone)), + ]); + + expander.expn.extend([ + TT::Ident({ + let mut name = self.name.clone(); + name.set_span(name_span); + name + }), + TT::Punct(punct_with_span('!', Alone, bang_span)), + ]); + let mut call_body = TokenStream::from_iter([TT::Literal(Literal::usize_unsuffixed(idx))]); + if let Some(arm) = expander.arm.as_mut() { + if !new_arm.args.is_empty() { + arm.add_sub_args(new_arm.args, &mut call_body); + } + } else { + call_body.extend(new_arm.args); + } + let mut g = Group::new(body.delimiter(), call_body); + g.set_span(body.span()); + expander.expn.extend([TT::Group(g)]); + Ok(()) + } + + /// Creates the macro definition. + fn finish(self, out: &mut TokenStream) { + if self.next_idx != 0 { + out.extend([ + TT::Ident(Ident::new("macro_rules", Span::call_site())), + TT::Punct(Punct::new('!', Alone)), + TT::Ident(self.name), + TT::Group(Group::new(Brace, self.macros)), + ]) + } + } +} + +struct MacroArm { + args_def: TokenStream, + args: Vec, +} +impl MacroArm { + fn add_single_arg_def(&mut self, kind: &str, dollar_span: Span, arg_span: Span, out: &mut TokenStream) { + let mut name = Ident::new(&format!("_{}", self.args.len()), Span::call_site()); + self.args_def.extend([ + TT::Punct(Punct::new('$', Alone)), + TT::Ident(name.clone()), + TT::Punct(Punct::new(':', Alone)), + TT::Ident(Ident::new(kind, Span::call_site())), + ]); + name.set_span(arg_span); + out.extend([TT::Punct(punct_with_span('$', Alone, dollar_span)), TT::Ident(name)]); + } + + fn add_parenthesized_arg_def(&mut self, kind: Ident, dollar_span: Span, arg_span: Span, out: &mut TokenStream) { + let mut name = Ident::new(&format!("_{}", self.args.len()), Span::call_site()); + self.args_def.extend([TT::Group(Group::new( + Parenthesis, + TokenStream::from_iter([ + TT::Punct(Punct::new('$', Alone)), + TT::Ident(name.clone()), + TT::Punct(Punct::new(':', Alone)), + TT::Ident(kind), + ]), + ))]); + name.set_span(arg_span); + out.extend([TT::Punct(punct_with_span('$', Alone, dollar_span)), TT::Ident(name)]); + } + + fn add_multi_arg_def(&mut self, dollar_span: Span, arg_span: Span, out: &mut TokenStream) { + let mut name = Ident::new(&format!("_{}", self.args.len()), Span::call_site()); + self.args_def.extend([TT::Group(Group::new( + Parenthesis, + TokenStream::from_iter([ + TT::Punct(Punct::new('$', Alone)), + TT::Group(Group::new( + Parenthesis, + TokenStream::from_iter([ + TT::Punct(Punct::new('$', Alone)), + TT::Ident(name.clone()), + TT::Punct(Punct::new(':', Alone)), + TT::Ident(Ident::new("tt", Span::call_site())), + ]), + )), + TT::Punct(Punct::new('*', Alone)), + ]), + ))]); + name.set_span(arg_span); + out.extend([ + TT::Punct(punct_with_span('$', Alone, dollar_span)), + TT::Group(group_with_span( + Parenthesis, + TokenStream::from_iter([TT::Punct(punct_with_span('$', Alone, dollar_span)), TT::Ident(name)]), + dollar_span, + )), + TT::Punct(punct_with_span('*', Alone, dollar_span)), + ]); + } + + fn add_arg(&mut self, dollar_span: Span, tt: TT, input: &mut IntoIter, out: &mut TokenStream) -> Result<()> { + match tt { + TT::Punct(p) if p.as_char() == ESCAPE_CHAR => out.extend([TT::Punct(p)]), + TT::Punct(p) if p.as_char() == '\'' && p.spacing() == Joint => { + let lt_name = expect_tt( + input.next(), + |tt| match tt { + TT::Ident(x) => Some(x), + _ => None, + }, + "lifetime name", + p.span(), + )?; + let arg_span = p.span().join(lt_name.span()).unwrap_or(p.span()); + self.add_single_arg_def("lifetime", dollar_span, arg_span, out); + self.args.extend([TT::Punct(p), TT::Ident(lt_name)]); + }, + TT::Ident(x) => { + self.add_single_arg_def("ident", dollar_span, x.span(), out); + self.args.push(TT::Ident(x)); + }, + TT::Literal(x) => { + self.add_single_arg_def("literal", dollar_span, x.span(), out); + self.args.push(TT::Literal(x)); + }, + TT::Group(g) if g.delimiter() == Parenthesis => { + let mut inner = g.stream().into_iter(); + if let Some(TT::Punct(p)) = inner.next() + && p.as_char() == '@' + { + let kind = expect_tt( + inner.next(), + |tt| match tt { + TT::Ident(kind) => Some(kind), + _ => None, + }, + "a macro fragment specifier", + p.span(), + )?; + self.add_parenthesized_arg_def(kind, dollar_span, g.span(), out); + self.args.push(TT::Group(group_with_span(Parenthesis, inner.collect(), g.span()))) + } else { + self.add_multi_arg_def(dollar_span, g.span(), out); + self.args.push(TT::Group(g)); + } + }, + tt => return Err(make_error("unsupported escape", tt.span())), + }; + Ok(()) + } + + fn add_sub_args(&mut self, args: Vec, out: &mut TokenStream) { + self.add_multi_arg_def(Span::call_site(), Span::call_site(), out); + self.args + .extend([TT::Group(Group::new(Parenthesis, TokenStream::from_iter(args)))]); + } +} + +#[derive(Default)] +struct Expander { + arm: Option, + expn: TokenStream, +} +impl Expander { + fn for_arm(idx: usize) -> Self { + Self { + arm: Some(MacroArm { + args_def: TokenStream::from_iter([TT::Literal(Literal::usize_unsuffixed(idx))]), + args: Vec::new(), + }), + expn: TokenStream::new(), + } + } + + fn write_tt(&mut self, tt: TT, mac: &mut MacWriter) -> Result<()> { + match tt { + TT::Group(g) => { + let outer = mem::take(&mut self.expn); + self.expand(g.stream().into_iter(), mac)?; + let inner = mem::replace(&mut self.expn, outer); + self.expn + .extend([TT::Group(group_with_span(g.delimiter(), inner, g.span()))]); + }, + tt => self.expn.extend([tt]), + } + Ok(()) + } + + fn expand(&mut self, input: IntoIter, mac: &mut MacWriter) -> Result<()> { + let Some(mut input) = LookaheadIter::new(input) else { + return Ok(()); + }; + while let Some(tt) = input.next() { + if let TT::Punct(p) = &tt + && p.as_char() == ESCAPE_CHAR + && let Some(arm) = self.arm.as_mut() + { + arm.add_arg(p.span(), mem::replace(&mut input.tt, tt), &mut input.iter, &mut self.expn)?; + if input.next().is_none() { + return Ok(()); + } + } else if let TT::Punct(p) = &input.tt + && p.as_char() == '!' + && let TT::Ident(name) = &tt + && name.to_string() == "inline" + { + let g = expect_tt( + input.iter.next(), + |tt| match tt { + TT::Group(g) => Some(g), + _ => None, + }, + "macro arguments", + p.span(), + )?; + mac.insert(name.span(), p.span(), g, self)?; + if input.next().is_none() { + return Ok(()); + } + } else { + self.write_tt(tt, mac)?; + } + } + self.write_tt(input.tt, mac) + } +} diff --git a/tests/ui/borrow_interior_mutable_const/auxiliary/helper.rs b/tests/ui/borrow_interior_mutable_const/auxiliary/helper.rs index f13733af3d0..b03c21262c3 100644 --- a/tests/ui/borrow_interior_mutable_const/auxiliary/helper.rs +++ b/tests/ui/borrow_interior_mutable_const/auxiliary/helper.rs @@ -1,5 +1,5 @@ // this file solely exists to test constants defined in foreign crates. -// As the most common case is the `http` crate, it replicates `http::HeadewrName`'s structure. +// As the most common case is the `http` crate, it replicates `http::HeaderName`'s structure. #![allow(clippy::declare_interior_mutable_const)] #![allow(unused_tuple_struct_fields)] diff --git a/tests/ui/crashes/ice-10148.rs b/tests/ui/crashes/ice-10148.rs index af33b10c693..1ab3570c907 100644 --- a/tests/ui/crashes/ice-10148.rs +++ b/tests/ui/crashes/ice-10148.rs @@ -1,8 +1,8 @@ -// aux-build:../../auxiliary/proc_macro_with_span.rs +// aux-build:../../auxiliary/proc_macros.rs -extern crate proc_macro_with_span; +extern crate proc_macros; -use proc_macro_with_span::with_span; +use proc_macros::with_span; fn main() { println!(with_span!(""something "")); diff --git a/tests/ui/default_numeric_fallback_f64.fixed b/tests/ui/default_numeric_fallback_f64.fixed index a9e5fd159af..42c15d6a70b 100644 --- a/tests/ui/default_numeric_fallback_f64.fixed +++ b/tests/ui/default_numeric_fallback_f64.fixed @@ -1,5 +1,5 @@ // run-rustfix -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs #![warn(clippy::default_numeric_fallback)] #![allow( @@ -13,8 +13,8 @@ clippy::let_with_type_underscore )] -#[macro_use] -extern crate macro_rules; +extern crate proc_macros; +use proc_macros::{external, inline_macros}; mod basic_expr { fn test() { @@ -167,20 +167,17 @@ mod method_calls { } mod in_macro { - macro_rules! internal_macro { - () => { - let x = 22.0_f64; - }; - } + use super::*; // Should lint in internal macro. + #[inline_macros] fn internal() { - internal_macro!(); + inline!(let x = 22.0_f64;); } // Should NOT lint in external macro. fn external() { - default_numeric_fallback!(); + external!(let x = 22.;); } } diff --git a/tests/ui/default_numeric_fallback_f64.rs b/tests/ui/default_numeric_fallback_f64.rs index 085f8f452b2..7da7ea254e9 100644 --- a/tests/ui/default_numeric_fallback_f64.rs +++ b/tests/ui/default_numeric_fallback_f64.rs @@ -1,5 +1,5 @@ // run-rustfix -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs #![warn(clippy::default_numeric_fallback)] #![allow( @@ -13,8 +13,8 @@ clippy::let_with_type_underscore )] -#[macro_use] -extern crate macro_rules; +extern crate proc_macros; +use proc_macros::{external, inline_macros}; mod basic_expr { fn test() { @@ -167,20 +167,17 @@ mod method_calls { } mod in_macro { - macro_rules! internal_macro { - () => { - let x = 22.; - }; - } + use super::*; // Should lint in internal macro. + #[inline_macros] fn internal() { - internal_macro!(); + inline!(let x = 22.;); } // Should NOT lint in external macro. fn external() { - default_numeric_fallback!(); + external!(let x = 22.;); } } diff --git a/tests/ui/default_numeric_fallback_f64.stderr b/tests/ui/default_numeric_fallback_f64.stderr index 44c6f1a9bea..b949cd1d50b 100644 --- a/tests/ui/default_numeric_fallback_f64.stderr +++ b/tests/ui/default_numeric_fallback_f64.stderr @@ -139,15 +139,12 @@ LL | s.generic_arg(1.); | ^^ help: consider adding suffix: `1.0_f64` error: default numeric fallback might occur - --> $DIR/default_numeric_fallback_f64.rs:172:21 + --> $DIR/default_numeric_fallback_f64.rs:175:25 | -LL | let x = 22.; - | ^^^ help: consider adding suffix: `22.0_f64` -... -LL | internal_macro!(); - | ----------------- in this macro invocation +LL | inline!(let x = 22.;); + | ^^^ help: consider adding suffix: `22.0_f64` | - = note: this error originates in the macro `internal_macro` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `__inline_mac_fn_internal` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 24 previous errors diff --git a/tests/ui/default_numeric_fallback_i32.fixed b/tests/ui/default_numeric_fallback_i32.fixed index 63ac4d5aeb6..b7485b73dcd 100644 --- a/tests/ui/default_numeric_fallback_i32.fixed +++ b/tests/ui/default_numeric_fallback_i32.fixed @@ -1,5 +1,5 @@ // run-rustfix -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs #![feature(lint_reasons)] #![warn(clippy::default_numeric_fallback)] @@ -13,8 +13,8 @@ clippy::let_with_type_underscore )] -#[macro_use] -extern crate macro_rules; +extern crate proc_macros; +use proc_macros::{external, inline_macros}; mod basic_expr { fn test() { @@ -168,20 +168,17 @@ mod method_calls { } mod in_macro { - macro_rules! internal_macro { - () => { - let x = 22_i32; - }; - } + use super::*; // Should lint in internal macro. + #[inline_macros] fn internal() { - internal_macro!(); + inline!(let x = 22_i32;); } // Should NOT lint in external macro. fn external() { - default_numeric_fallback!(); + external!(let x = 22;); } } diff --git a/tests/ui/default_numeric_fallback_i32.rs b/tests/ui/default_numeric_fallback_i32.rs index 28e6eceb80e..7307d31354e 100644 --- a/tests/ui/default_numeric_fallback_i32.rs +++ b/tests/ui/default_numeric_fallback_i32.rs @@ -1,5 +1,5 @@ // run-rustfix -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs #![feature(lint_reasons)] #![warn(clippy::default_numeric_fallback)] @@ -13,8 +13,8 @@ clippy::let_with_type_underscore )] -#[macro_use] -extern crate macro_rules; +extern crate proc_macros; +use proc_macros::{external, inline_macros}; mod basic_expr { fn test() { @@ -168,20 +168,17 @@ mod method_calls { } mod in_macro { - macro_rules! internal_macro { - () => { - let x = 22; - }; - } + use super::*; // Should lint in internal macro. + #[inline_macros] fn internal() { - internal_macro!(); + inline!(let x = 22;); } // Should NOT lint in external macro. fn external() { - default_numeric_fallback!(); + external!(let x = 22;); } } diff --git a/tests/ui/default_numeric_fallback_i32.stderr b/tests/ui/default_numeric_fallback_i32.stderr index dd91574d5b3..48cd28102ce 100644 --- a/tests/ui/default_numeric_fallback_i32.stderr +++ b/tests/ui/default_numeric_fallback_i32.stderr @@ -151,15 +151,12 @@ LL | s.generic_arg(1); | ^ help: consider adding suffix: `1_i32` error: default numeric fallback might occur - --> $DIR/default_numeric_fallback_i32.rs:173:21 + --> $DIR/default_numeric_fallback_i32.rs:176:25 | -LL | let x = 22; - | ^^ help: consider adding suffix: `22_i32` -... -LL | internal_macro!(); - | ----------------- in this macro invocation +LL | inline!(let x = 22;); + | ^^ help: consider adding suffix: `22_i32` | - = note: this error originates in the macro `internal_macro` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `__inline_mac_fn_internal` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 26 previous errors diff --git a/tests/ui/default_trait_access.fixed b/tests/ui/default_trait_access.fixed index 5640599d48a..7842ef3ec40 100644 --- a/tests/ui/default_trait_access.fixed +++ b/tests/ui/default_trait_access.fixed @@ -1,12 +1,12 @@ // run-rustfix -// aux-build: proc_macro_with_span.rs +// aux-build: proc_macros.rs #![deny(clippy::default_trait_access)] #![allow(dead_code, unused_imports)] #![allow(clippy::uninlined_format_args)] -extern crate proc_macro_with_span; +extern crate proc_macros; -use proc_macro_with_span::with_span; +use proc_macros::with_span; use std::default; use std::default::Default as D2; use std::string; diff --git a/tests/ui/default_trait_access.rs b/tests/ui/default_trait_access.rs index 11d4bc5c5f0..cbb3e59c970 100644 --- a/tests/ui/default_trait_access.rs +++ b/tests/ui/default_trait_access.rs @@ -1,12 +1,12 @@ // run-rustfix -// aux-build: proc_macro_with_span.rs +// aux-build: proc_macros.rs #![deny(clippy::default_trait_access)] #![allow(dead_code, unused_imports)] #![allow(clippy::uninlined_format_args)] -extern crate proc_macro_with_span; +extern crate proc_macros; -use proc_macro_with_span::with_span; +use proc_macros::with_span; use std::default; use std::default::Default as D2; use std::string; diff --git a/tests/ui/deref_addrof.fixed b/tests/ui/deref_addrof.fixed index 2f489deb1ee..ca5c03304c7 100644 --- a/tests/ui/deref_addrof.fixed +++ b/tests/ui/deref_addrof.fixed @@ -1,7 +1,12 @@ // run-rustfix +// aux-build:proc_macros.rs + #![allow(clippy::return_self_not_must_use)] #![warn(clippy::deref_addrof)] +extern crate proc_macros; +use proc_macros::inline_macros; + fn get_number() -> usize { 10 } @@ -41,28 +46,15 @@ fn main() { let _ = unsafe { *core::ptr::addr_of!(a) }; } -#[rustfmt::skip] -macro_rules! m { - ($visitor: expr) => { - $visitor - }; -} - -#[rustfmt::skip] -macro_rules! m_mut { - ($visitor: expr) => { - $visitor - }; -} - #[derive(Copy, Clone)] pub struct S; +#[inline_macros] impl S { pub fn f(&self) -> &Self { - m!(self) + inline!($(@expr self)) } #[allow(unused_mut)] // mut will be unused, once the macro is fixed pub fn f_mut(mut self) -> Self { - m_mut!(self) + inline!($(@expr self)) } } diff --git a/tests/ui/deref_addrof.rs b/tests/ui/deref_addrof.rs index 49f360b9a7f..3db5fafe944 100644 --- a/tests/ui/deref_addrof.rs +++ b/tests/ui/deref_addrof.rs @@ -1,7 +1,12 @@ // run-rustfix +// aux-build:proc_macros.rs + #![allow(clippy::return_self_not_must_use)] #![warn(clippy::deref_addrof)] +extern crate proc_macros; +use proc_macros::inline_macros; + fn get_number() -> usize { 10 } @@ -41,28 +46,15 @@ fn main() { let _ = unsafe { *core::ptr::addr_of!(a) }; } -#[rustfmt::skip] -macro_rules! m { - ($visitor: expr) => { - *& $visitor - }; -} - -#[rustfmt::skip] -macro_rules! m_mut { - ($visitor: expr) => { - *& mut $visitor - }; -} - #[derive(Copy, Clone)] pub struct S; +#[inline_macros] impl S { pub fn f(&self) -> &Self { - m!(self) + inline!(*& $(@expr self)) } #[allow(unused_mut)] // mut will be unused, once the macro is fixed pub fn f_mut(mut self) -> Self { - m_mut!(self) + inline!(*&mut $(@expr self)) } } diff --git a/tests/ui/deref_addrof.stderr b/tests/ui/deref_addrof.stderr index 75371fcdb96..e0287522fc5 100644 --- a/tests/ui/deref_addrof.stderr +++ b/tests/ui/deref_addrof.stderr @@ -1,5 +1,5 @@ error: immediately dereferencing a reference - --> $DIR/deref_addrof.rs:19:13 + --> $DIR/deref_addrof.rs:24:13 | LL | let b = *&a; | ^^^ help: try this: `a` @@ -7,68 +7,62 @@ LL | let b = *&a; = note: `-D clippy::deref-addrof` implied by `-D warnings` error: immediately dereferencing a reference - --> $DIR/deref_addrof.rs:21:13 + --> $DIR/deref_addrof.rs:26:13 | LL | let b = *&get_number(); | ^^^^^^^^^^^^^^ help: try this: `get_number()` error: immediately dereferencing a reference - --> $DIR/deref_addrof.rs:26:13 + --> $DIR/deref_addrof.rs:31:13 | LL | let b = *&bytes[1..2][0]; | ^^^^^^^^^^^^^^^^ help: try this: `bytes[1..2][0]` error: immediately dereferencing a reference - --> $DIR/deref_addrof.rs:30:13 + --> $DIR/deref_addrof.rs:35:13 | LL | let b = *&(a); | ^^^^^ help: try this: `(a)` error: immediately dereferencing a reference - --> $DIR/deref_addrof.rs:32:13 + --> $DIR/deref_addrof.rs:37:13 | LL | let b = *(&a); | ^^^^^ help: try this: `a` error: immediately dereferencing a reference - --> $DIR/deref_addrof.rs:35:13 + --> $DIR/deref_addrof.rs:40:13 | LL | let b = *((&a)); | ^^^^^^^ help: try this: `a` error: immediately dereferencing a reference - --> $DIR/deref_addrof.rs:37:13 + --> $DIR/deref_addrof.rs:42:13 | LL | let b = *&&a; | ^^^^ help: try this: `&a` error: immediately dereferencing a reference - --> $DIR/deref_addrof.rs:39:14 + --> $DIR/deref_addrof.rs:44:14 | LL | let b = **&aref; | ^^^^^^ help: try this: `aref` error: immediately dereferencing a reference - --> $DIR/deref_addrof.rs:47:9 + --> $DIR/deref_addrof.rs:54:17 | -LL | *& $visitor - | ^^^^^^^^^^^ help: try this: `$visitor` -... -LL | m!(self) - | -------- in this macro invocation +LL | inline!(*& $(@expr self)) + | ^^^^^^^^^^^^^^^^ help: try this: `$(@expr self)` | - = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `__inline_mac_impl` (in Nightly builds, run with -Z macro-backtrace for more info) error: immediately dereferencing a reference - --> $DIR/deref_addrof.rs:54:9 + --> $DIR/deref_addrof.rs:58:17 | -LL | *& mut $visitor - | ^^^^^^^^^^^^^^^ help: try this: `$visitor` -... -LL | m_mut!(self) - | ------------ in this macro invocation +LL | inline!(*&mut $(@expr self)) + | ^^^^^^^^^^^^^^^^^^^ help: try this: `$(@expr self)` | - = note: this error originates in the macro `m_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `__inline_mac_impl` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 10 previous errors diff --git a/tests/ui/deref_addrof_macro.rs b/tests/ui/deref_addrof_macro.rs index dcebd6c6e29..57c0be3f51e 100644 --- a/tests/ui/deref_addrof_macro.rs +++ b/tests/ui/deref_addrof_macro.rs @@ -1,10 +1,13 @@ -macro_rules! m { - ($($x:tt),*) => { &[$(($x, stringify!(x)),)*] }; -} +// aux-build:proc_macros.rs -#[warn(clippy::deref_addrof)] -fn f() -> [(i32, &'static str); 3] { - *m![1, 2, 3] // should be fine +#![warn(clippy::deref_addrof)] + +extern crate proc_macros; + +#[proc_macros::inline_macros] +fn f() -> i32 { + // should be fine + *inline!(&$1) } fn main() {} diff --git a/tests/ui/doc_unsafe.rs b/tests/ui/doc_unsafe.rs index b91f7aa0dd8..30674ce3708 100644 --- a/tests/ui/doc_unsafe.rs +++ b/tests/ui/doc_unsafe.rs @@ -1,9 +1,9 @@ -// aux-build:doc_unsafe_macros.rs +// aux-build:proc_macros.rs #![allow(clippy::let_unit_value)] -#[macro_use] -extern crate doc_unsafe_macros; +extern crate proc_macros; +use proc_macros::external; /// This is not sufficiently documented pub unsafe fn destroy_the_planet() { @@ -105,7 +105,11 @@ macro_rules! very_unsafe { very_unsafe!(); // we don't lint code from external macros -undocd_unsafe!(); +external! { + pub unsafe fn oy_vey() { + unimplemented!(); + } +} fn main() { unsafe { diff --git a/tests/ui/empty_loop.rs b/tests/ui/empty_loop.rs index 8fd7697eb3b..6a8e6b550c1 100644 --- a/tests/ui/empty_loop.rs +++ b/tests/ui/empty_loop.rs @@ -1,9 +1,9 @@ -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs #![warn(clippy::empty_loop)] -#[macro_use] -extern crate macro_rules; +extern crate proc_macros; +use proc_macros::{external, inline_macros}; fn should_trigger() { loop {} @@ -16,6 +16,7 @@ fn should_trigger() { } } +#[inline_macros] fn should_not_trigger() { loop { panic!("This is fine") @@ -38,14 +39,10 @@ fn should_not_trigger() { loop {} // We don't lint loops inside macros - macro_rules! foo { - () => { - loop {} - }; - } + inline!(loop {}); // We don't lint external macros - foofoo!() + external!(loop {}); } fn main() {} diff --git a/tests/ui/equatable_if_let.fixed b/tests/ui/equatable_if_let.fixed index 9af2ba96272..007702ab550 100644 --- a/tests/ui/equatable_if_let.fixed +++ b/tests/ui/equatable_if_let.fixed @@ -1,11 +1,11 @@ // run-rustfix -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs #![allow(unused_variables, dead_code, clippy::derive_partial_eq_without_eq)] #![warn(clippy::equatable_if_let)] -#[macro_use] -extern crate macro_rules; +extern crate proc_macros; +use proc_macros::{external, inline_macros}; use std::cmp::Ordering; @@ -44,6 +44,7 @@ impl PartialEq for NotStructuralEq { } } +#[inline_macros] fn main() { let a = 2; let b = 3; @@ -78,14 +79,9 @@ fn main() { if Some(g) == Some(NotStructuralEq::A) {} if matches!(h, NoPartialEqStruct { a: 2, b: false }) {} - macro_rules! m1 { - (x) => { - "abc" - }; - } - if "abc" == m1!(x) { + if "abc" == inline!("abc") { println!("OK"); } - equatable_if_let!(a); + external!({ if let 2 = $a {} }); } diff --git a/tests/ui/equatable_if_let.rs b/tests/ui/equatable_if_let.rs index c3626c081dd..3bda7977645 100644 --- a/tests/ui/equatable_if_let.rs +++ b/tests/ui/equatable_if_let.rs @@ -1,11 +1,11 @@ // run-rustfix -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs #![allow(unused_variables, dead_code, clippy::derive_partial_eq_without_eq)] #![warn(clippy::equatable_if_let)] -#[macro_use] -extern crate macro_rules; +extern crate proc_macros; +use proc_macros::{external, inline_macros}; use std::cmp::Ordering; @@ -44,6 +44,7 @@ impl PartialEq for NotStructuralEq { } } +#[inline_macros] fn main() { let a = 2; let b = 3; @@ -78,14 +79,9 @@ fn main() { if let Some(NotStructuralEq::A) = Some(g) {} if let NoPartialEqStruct { a: 2, b: false } = h {} - macro_rules! m1 { - (x) => { - "abc" - }; - } - if let m1!(x) = "abc" { + if let inline!("abc") = "abc" { println!("OK"); } - equatable_if_let!(a); + external!({ if let 2 = $a {} }); } diff --git a/tests/ui/equatable_if_let.stderr b/tests/ui/equatable_if_let.stderr index 40ca75b8da2..a72d87bb7ba 100644 --- a/tests/ui/equatable_if_let.stderr +++ b/tests/ui/equatable_if_let.stderr @@ -1,5 +1,5 @@ error: this pattern matching can be expressed using equality - --> $DIR/equatable_if_let.rs:59:8 + --> $DIR/equatable_if_let.rs:60:8 | LL | if let 2 = a {} | ^^^^^^^^^ help: try: `a == 2` @@ -7,82 +7,82 @@ LL | if let 2 = a {} = note: `-D clippy::equatable-if-let` implied by `-D warnings` error: this pattern matching can be expressed using equality - --> $DIR/equatable_if_let.rs:60:8 + --> $DIR/equatable_if_let.rs:61:8 | LL | if let Ordering::Greater = a.cmp(&b) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `a.cmp(&b) == Ordering::Greater` error: this pattern matching can be expressed using equality - --> $DIR/equatable_if_let.rs:61:8 + --> $DIR/equatable_if_let.rs:62:8 | LL | if let Some(2) = c {} | ^^^^^^^^^^^^^^^ help: try: `c == Some(2)` error: this pattern matching can be expressed using equality - --> $DIR/equatable_if_let.rs:62:8 + --> $DIR/equatable_if_let.rs:63:8 | LL | if let Struct { a: 2, b: false } = d {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `d == (Struct { a: 2, b: false })` error: this pattern matching can be expressed using equality - --> $DIR/equatable_if_let.rs:63:8 + --> $DIR/equatable_if_let.rs:64:8 | LL | if let Enum::TupleVariant(32, 64) = e {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `e == Enum::TupleVariant(32, 64)` error: this pattern matching can be expressed using equality - --> $DIR/equatable_if_let.rs:64:8 + --> $DIR/equatable_if_let.rs:65:8 | LL | if let Enum::RecordVariant { a: 64, b: 32 } = e {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `e == (Enum::RecordVariant { a: 64, b: 32 })` error: this pattern matching can be expressed using equality - --> $DIR/equatable_if_let.rs:65:8 + --> $DIR/equatable_if_let.rs:66:8 | LL | if let Enum::UnitVariant = e {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `e == Enum::UnitVariant` error: this pattern matching can be expressed using equality - --> $DIR/equatable_if_let.rs:66:8 + --> $DIR/equatable_if_let.rs:67:8 | LL | if let (Enum::UnitVariant, &Struct { a: 2, b: false }) = (e, &d) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(e, &d) == (Enum::UnitVariant, &Struct { a: 2, b: false })` error: this pattern matching can be expressed using `matches!` - --> $DIR/equatable_if_let.rs:75:8 + --> $DIR/equatable_if_let.rs:76:8 | LL | if let NotPartialEq::A = f {} | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(f, NotPartialEq::A)` error: this pattern matching can be expressed using equality - --> $DIR/equatable_if_let.rs:76:8 + --> $DIR/equatable_if_let.rs:77:8 | LL | if let NotStructuralEq::A = g {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `g == NotStructuralEq::A` error: this pattern matching can be expressed using `matches!` - --> $DIR/equatable_if_let.rs:77:8 + --> $DIR/equatable_if_let.rs:78:8 | LL | if let Some(NotPartialEq::A) = Some(f) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(Some(f), Some(NotPartialEq::A))` error: this pattern matching can be expressed using equality - --> $DIR/equatable_if_let.rs:78:8 + --> $DIR/equatable_if_let.rs:79:8 | LL | if let Some(NotStructuralEq::A) = Some(g) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Some(g) == Some(NotStructuralEq::A)` error: this pattern matching can be expressed using `matches!` - --> $DIR/equatable_if_let.rs:79:8 + --> $DIR/equatable_if_let.rs:80:8 | LL | if let NoPartialEqStruct { a: 2, b: false } = h {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(h, NoPartialEqStruct { a: 2, b: false })` error: this pattern matching can be expressed using equality - --> $DIR/equatable_if_let.rs:86:8 + --> $DIR/equatable_if_let.rs:82:8 | -LL | if let m1!(x) = "abc" { - | ^^^^^^^^^^^^^^^^^^ help: try: `"abc" == m1!(x)` +LL | if let inline!("abc") = "abc" { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"abc" == inline!("abc")` error: aborting due to 14 previous errors diff --git a/tests/ui/field_reassign_with_default.rs b/tests/ui/field_reassign_with_default.rs index 1f989bb1220..0e208b3ed0e 100644 --- a/tests/ui/field_reassign_with_default.rs +++ b/tests/ui/field_reassign_with_default.rs @@ -1,12 +1,12 @@ // aux-build:proc_macro_derive.rs -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs #![warn(clippy::field_reassign_with_default)] #[macro_use] extern crate proc_macro_derive; -#[macro_use] -extern crate macro_rules; +extern crate proc_macros; +use proc_macros::{external, inline_macros}; // Don't lint on derives that derive `Default` // See https://github.com/rust-lang/rust-clippy/issues/6545 @@ -36,14 +36,6 @@ struct D { b: Option, } -macro_rules! m { - ($key:ident: $value:tt) => {{ - let mut data = $crate::D::default(); - data.$key = Some($value); - data - }}; -} - /// Implements .next() that returns a different number each time. struct SideEffect(i32); @@ -57,6 +49,7 @@ impl SideEffect { } } +#[inline_macros] fn main() { // wrong, produces first error in stderr let mut a: A = Default::default(); @@ -150,7 +143,18 @@ fn main() { a.i = vec![1]; // Don't lint in external macros - field_reassign_with_default!(); + external! { + #[derive(Default)] + struct A { + pub i: i32, + pub j: i64, + } + fn lint() { + let mut a: A = Default::default(); + a.i = 42; + a; + } + } // be sure suggestion is correct with generics let mut a: Wrapper = Default::default(); @@ -160,9 +164,11 @@ fn main() { a.i = 42; // Don't lint in macros - m! { - a: 42 - }; + inline!( + let mut data = $crate::D::default(); + data.$a = Some($42); + data + ); } mod m { diff --git a/tests/ui/field_reassign_with_default.stderr b/tests/ui/field_reassign_with_default.stderr index 710bb66a48a..da74f9ef9f7 100644 --- a/tests/ui/field_reassign_with_default.stderr +++ b/tests/ui/field_reassign_with_default.stderr @@ -1,132 +1,132 @@ error: field assignment outside of initializer for an instance created with Default::default() - --> $DIR/field_reassign_with_default.rs:63:5 + --> $DIR/field_reassign_with_default.rs:56:5 | LL | a.i = 42; | ^^^^^^^^^ | note: consider initializing the variable with `main::A { i: 42, ..Default::default() }` and removing relevant reassignments - --> $DIR/field_reassign_with_default.rs:62:5 + --> $DIR/field_reassign_with_default.rs:55:5 | LL | let mut a: A = Default::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: `-D clippy::field-reassign-with-default` implied by `-D warnings` error: field assignment outside of initializer for an instance created with Default::default() - --> $DIR/field_reassign_with_default.rs:103:5 + --> $DIR/field_reassign_with_default.rs:96:5 | LL | a.j = 43; | ^^^^^^^^^ | note: consider initializing the variable with `main::A { j: 43, i: 42 }` and removing relevant reassignments - --> $DIR/field_reassign_with_default.rs:102:5 + --> $DIR/field_reassign_with_default.rs:95:5 | LL | let mut a: A = Default::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: field assignment outside of initializer for an instance created with Default::default() - --> $DIR/field_reassign_with_default.rs:108:5 + --> $DIR/field_reassign_with_default.rs:101:5 | LL | a.i = 42; | ^^^^^^^^^ | note: consider initializing the variable with `main::A { i: 42, j: 44 }` and removing relevant reassignments - --> $DIR/field_reassign_with_default.rs:107:5 + --> $DIR/field_reassign_with_default.rs:100:5 | LL | let mut a: A = Default::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: field assignment outside of initializer for an instance created with Default::default() - --> $DIR/field_reassign_with_default.rs:114:5 + --> $DIR/field_reassign_with_default.rs:107:5 | LL | a.i = 42; | ^^^^^^^^^ | note: consider initializing the variable with `main::A { i: 42, ..Default::default() }` and removing relevant reassignments - --> $DIR/field_reassign_with_default.rs:113:5 + --> $DIR/field_reassign_with_default.rs:106:5 | LL | let mut a = A::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: field assignment outside of initializer for an instance created with Default::default() - --> $DIR/field_reassign_with_default.rs:124:5 + --> $DIR/field_reassign_with_default.rs:117:5 | LL | a.i = Default::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ | note: consider initializing the variable with `main::A { i: Default::default(), ..Default::default() }` and removing relevant reassignments - --> $DIR/field_reassign_with_default.rs:123:5 + --> $DIR/field_reassign_with_default.rs:116:5 | LL | let mut a: A = Default::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: field assignment outside of initializer for an instance created with Default::default() - --> $DIR/field_reassign_with_default.rs:128:5 + --> $DIR/field_reassign_with_default.rs:121:5 | LL | a.i = Default::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ | note: consider initializing the variable with `main::A { i: Default::default(), j: 45 }` and removing relevant reassignments - --> $DIR/field_reassign_with_default.rs:127:5 + --> $DIR/field_reassign_with_default.rs:120:5 | LL | let mut a: A = Default::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: field assignment outside of initializer for an instance created with Default::default() - --> $DIR/field_reassign_with_default.rs:150:5 + --> $DIR/field_reassign_with_default.rs:143:5 | LL | a.i = vec![1]; | ^^^^^^^^^^^^^^ | note: consider initializing the variable with `C { i: vec![1], ..Default::default() }` and removing relevant reassignments - --> $DIR/field_reassign_with_default.rs:149:5 + --> $DIR/field_reassign_with_default.rs:142:5 | LL | let mut a: C = C::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: field assignment outside of initializer for an instance created with Default::default() - --> $DIR/field_reassign_with_default.rs:157:5 + --> $DIR/field_reassign_with_default.rs:161:5 | LL | a.i = true; | ^^^^^^^^^^^ | note: consider initializing the variable with `Wrapper:: { i: true }` and removing relevant reassignments - --> $DIR/field_reassign_with_default.rs:156:5 + --> $DIR/field_reassign_with_default.rs:160:5 | LL | let mut a: Wrapper = Default::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: field assignment outside of initializer for an instance created with Default::default() - --> $DIR/field_reassign_with_default.rs:160:5 + --> $DIR/field_reassign_with_default.rs:164:5 | LL | a.i = 42; | ^^^^^^^^^ | note: consider initializing the variable with `WrapperMulti:: { i: 42, ..Default::default() }` and removing relevant reassignments - --> $DIR/field_reassign_with_default.rs:159:5 + --> $DIR/field_reassign_with_default.rs:163:5 | LL | let mut a: WrapperMulti = Default::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: field assignment outside of initializer for an instance created with Default::default() - --> $DIR/field_reassign_with_default.rs:229:13 + --> $DIR/field_reassign_with_default.rs:235:13 | LL | f.name = name.len(); | ^^^^^^^^^^^^^^^^^^^^ | note: consider initializing the variable with `issue6312::ImplDropAllCopy { name: name.len(), ..Default::default() }` and removing relevant reassignments - --> $DIR/field_reassign_with_default.rs:228:13 + --> $DIR/field_reassign_with_default.rs:234:13 | LL | let mut f = ImplDropAllCopy::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: field assignment outside of initializer for an instance created with Default::default() - --> $DIR/field_reassign_with_default.rs:245:13 + --> $DIR/field_reassign_with_default.rs:251:13 | LL | f.name = name.len(); | ^^^^^^^^^^^^^^^^^^^^ | note: consider initializing the variable with `issue6312::NoDropAllCopy { name: name.len(), ..Default::default() }` and removing relevant reassignments - --> $DIR/field_reassign_with_default.rs:244:13 + --> $DIR/field_reassign_with_default.rs:250:13 | LL | let mut f = NoDropAllCopy::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/ifs_same_cond.rs b/tests/ui/ifs_same_cond.rs index 9850fc0919e..9ce9a87626a 100644 --- a/tests/ui/ifs_same_cond.rs +++ b/tests/ui/ifs_same_cond.rs @@ -43,4 +43,30 @@ fn ifs_same_cond() { } } +fn issue10272() { + let a = String::from("ha"); + if a.contains("ah") { + } else if a.contains("ah") { + // Trigger this lint + } else if a.contains("ha") { + } else if a == "wow" { + } + + let p: *mut i8 = std::ptr::null_mut(); + if p.is_null() { + } else if p.align_offset(0) == 0 { + } else if p.is_null() { + // ok, p is mutable pointer + } else { + } + + let x = std::cell::Cell::new(true); + if x.get() { + } else if !x.take() { + } else if x.get() { + // ok, x is interior mutable type + } else { + } +} + fn main() {} diff --git a/tests/ui/ifs_same_cond.stderr b/tests/ui/ifs_same_cond.stderr index 4113087327a..9519f6904cb 100644 --- a/tests/ui/ifs_same_cond.stderr +++ b/tests/ui/ifs_same_cond.stderr @@ -35,5 +35,17 @@ note: same as this LL | if 2 * a == 1 { | ^^^^^^^^^^ -error: aborting due to 3 previous errors +error: this `if` has the same condition as a previous `if` + --> $DIR/ifs_same_cond.rs:49:15 + | +LL | } else if a.contains("ah") { + | ^^^^^^^^^^^^^^^^ + | +note: same as this + --> $DIR/ifs_same_cond.rs:48:8 + | +LL | if a.contains("ah") { + | ^^^^^^^^^^^^^^^^ + +error: aborting due to 4 previous errors diff --git a/tests/ui/implicit_hasher.rs b/tests/ui/implicit_hasher.rs index fd96ca3f466..35d08a07bc3 100644 --- a/tests/ui/implicit_hasher.rs +++ b/tests/ui/implicit_hasher.rs @@ -1,9 +1,11 @@ -// aux-build:implicit_hasher_macros.rs +// aux-build:proc_macros.rs + #![deny(clippy::implicit_hasher)] #![allow(unused)] #[macro_use] -extern crate implicit_hasher_macros; +extern crate proc_macros; +use proc_macros::external; use std::cmp::Eq; use std::collections::{HashMap, HashSet}; @@ -68,22 +70,19 @@ impl Foo for HashSet { pub fn foo(_map: &mut HashMap, _set: &mut HashSet) {} -macro_rules! gen { - (impl) => { +#[proc_macros::inline_macros] +pub mod gen { + use super::*; + inline! { impl Foo for HashMap { fn make() -> (Self, Self) { (HashMap::new(), HashMap::with_capacity(10)) } } - }; - (fn $name:ident) => { - pub fn $name(_map: &mut HashMap, _set: &mut HashSet) {} - }; + pub fn bar(_map: &mut HashMap, _set: &mut HashSet) {} + } } -#[rustfmt::skip] -gen!(impl); -gen!(fn bar); // When the macro is in a different file, the suggestion spans can't be combined properly // and should not cause an ICE @@ -94,7 +93,9 @@ pub mod test_macro; __implicit_hasher_test_macro!(impl for HashMap where V: test_macro::A); // #4260 -implicit_hasher_fn!(); +external! { + pub fn f(input: &HashMap) {} +} // #7712 pub async fn election_vote(_data: HashMap) {} diff --git a/tests/ui/implicit_hasher.stderr b/tests/ui/implicit_hasher.stderr index 59b0fba2a4c..83b46de2eb5 100644 --- a/tests/ui/implicit_hasher.stderr +++ b/tests/ui/implicit_hasher.stderr @@ -1,11 +1,11 @@ error: impl for `HashMap` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:16:35 + --> $DIR/implicit_hasher.rs:18:35 | LL | impl Foo for HashMap { | ^^^^^^^^^^^^^ | note: the lint level is defined here - --> $DIR/implicit_hasher.rs:2:9 + --> $DIR/implicit_hasher.rs:3:9 | LL | #![deny(clippy::implicit_hasher)] | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -19,7 +19,7 @@ LL | (HashMap::default(), HashMap::with_capacity_and_hasher(10, Default: | ~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: impl for `HashMap` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:25:36 + --> $DIR/implicit_hasher.rs:27:36 | LL | impl Foo for (HashMap,) { | ^^^^^^^^^^^^^ @@ -34,7 +34,7 @@ LL | ((HashMap::default(),), (HashMap::with_capacity_and_hasher(10, Defa | ~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: impl for `HashMap` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:30:19 + --> $DIR/implicit_hasher.rs:32:19 | LL | impl Foo for HashMap { | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL | (HashMap::default(), HashMap::with_capacity_and_hasher(10, Default: | ~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: impl for `HashSet` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:47:32 + --> $DIR/implicit_hasher.rs:49:32 | LL | impl Foo for HashSet { | ^^^^^^^^^^ @@ -64,7 +64,7 @@ LL | (HashSet::default(), HashSet::with_capacity_and_hasher(10, Default: | ~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: impl for `HashSet` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:52:19 + --> $DIR/implicit_hasher.rs:54:19 | LL | impl Foo for HashSet { | ^^^^^^^^^^^^^^^ @@ -79,7 +79,7 @@ LL | (HashSet::default(), HashSet::with_capacity_and_hasher(10, Default: | ~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: parameter of type `HashMap` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:69:23 + --> $DIR/implicit_hasher.rs:71:23 | LL | pub fn foo(_map: &mut HashMap, _set: &mut HashSet) {} | ^^^^^^^^^^^^^^^^^ @@ -90,7 +90,7 @@ LL | pub fn foo(_map: &mut HashMap, _s | +++++++++++++++++++++++++++++ ~~~~~~~~~~~~~~~~~~~~ error: parameter of type `HashSet` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:69:53 + --> $DIR/implicit_hasher.rs:71:53 | LL | pub fn foo(_map: &mut HashMap, _set: &mut HashSet) {} | ^^^^^^^^^^^^ @@ -101,15 +101,12 @@ LL | pub fn foo(_map: &mut HashMap, _set: | +++++++++++++++++++++++++++++ ~~~~~~~~~~~~~~~ error: impl for `HashMap` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:73:43 + --> $DIR/implicit_hasher.rs:77:43 | LL | impl Foo for HashMap { | ^^^^^^^^^^^^^ -... -LL | gen!(impl); - | ---------- in this macro invocation | - = note: this error originates in the macro `gen` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `__inline_mac_mod_gen` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider adding a type parameter | LL | impl Foo for HashMap { @@ -120,37 +117,31 @@ LL | (HashMap::default(), HashMap::with_capacity_and_hasher(10, | ~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: parameter of type `HashMap` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:81:33 + --> $DIR/implicit_hasher.rs:83:31 | -LL | pub fn $name(_map: &mut HashMap, _set: &mut HashSet) {} - | ^^^^^^^^^^^^^^^^^ -... -LL | gen!(fn bar); - | ------------ in this macro invocation +LL | pub fn bar(_map: &mut HashMap, _set: &mut HashSet) {} + | ^^^^^^^^^^^^^^^^^ | - = note: this error originates in the macro `gen` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `__inline_mac_mod_gen` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider adding a type parameter | -LL | pub fn $name(_map: &mut HashMap, _set: &mut HashSet) {} - | +++++++++++++++++++++++++++++ ~~~~~~~~~~~~~~~~~~~~ +LL | pub fn bar(_map: &mut HashMap, _set: &mut HashSet) {} + | +++++++++++++++++++++++++++++ ~~~~~~~~~~~~~~~~~~~~ error: parameter of type `HashSet` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:81:63 + --> $DIR/implicit_hasher.rs:83:61 | -LL | pub fn $name(_map: &mut HashMap, _set: &mut HashSet) {} - | ^^^^^^^^^^^^ -... -LL | gen!(fn bar); - | ------------ in this macro invocation +LL | pub fn bar(_map: &mut HashMap, _set: &mut HashSet) {} + | ^^^^^^^^^^^^ | - = note: this error originates in the macro `gen` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `__inline_mac_mod_gen` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider adding a type parameter | -LL | pub fn $name(_map: &mut HashMap, _set: &mut HashSet) {} - | +++++++++++++++++++++++++++++ ~~~~~~~~~~~~~~~ +LL | pub fn bar(_map: &mut HashMap, _set: &mut HashSet) {} + | +++++++++++++++++++++++++++++ ~~~~~~~~~~~~~~~ error: parameter of type `HashMap` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:100:35 + --> $DIR/implicit_hasher.rs:101:35 | LL | pub async fn election_vote(_data: HashMap) {} | ^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/inconsistent_struct_constructor.fixed b/tests/ui/inconsistent_struct_constructor.fixed index 74ba2f1c5e7..5aaa00f8517 100644 --- a/tests/ui/inconsistent_struct_constructor.fixed +++ b/tests/ui/inconsistent_struct_constructor.fixed @@ -1,10 +1,14 @@ // run-rustfix +// aux-build:proc_macros.rs + #![warn(clippy::inconsistent_struct_constructor)] #![allow(clippy::redundant_field_names)] #![allow(clippy::unnecessary_operation)] #![allow(clippy::no_effect)] #![allow(dead_code)] +extern crate proc_macros; + #[derive(Default)] struct Foo { x: i32, @@ -12,18 +16,10 @@ struct Foo { z: i32, } -macro_rules! new_foo { - () => { - let x = 1; - let y = 1; - let z = 1; - Foo { y, x, z } - }; -} - mod without_base { use super::Foo; + #[proc_macros::inline_macros] fn test() { let x = 1; let y = 1; @@ -34,7 +30,12 @@ mod without_base { // Should NOT lint. // issue #7069. - new_foo!(); + inline!({ + let x = 1; + let y = 1; + let z = 1; + Foo { y, x, z } + }); // Should NOT lint because the order is the same as in the definition. Foo { x, y, z }; diff --git a/tests/ui/inconsistent_struct_constructor.rs b/tests/ui/inconsistent_struct_constructor.rs index ba96e1e330f..2b2dd7f59a4 100644 --- a/tests/ui/inconsistent_struct_constructor.rs +++ b/tests/ui/inconsistent_struct_constructor.rs @@ -1,10 +1,14 @@ // run-rustfix +// aux-build:proc_macros.rs + #![warn(clippy::inconsistent_struct_constructor)] #![allow(clippy::redundant_field_names)] #![allow(clippy::unnecessary_operation)] #![allow(clippy::no_effect)] #![allow(dead_code)] +extern crate proc_macros; + #[derive(Default)] struct Foo { x: i32, @@ -12,18 +16,10 @@ struct Foo { z: i32, } -macro_rules! new_foo { - () => { - let x = 1; - let y = 1; - let z = 1; - Foo { y, x, z } - }; -} - mod without_base { use super::Foo; + #[proc_macros::inline_macros] fn test() { let x = 1; let y = 1; @@ -34,7 +30,12 @@ mod without_base { // Should NOT lint. // issue #7069. - new_foo!(); + inline!({ + let x = 1; + let y = 1; + let z = 1; + Foo { y, x, z } + }); // Should NOT lint because the order is the same as in the definition. Foo { x, y, z }; diff --git a/tests/ui/inconsistent_struct_constructor.stderr b/tests/ui/inconsistent_struct_constructor.stderr index c90189e964f..785a6dc9d53 100644 --- a/tests/ui/inconsistent_struct_constructor.stderr +++ b/tests/ui/inconsistent_struct_constructor.stderr @@ -1,5 +1,5 @@ error: struct constructor field order is inconsistent with struct definition field order - --> $DIR/inconsistent_struct_constructor.rs:33:9 + --> $DIR/inconsistent_struct_constructor.rs:29:9 | LL | Foo { y, x, z }; | ^^^^^^^^^^^^^^^ help: try: `Foo { x, y, z }` @@ -7,7 +7,7 @@ LL | Foo { y, x, z }; = note: `-D clippy::inconsistent-struct-constructor` implied by `-D warnings` error: struct constructor field order is inconsistent with struct definition field order - --> $DIR/inconsistent_struct_constructor.rs:55:9 + --> $DIR/inconsistent_struct_constructor.rs:56:9 | LL | / Foo { LL | | z, diff --git a/tests/ui/large_enum_variant.rs b/tests/ui/large_enum_variant.rs index 3b96f09d7b1..f09f8ae0ccc 100644 --- a/tests/ui/large_enum_variant.rs +++ b/tests/ui/large_enum_variant.rs @@ -1,11 +1,11 @@ -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs #![allow(dead_code)] #![allow(unused_variables)] #![warn(clippy::large_enum_variant)] -#[macro_use] -extern crate macro_rules; +extern crate proc_macros; +use proc_macros::external; enum LargeEnum { A(i32), @@ -155,5 +155,10 @@ enum LargeEnumOfConst { } fn main() { - large_enum_variant!(); + external!( + enum LargeEnumInMacro { + A(i32), + B([i32; 8000]), + } + ); } diff --git a/tests/ui/macro_use_imports.fixed b/tests/ui/macro_use_imports.fixed index e612480d264..15f7a099a7d 100644 --- a/tests/ui/macro_use_imports.fixed +++ b/tests/ui/macro_use_imports.fixed @@ -20,7 +20,7 @@ mod a { use mac; use mini_mac::ClippyMiniMacroTest; use mini_mac; - use mac::{inner::foofoo, inner::try_err}; + use mac::{inner::mut_mut, inner::try_err}; use mac::inner; use mac::inner::nested::string_add; use mac::inner::nested; @@ -36,7 +36,7 @@ mod a { let v: ty_macro!() = Vec::default(); inner::try_err!(); - inner::foofoo!(); + inner::mut_mut!(); nested::string_add!(); } } diff --git a/tests/ui/macro_use_imports.rs b/tests/ui/macro_use_imports.rs index b34817cc3b2..b1a28733294 100644 --- a/tests/ui/macro_use_imports.rs +++ b/tests/ui/macro_use_imports.rs @@ -36,7 +36,7 @@ mod a { let v: ty_macro!() = Vec::default(); inner::try_err!(); - inner::foofoo!(); + inner::mut_mut!(); nested::string_add!(); } } diff --git a/tests/ui/macro_use_imports.stderr b/tests/ui/macro_use_imports.stderr index 61843124ccd..68d558dede0 100644 --- a/tests/ui/macro_use_imports.stderr +++ b/tests/ui/macro_use_imports.stderr @@ -16,7 +16,7 @@ error: `macro_use` attributes are no longer needed in the Rust 2018 edition --> $DIR/macro_use_imports.rs:23:5 | LL | #[macro_use] - | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::{inner::foofoo, inner::try_err};` + | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::{inner::mut_mut, inner::try_err};` error: `macro_use` attributes are no longer needed in the Rust 2018 edition --> $DIR/macro_use_imports.rs:19:5 diff --git a/tests/ui/macro_use_imports_expect.rs b/tests/ui/macro_use_imports_expect.rs index 8a1b05da9ef..5aac5af26db 100644 --- a/tests/ui/macro_use_imports_expect.rs +++ b/tests/ui/macro_use_imports_expect.rs @@ -39,7 +39,7 @@ mod a { let v: ty_macro!() = Vec::default(); inner::try_err!(); - inner::foofoo!(); + inner::mut_mut!(); nested::string_add!(); } } diff --git a/tests/ui/manual_async_fn.fixed b/tests/ui/manual_async_fn.fixed index b7e46a4a8cc..5cc4a43af7e 100644 --- a/tests/ui/manual_async_fn.fixed +++ b/tests/ui/manual_async_fn.fixed @@ -107,4 +107,10 @@ mod issue_5765 { } } +pub async fn issue_10450() -> i32 { 42 } + +pub(crate) async fn issue_10450_2() -> i32 { 42 } + +pub(self) async fn issue_10450_3() -> i32 { 42 } + fn main() {} diff --git a/tests/ui/manual_async_fn.rs b/tests/ui/manual_async_fn.rs index b05429da662..ba504b8a823 100644 --- a/tests/ui/manual_async_fn.rs +++ b/tests/ui/manual_async_fn.rs @@ -127,4 +127,16 @@ mod issue_5765 { } } +pub fn issue_10450() -> impl Future { + async { 42 } +} + +pub(crate) fn issue_10450_2() -> impl Future { + async { 42 } +} + +pub(self) fn issue_10450_3() -> impl Future { + async { 42 } +} + fn main() {} diff --git a/tests/ui/manual_async_fn.stderr b/tests/ui/manual_async_fn.stderr index 0a903ed6fd4..f5ee3eb7ccc 100644 --- a/tests/ui/manual_async_fn.stderr +++ b/tests/ui/manual_async_fn.stderr @@ -161,5 +161,50 @@ help: move the body of the async block to the enclosing function LL | fn explicit<'a, 'b>(_: &'a i32, _: &'b i32) -> impl Future + 'a + 'b { 42 } | ~~~~~~ -error: aborting due to 10 previous errors +error: this function can be simplified using the `async fn` syntax + --> $DIR/manual_async_fn.rs:130:1 + | +LL | pub fn issue_10450() -> impl Future { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: make the function `async` and return the output of the future directly + | +LL | pub async fn issue_10450() -> i32 { + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +help: move the body of the async block to the enclosing function + | +LL | pub fn issue_10450() -> impl Future { 42 } + | ~~~~~~ + +error: this function can be simplified using the `async fn` syntax + --> $DIR/manual_async_fn.rs:134:1 + | +LL | pub(crate) fn issue_10450_2() -> impl Future { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: make the function `async` and return the output of the future directly + | +LL | pub(crate) async fn issue_10450_2() -> i32 { + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +help: move the body of the async block to the enclosing function + | +LL | pub(crate) fn issue_10450_2() -> impl Future { 42 } + | ~~~~~~ + +error: this function can be simplified using the `async fn` syntax + --> $DIR/manual_async_fn.rs:138:1 + | +LL | pub(self) fn issue_10450_3() -> impl Future { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: make the function `async` and return the output of the future directly + | +LL | pub(self) async fn issue_10450_3() -> i32 { + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +help: move the body of the async block to the enclosing function + | +LL | pub(self) fn issue_10450_3() -> impl Future { 42 } + | ~~~~~~ + +error: aborting due to 13 previous errors diff --git a/tests/ui/manual_clamp.rs b/tests/ui/manual_clamp.rs index f7902e6fd53..cdfd8e4c3fe 100644 --- a/tests/ui/manual_clamp.rs +++ b/tests/ui/manual_clamp.rs @@ -326,3 +326,22 @@ fn msrv_1_50() { input }; } + +const fn _const() { + let (input, min, max) = (0, -1, 2); + let _ = if input < min { + min + } else if input > max { + max + } else { + input + }; + + let mut x = input; + if max < x { + let x = max; + } + if min > x { + x = min; + } +} diff --git a/tests/ui/manual_main_separator_str.fixed b/tests/ui/manual_main_separator_str.fixed new file mode 100644 index 00000000000..50f46d6b355 --- /dev/null +++ b/tests/ui/manual_main_separator_str.fixed @@ -0,0 +1,39 @@ +// run-rustfix + +#![allow(unused)] +#![warn(clippy::manual_main_separator_str)] + +use std::path::MAIN_SEPARATOR; + +fn len(s: &str) -> usize { + s.len() +} + +struct U<'a> { + f: &'a str, + g: &'a String, +} + +struct V { + f: T, +} + +fn main() { + // Should lint + let _: &str = std::path::MAIN_SEPARATOR_STR; + let _ = len(std::path::MAIN_SEPARATOR_STR); + let _: Vec = std::path::MAIN_SEPARATOR_STR.encode_utf16().collect(); + + // Should lint for field `f` only + let _ = U { + f: std::path::MAIN_SEPARATOR_STR, + g: &MAIN_SEPARATOR.to_string(), + }; + + // Should not lint + let _: &String = &MAIN_SEPARATOR.to_string(); + let _ = &MAIN_SEPARATOR.to_string(); + let _ = V { + f: &MAIN_SEPARATOR.to_string(), + }; +} diff --git a/tests/ui/manual_main_separator_str.rs b/tests/ui/manual_main_separator_str.rs new file mode 100644 index 00000000000..2dbb9e66151 --- /dev/null +++ b/tests/ui/manual_main_separator_str.rs @@ -0,0 +1,39 @@ +// run-rustfix + +#![allow(unused)] +#![warn(clippy::manual_main_separator_str)] + +use std::path::MAIN_SEPARATOR; + +fn len(s: &str) -> usize { + s.len() +} + +struct U<'a> { + f: &'a str, + g: &'a String, +} + +struct V { + f: T, +} + +fn main() { + // Should lint + let _: &str = &MAIN_SEPARATOR.to_string(); + let _ = len(&MAIN_SEPARATOR.to_string()); + let _: Vec = MAIN_SEPARATOR.to_string().encode_utf16().collect(); + + // Should lint for field `f` only + let _ = U { + f: &MAIN_SEPARATOR.to_string(), + g: &MAIN_SEPARATOR.to_string(), + }; + + // Should not lint + let _: &String = &MAIN_SEPARATOR.to_string(); + let _ = &MAIN_SEPARATOR.to_string(); + let _ = V { + f: &MAIN_SEPARATOR.to_string(), + }; +} diff --git a/tests/ui/manual_main_separator_str.stderr b/tests/ui/manual_main_separator_str.stderr new file mode 100644 index 00000000000..e6cefde66a7 --- /dev/null +++ b/tests/ui/manual_main_separator_str.stderr @@ -0,0 +1,28 @@ +error: taking a reference on `std::path::MAIN_SEPARATOR` conversion to `String` + --> $DIR/manual_main_separator_str.rs:23:19 + | +LL | let _: &str = &MAIN_SEPARATOR.to_string(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `std::path::MAIN_SEPARATOR_STR` + | + = note: `-D clippy::manual-main-separator-str` implied by `-D warnings` + +error: taking a reference on `std::path::MAIN_SEPARATOR` conversion to `String` + --> $DIR/manual_main_separator_str.rs:24:17 + | +LL | let _ = len(&MAIN_SEPARATOR.to_string()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `std::path::MAIN_SEPARATOR_STR` + +error: taking a reference on `std::path::MAIN_SEPARATOR` conversion to `String` + --> $DIR/manual_main_separator_str.rs:25:23 + | +LL | let _: Vec = MAIN_SEPARATOR.to_string().encode_utf16().collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `std::path::MAIN_SEPARATOR_STR` + +error: taking a reference on `std::path::MAIN_SEPARATOR` conversion to `String` + --> $DIR/manual_main_separator_str.rs:29:12 + | +LL | f: &MAIN_SEPARATOR.to_string(), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `std::path::MAIN_SEPARATOR_STR` + +error: aborting due to 4 previous errors + diff --git a/tests/ui/manual_rem_euclid.fixed b/tests/ui/manual_rem_euclid.fixed index 6916a284a20..1f6df1b0a86 100644 --- a/tests/ui/manual_rem_euclid.fixed +++ b/tests/ui/manual_rem_euclid.fixed @@ -1,19 +1,13 @@ // run-rustfix -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs #![warn(clippy::manual_rem_euclid)] #![allow(clippy::let_with_type_underscore)] -#[macro_use] -extern crate macro_rules; - -macro_rules! internal_rem_euclid { - () => { - let value: i32 = 5; - let _: i32 = value.rem_euclid(4); - }; -} +extern crate proc_macros; +use proc_macros::{external, inline_macros}; +#[inline_macros] fn main() { let value: i32 = 5; @@ -39,10 +33,16 @@ fn main() { let _: i32 = ((4 % value) + 4) % 4; // Lint in internal macros - internal_rem_euclid!(); + inline!( + let value: i32 = 5; + let _: i32 = value.rem_euclid(4); + ); // Do not lint in external macros - manual_rem_euclid!(); + external!( + let value: i32 = 5; + let _: i32 = ((value % 4) + 4) % 4; + ); } // Should lint for params too diff --git a/tests/ui/manual_rem_euclid.rs b/tests/ui/manual_rem_euclid.rs index 412dbddb426..b275e8a38d2 100644 --- a/tests/ui/manual_rem_euclid.rs +++ b/tests/ui/manual_rem_euclid.rs @@ -1,19 +1,13 @@ // run-rustfix -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs #![warn(clippy::manual_rem_euclid)] #![allow(clippy::let_with_type_underscore)] -#[macro_use] -extern crate macro_rules; - -macro_rules! internal_rem_euclid { - () => { - let value: i32 = 5; - let _: i32 = ((value % 4) + 4) % 4; - }; -} +extern crate proc_macros; +use proc_macros::{external, inline_macros}; +#[inline_macros] fn main() { let value: i32 = 5; @@ -39,10 +33,16 @@ fn main() { let _: i32 = ((4 % value) + 4) % 4; // Lint in internal macros - internal_rem_euclid!(); + inline!( + let value: i32 = 5; + let _: i32 = ((value % 4) + 4) % 4; + ); // Do not lint in external macros - manual_rem_euclid!(); + external!( + let value: i32 = 5; + let _: i32 = ((value % 4) + 4) % 4; + ); } // Should lint for params too diff --git a/tests/ui/manual_rem_euclid.stderr b/tests/ui/manual_rem_euclid.stderr index 6d06654638b..a43707f89c4 100644 --- a/tests/ui/manual_rem_euclid.stderr +++ b/tests/ui/manual_rem_euclid.stderr @@ -1,5 +1,5 @@ error: manual `rem_euclid` implementation - --> $DIR/manual_rem_euclid.rs:20:18 + --> $DIR/manual_rem_euclid.rs:14:18 | LL | let _: i32 = ((value % 4) + 4) % 4; | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `value.rem_euclid(4)` @@ -7,39 +7,36 @@ LL | let _: i32 = ((value % 4) + 4) % 4; = note: `-D clippy::manual-rem-euclid` implied by `-D warnings` error: manual `rem_euclid` implementation - --> $DIR/manual_rem_euclid.rs:21:18 + --> $DIR/manual_rem_euclid.rs:15:18 | LL | let _: i32 = (4 + (value % 4)) % 4; | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `value.rem_euclid(4)` error: manual `rem_euclid` implementation - --> $DIR/manual_rem_euclid.rs:22:18 + --> $DIR/manual_rem_euclid.rs:16:18 | LL | let _: i32 = (value % 4 + 4) % 4; | ^^^^^^^^^^^^^^^^^^^ help: consider using: `value.rem_euclid(4)` error: manual `rem_euclid` implementation - --> $DIR/manual_rem_euclid.rs:23:18 + --> $DIR/manual_rem_euclid.rs:17:18 | LL | let _: i32 = (4 + value % 4) % 4; | ^^^^^^^^^^^^^^^^^^^ help: consider using: `value.rem_euclid(4)` error: manual `rem_euclid` implementation - --> $DIR/manual_rem_euclid.rs:24:22 + --> $DIR/manual_rem_euclid.rs:18:22 | LL | let _: i32 = 1 + (4 + value % 4) % 4; | ^^^^^^^^^^^^^^^^^^^ help: consider using: `value.rem_euclid(4)` error: manual `rem_euclid` implementation - --> $DIR/manual_rem_euclid.rs:13:22 + --> $DIR/manual_rem_euclid.rs:38:22 | LL | let _: i32 = ((value % 4) + 4) % 4; | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `value.rem_euclid(4)` -... -LL | internal_rem_euclid!(); - | ---------------------- in this macro invocation | - = note: this error originates in the macro `internal_rem_euclid` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info) error: manual `rem_euclid` implementation --> $DIR/manual_rem_euclid.rs:50:5 diff --git a/tests/ui/match_single_binding.fixed b/tests/ui/match_single_binding.fixed index 6cfb6661a03..201301cc9b7 100644 --- a/tests/ui/match_single_binding.fixed +++ b/tests/ui/match_single_binding.fixed @@ -1,7 +1,12 @@ // run-rustfix #![warn(clippy::match_single_binding)] -#![allow(unused_variables)] -#![allow(clippy::toplevel_ref_arg, clippy::uninlined_format_args)] +#![allow( + unused, + clippy::let_unit_value, + clippy::no_effect, + clippy::toplevel_ref_arg, + clippy::uninlined_format_args +)] struct Point { x: i32, @@ -109,10 +114,9 @@ fn main() { // Lint let x = 1; - println!("Not an array index start"); + println!("Not an array index start") } -#[allow(dead_code)] fn issue_8723() { let (mut val, idx) = ("a b", 1); @@ -125,16 +129,15 @@ fn issue_8723() { let _ = val; } -#[allow(dead_code)] +fn side_effects() {} + fn issue_9575() { - fn side_effects() {} let _ = || { side_effects(); - println!("Needs curlies"); + println!("Needs curlies") }; } -#[allow(dead_code)] fn issue_9725(r: Option) { let x = r; match x { @@ -146,3 +149,25 @@ fn issue_9725(r: Option) { }, }; } + +fn issue_10447() -> usize { + (); + + let a = (); + + side_effects(); + + let b = side_effects(); + + println!("1"); + + let c = println!("1"); + + let in_expr = [ + (), + side_effects(), + println!("1"), + ]; + + 2 +} diff --git a/tests/ui/match_single_binding.rs b/tests/ui/match_single_binding.rs index f188aeb5f2f..8b047b19ce9 100644 --- a/tests/ui/match_single_binding.rs +++ b/tests/ui/match_single_binding.rs @@ -1,7 +1,12 @@ // run-rustfix #![warn(clippy::match_single_binding)] -#![allow(unused_variables)] -#![allow(clippy::toplevel_ref_arg, clippy::uninlined_format_args)] +#![allow( + unused, + clippy::let_unit_value, + clippy::no_effect, + clippy::toplevel_ref_arg, + clippy::uninlined_format_args +)] struct Point { x: i32, @@ -127,7 +132,6 @@ fn main() { } } -#[allow(dead_code)] fn issue_8723() { let (mut val, idx) = ("a b", 1); @@ -141,15 +145,14 @@ fn issue_8723() { let _ = val; } -#[allow(dead_code)] +fn side_effects() {} + fn issue_9575() { - fn side_effects() {} let _ = || match side_effects() { _ => println!("Needs curlies"), }; } -#[allow(dead_code)] fn issue_9725(r: Option) { match r { x => match x { @@ -162,3 +165,43 @@ fn issue_9725(r: Option) { }, }; } + +fn issue_10447() -> usize { + match 1 { + _ => (), + } + + let a = match 1 { + _ => (), + }; + + match 1 { + _ => side_effects(), + } + + let b = match 1 { + _ => side_effects(), + }; + + match 1 { + _ => println!("1"), + } + + let c = match 1 { + _ => println!("1"), + }; + + let in_expr = [ + match 1 { + _ => (), + }, + match 1 { + _ => side_effects(), + }, + match 1 { + _ => println!("1"), + }, + ]; + + 2 +} diff --git a/tests/ui/match_single_binding.stderr b/tests/ui/match_single_binding.stderr index e960d64ad2b..9d16af76c6a 100644 --- a/tests/ui/match_single_binding.stderr +++ b/tests/ui/match_single_binding.stderr @@ -1,5 +1,5 @@ error: this match could be written as a `let` statement - --> $DIR/match_single_binding.rs:28:5 + --> $DIR/match_single_binding.rs:33:5 | LL | / match (a, b, c) { LL | | (x, y, z) => { @@ -18,7 +18,7 @@ LL + } | error: this match could be written as a `let` statement - --> $DIR/match_single_binding.rs:34:5 + --> $DIR/match_single_binding.rs:39:5 | LL | / match (a, b, c) { LL | | (x, y, z) => println!("{} {} {}", x, y, z), @@ -32,7 +32,7 @@ LL + println!("{} {} {}", x, y, z); | error: this match could be replaced by its body itself - --> $DIR/match_single_binding.rs:51:5 + --> $DIR/match_single_binding.rs:56:5 | LL | / match a { LL | | _ => println!("whatever"), @@ -40,7 +40,7 @@ LL | | } | |_____^ help: consider using the match body instead: `println!("whatever");` error: this match could be replaced by its body itself - --> $DIR/match_single_binding.rs:55:5 + --> $DIR/match_single_binding.rs:60:5 | LL | / match a { LL | | _ => { @@ -59,7 +59,7 @@ LL + } | error: this match could be replaced by its body itself - --> $DIR/match_single_binding.rs:62:5 + --> $DIR/match_single_binding.rs:67:5 | LL | / match a { LL | | _ => { @@ -81,7 +81,7 @@ LL + } | error: this match could be written as a `let` statement - --> $DIR/match_single_binding.rs:72:5 + --> $DIR/match_single_binding.rs:77:5 | LL | / match p { LL | | Point { x, y } => println!("Coords: ({}, {})", x, y), @@ -95,7 +95,7 @@ LL + println!("Coords: ({}, {})", x, y); | error: this match could be written as a `let` statement - --> $DIR/match_single_binding.rs:76:5 + --> $DIR/match_single_binding.rs:81:5 | LL | / match p { LL | | Point { x: x1, y: y1 } => println!("Coords: ({}, {})", x1, y1), @@ -109,7 +109,7 @@ LL + println!("Coords: ({}, {})", x1, y1); | error: this match could be written as a `let` statement - --> $DIR/match_single_binding.rs:81:5 + --> $DIR/match_single_binding.rs:86:5 | LL | / match x { LL | | ref r => println!("Got a reference to {}", r), @@ -123,7 +123,7 @@ LL + println!("Got a reference to {}", r); | error: this match could be written as a `let` statement - --> $DIR/match_single_binding.rs:86:5 + --> $DIR/match_single_binding.rs:91:5 | LL | / match x { LL | | ref mut mr => println!("Got a mutable reference to {}", mr), @@ -137,7 +137,7 @@ LL + println!("Got a mutable reference to {}", mr); | error: this match could be written as a `let` statement - --> $DIR/match_single_binding.rs:90:5 + --> $DIR/match_single_binding.rs:95:5 | LL | / let product = match coords() { LL | | Point { x, y } => x * y, @@ -151,7 +151,7 @@ LL + let product = x * y; | error: this match could be written as a `let` statement - --> $DIR/match_single_binding.rs:98:18 + --> $DIR/match_single_binding.rs:103:18 | LL | .map(|i| match i.unwrap() { | __________________^ @@ -168,16 +168,16 @@ LL ~ }) | error: this match could be replaced by its body itself - --> $DIR/match_single_binding.rs:124:5 + --> $DIR/match_single_binding.rs:129:5 | LL | / match x { LL | | // => LL | | _ => println!("Not an array index start"), LL | | } - | |_____^ help: consider using the match body instead: `println!("Not an array index start");` + | |_____^ help: consider using the match body instead: `println!("Not an array index start")` error: this assignment could be simplified - --> $DIR/match_single_binding.rs:134:5 + --> $DIR/match_single_binding.rs:138:5 | LL | / val = match val.split_at(idx) { LL | | (pre, suf) => { @@ -197,7 +197,7 @@ LL ~ }; | error: this match could be replaced by its scrutinee and body - --> $DIR/match_single_binding.rs:147:16 + --> $DIR/match_single_binding.rs:151:16 | LL | let _ = || match side_effects() { | ________________^ @@ -209,12 +209,12 @@ help: consider using the scrutinee and body instead | LL ~ let _ = || { LL + side_effects(); -LL + println!("Needs curlies"); +LL + println!("Needs curlies") LL ~ }; | error: this match could be written as a `let` statement - --> $DIR/match_single_binding.rs:154:5 + --> $DIR/match_single_binding.rs:157:5 | LL | / match r { LL | | x => match x { @@ -238,5 +238,80 @@ LL + }, LL ~ }; | -error: aborting due to 15 previous errors +error: this match could be replaced by its body itself + --> $DIR/match_single_binding.rs:170:5 + | +LL | / match 1 { +LL | | _ => (), +LL | | } + | |_____^ help: consider using the match body instead: `();` + +error: this match could be replaced by its body itself + --> $DIR/match_single_binding.rs:174:13 + | +LL | let a = match 1 { + | _____________^ +LL | | _ => (), +LL | | }; + | |_____^ help: consider using the match body instead: `()` + +error: this match could be replaced by its body itself + --> $DIR/match_single_binding.rs:178:5 + | +LL | / match 1 { +LL | | _ => side_effects(), +LL | | } + | |_____^ help: consider using the match body instead: `side_effects();` + +error: this match could be replaced by its body itself + --> $DIR/match_single_binding.rs:182:13 + | +LL | let b = match 1 { + | _____________^ +LL | | _ => side_effects(), +LL | | }; + | |_____^ help: consider using the match body instead: `side_effects()` + +error: this match could be replaced by its body itself + --> $DIR/match_single_binding.rs:186:5 + | +LL | / match 1 { +LL | | _ => println!("1"), +LL | | } + | |_____^ help: consider using the match body instead: `println!("1");` + +error: this match could be replaced by its body itself + --> $DIR/match_single_binding.rs:190:13 + | +LL | let c = match 1 { + | _____________^ +LL | | _ => println!("1"), +LL | | }; + | |_____^ help: consider using the match body instead: `println!("1")` + +error: this match could be replaced by its body itself + --> $DIR/match_single_binding.rs:195:9 + | +LL | / match 1 { +LL | | _ => (), +LL | | }, + | |_________^ help: consider using the match body instead: `()` + +error: this match could be replaced by its body itself + --> $DIR/match_single_binding.rs:198:9 + | +LL | / match 1 { +LL | | _ => side_effects(), +LL | | }, + | |_________^ help: consider using the match body instead: `side_effects()` + +error: this match could be replaced by its body itself + --> $DIR/match_single_binding.rs:201:9 + | +LL | / match 1 { +LL | | _ => println!("1"), +LL | | }, + | |_________^ help: consider using the match body instead: `println!("1")` + +error: aborting due to 24 previous errors diff --git a/tests/ui/match_single_binding2.fixed b/tests/ui/match_single_binding2.fixed index 6a7db67e311..e3cf56a4293 100644 --- a/tests/ui/match_single_binding2.fixed +++ b/tests/ui/match_single_binding2.fixed @@ -30,7 +30,7 @@ fn main() { #[rustfmt::skip] Some((first, _second)) => { let (a, b) = get_tup(); - println!("a {:?} and b {:?}", a, b); + println!("a {:?} and b {:?}", a, b) }, None => println!("nothing"), } @@ -49,5 +49,5 @@ fn main() { 0 => 1, _ => 2, }; - println!("Single branch"); + println!("Single branch") } diff --git a/tests/ui/match_single_binding2.stderr b/tests/ui/match_single_binding2.stderr index 22bf7d8be4a..e180b93e76d 100644 --- a/tests/ui/match_single_binding2.stderr +++ b/tests/ui/match_single_binding2.stderr @@ -27,7 +27,7 @@ LL | | } help: consider using a `let` statement | LL ~ let (a, b) = get_tup(); -LL + println!("a {:?} and b {:?}", a, b); +LL + println!("a {:?} and b {:?}", a, b) | error: this match could be replaced by its scrutinee and body @@ -61,7 +61,7 @@ LL ~ match x { LL + 0 => 1, LL + _ => 2, LL + }; -LL + println!("Single branch"); +LL + println!("Single branch") | error: aborting due to 4 previous errors diff --git a/tests/ui/mem_replace_macro.rs b/tests/ui/mem_replace_macro.rs index 0c09344b80d..3932e7d00c1 100644 --- a/tests/ui/mem_replace_macro.rs +++ b/tests/ui/mem_replace_macro.rs @@ -1,21 +1,12 @@ -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs #![warn(clippy::mem_replace_with_default)] -#[macro_use] -extern crate macro_rules; - -macro_rules! take { - ($s:expr) => { - std::mem::replace($s, Default::default()) - }; -} - -fn replace_with_default() { - let s = &mut String::from("foo"); - take!(s); - take_external!(s); -} +extern crate proc_macros; +use proc_macros::{external, inline_macros}; +#[inline_macros] fn main() { - replace_with_default(); + let s = &mut String::from("foo"); + inline!(std::mem::replace($s, Default::default())); + external!(std::mem::replace($s, Default::default())); } diff --git a/tests/ui/mem_replace_macro.stderr b/tests/ui/mem_replace_macro.stderr index dd69ab8b5ef..35dda93da3d 100644 --- a/tests/ui/mem_replace_macro.stderr +++ b/tests/ui/mem_replace_macro.stderr @@ -1,14 +1,11 @@ error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` - --> $DIR/mem_replace_macro.rs:9:9 + --> $DIR/mem_replace_macro.rs:10:13 | -LL | std::mem::replace($s, Default::default()) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -... -LL | take!(s); - | -------- in this macro invocation +LL | inline!(std::mem::replace($s, Default::default())); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::mem-replace-with-default` implied by `-D warnings` - = note: this error originates in the macro `take` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error diff --git a/tests/ui/missing_const_for_fn/cant_be_const.rs b/tests/ui/missing_const_for_fn/cant_be_const.rs index 75cace18167..e6f88c6e622 100644 --- a/tests/ui/missing_const_for_fn/cant_be_const.rs +++ b/tests/ui/missing_const_for_fn/cant_be_const.rs @@ -3,15 +3,15 @@ //! The .stderr output of this test should be empty. Otherwise it's a bug somewhere. // aux-build:helper.rs -// aux-build:../../auxiliary/proc_macro_with_span.rs +// aux-build:../../auxiliary/proc_macros.rs #![warn(clippy::missing_const_for_fn)] #![feature(start)] extern crate helper; -extern crate proc_macro_with_span; +extern crate proc_macros; -use proc_macro_with_span::with_span; +use proc_macros::with_span; struct Game; diff --git a/tests/ui/missing_doc.rs b/tests/ui/missing_doc.rs index 590ad63c90b..5752048949c 100644 --- a/tests/ui/missing_doc.rs +++ b/tests/ui/missing_doc.rs @@ -1,5 +1,5 @@ // needs-asm-support -// aux-build: proc_macro_with_span.rs +// aux-build: proc_macros.rs #![warn(clippy::missing_docs_in_private_items)] // When denying at the crate level, be sure to not get random warnings from the @@ -8,9 +8,9 @@ //! Some garbage docs for the crate here #![doc = "More garbage"] -extern crate proc_macro_with_span; +extern crate proc_macros; -use proc_macro_with_span::with_span; +use proc_macros::with_span; use std::arch::global_asm; type Typedef = String; diff --git a/tests/ui/missing_doc_impl.rs b/tests/ui/missing_doc_impl.rs index 0396d1193ff..e2d49b0907d 100644 --- a/tests/ui/missing_doc_impl.rs +++ b/tests/ui/missing_doc_impl.rs @@ -1,4 +1,4 @@ -// aux-build: proc_macro_with_span.rs +// aux-build: proc_macros.rs #![warn(clippy::missing_docs_in_private_items)] #![allow(dead_code)] @@ -7,8 +7,8 @@ //! Some garbage docs for the crate here #![doc = "More garbage"] -extern crate proc_macro_with_span; -use proc_macro_with_span::with_span; +extern crate proc_macros; +use proc_macros::with_span; struct Foo { a: isize, diff --git a/tests/ui/mistyped_literal_suffix.fixed b/tests/ui/mistyped_literal_suffix.fixed index becb9562a84..9a47d7c56ed 100644 --- a/tests/ui/mistyped_literal_suffix.fixed +++ b/tests/ui/mistyped_literal_suffix.fixed @@ -1,5 +1,5 @@ // run-rustfix -// aux-build: proc_macro_with_span.rs +// aux-build: proc_macros.rs #![allow( dead_code, @@ -10,8 +10,8 @@ clippy::unusual_byte_groupings )] -extern crate proc_macro_with_span; -use proc_macro_with_span::with_span; +extern crate proc_macros; +use proc_macros::with_span; fn main() { let fail14 = 2_i32; diff --git a/tests/ui/mistyped_literal_suffix.rs b/tests/ui/mistyped_literal_suffix.rs index ee841bcd7e4..04261cba55a 100644 --- a/tests/ui/mistyped_literal_suffix.rs +++ b/tests/ui/mistyped_literal_suffix.rs @@ -1,5 +1,5 @@ // run-rustfix -// aux-build: proc_macro_with_span.rs +// aux-build: proc_macros.rs #![allow( dead_code, @@ -10,8 +10,8 @@ clippy::unusual_byte_groupings )] -extern crate proc_macro_with_span; -use proc_macro_with_span::with_span; +extern crate proc_macros; +use proc_macros::with_span; fn main() { let fail14 = 2_32; diff --git a/tests/ui/multiple_unsafe_ops_per_block.rs b/tests/ui/multiple_unsafe_ops_per_block.rs index 5073685c9f0..9082f1675a8 100644 --- a/tests/ui/multiple_unsafe_ops_per_block.rs +++ b/tests/ui/multiple_unsafe_ops_per_block.rs @@ -1,12 +1,12 @@ -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs #![allow(unused)] #![allow(deref_nullptr)] #![allow(clippy::unnecessary_operation)] #![allow(clippy::drop_copy)] #![warn(clippy::multiple_unsafe_ops_per_block)] -#[macro_use] -extern crate macro_rules; +extern crate proc_macros; +use proc_macros::external; use core::arch::asm; @@ -113,7 +113,10 @@ unsafe fn read_char_good(ptr: *const u8) -> char { // no lint fn issue10259() { - unsafe_macro!(); + external!(unsafe { + *core::ptr::null::<()>(); + *core::ptr::null::<()>(); + }); } fn _fn_ptr(x: unsafe fn()) { diff --git a/tests/ui/multiple_unsafe_ops_per_block.stderr b/tests/ui/multiple_unsafe_ops_per_block.stderr index e0c1d3801f7..badc284ec42 100644 --- a/tests/ui/multiple_unsafe_ops_per_block.stderr +++ b/tests/ui/multiple_unsafe_ops_per_block.stderr @@ -126,7 +126,7 @@ LL | unsafe { char::from_u32_unchecked(*ptr.cast::()) } | ^^^^^^^^^^^^^^^^^^ error: this `unsafe` block contains 2 unsafe operations, expected only one - --> $DIR/multiple_unsafe_ops_per_block.rs:120:5 + --> $DIR/multiple_unsafe_ops_per_block.rs:123:5 | LL | / unsafe { LL | | x(); @@ -135,18 +135,18 @@ LL | | } | |_____^ | note: unsafe function call occurs here - --> $DIR/multiple_unsafe_ops_per_block.rs:121:9 + --> $DIR/multiple_unsafe_ops_per_block.rs:124:9 | LL | x(); | ^^^ note: unsafe function call occurs here - --> $DIR/multiple_unsafe_ops_per_block.rs:122:9 + --> $DIR/multiple_unsafe_ops_per_block.rs:125:9 | LL | x(); | ^^^ error: this `unsafe` block contains 2 unsafe operations, expected only one - --> $DIR/multiple_unsafe_ops_per_block.rs:131:9 + --> $DIR/multiple_unsafe_ops_per_block.rs:134:9 | LL | / unsafe { LL | | T::X(); @@ -155,18 +155,18 @@ LL | | } | |_________^ | note: unsafe function call occurs here - --> $DIR/multiple_unsafe_ops_per_block.rs:132:13 + --> $DIR/multiple_unsafe_ops_per_block.rs:135:13 | LL | T::X(); | ^^^^^^ note: unsafe function call occurs here - --> $DIR/multiple_unsafe_ops_per_block.rs:133:13 + --> $DIR/multiple_unsafe_ops_per_block.rs:136:13 | LL | T::X(); | ^^^^^^ error: this `unsafe` block contains 2 unsafe operations, expected only one - --> $DIR/multiple_unsafe_ops_per_block.rs:141:5 + --> $DIR/multiple_unsafe_ops_per_block.rs:144:5 | LL | / unsafe { LL | | x.0(); @@ -175,12 +175,12 @@ LL | | } | |_____^ | note: unsafe function call occurs here - --> $DIR/multiple_unsafe_ops_per_block.rs:142:9 + --> $DIR/multiple_unsafe_ops_per_block.rs:145:9 | LL | x.0(); | ^^^^^ note: unsafe function call occurs here - --> $DIR/multiple_unsafe_ops_per_block.rs:143:9 + --> $DIR/multiple_unsafe_ops_per_block.rs:146:9 | LL | x.0(); | ^^^^^ diff --git a/tests/ui/must_use_unit.fixed b/tests/ui/must_use_unit.fixed index 6c9aa434ac0..b7d375ff80e 100644 --- a/tests/ui/must_use_unit.fixed +++ b/tests/ui/must_use_unit.fixed @@ -1,11 +1,11 @@ //run-rustfix -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs #![warn(clippy::must_use_unit)] #![allow(clippy::unused_unit)] -#[macro_use] -extern crate macro_rules; +extern crate proc_macros; +use proc_macros::external; pub fn must_use_default() {} @@ -22,5 +22,8 @@ fn main() { must_use_with_note(); // We should not lint in external macros - must_use_unit!(); + external!( + #[must_use] + fn foo() {} + ); } diff --git a/tests/ui/must_use_unit.rs b/tests/ui/must_use_unit.rs index 8a395dc284d..74d6b4ca865 100644 --- a/tests/ui/must_use_unit.rs +++ b/tests/ui/must_use_unit.rs @@ -1,11 +1,11 @@ //run-rustfix -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs #![warn(clippy::must_use_unit)] #![allow(clippy::unused_unit)] -#[macro_use] -extern crate macro_rules; +extern crate proc_macros; +use proc_macros::external; #[must_use] pub fn must_use_default() {} @@ -22,5 +22,8 @@ fn main() { must_use_with_note(); // We should not lint in external macros - must_use_unit!(); + external!( + #[must_use] + fn foo() {} + ); } diff --git a/tests/ui/mut_mut.rs b/tests/ui/mut_mut.rs index ee3a856566c..06bb085442a 100644 --- a/tests/ui/mut_mut.rs +++ b/tests/ui/mut_mut.rs @@ -1,10 +1,10 @@ -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs #![warn(clippy::mut_mut)] #![allow(unused)] #![allow(clippy::no_effect, clippy::uninlined_format_args, clippy::unnecessary_operation)] -#[macro_use] -extern crate macro_rules; +extern crate proc_macros; +use proc_macros::{external, inline_macros}; fn fun(x: &mut &mut u32) -> bool { **x > 0 @@ -21,6 +21,7 @@ macro_rules! mut_ptr { } #[allow(unused_mut, unused_variables)] +#[inline_macros] fn main() { let mut x = &mut &mut 1u32; { @@ -37,7 +38,7 @@ fn main() { ***y + **x; } - let mut z = mut_ptr!(&mut 3u32); + let mut z = inline!(&mut $(&mut 3u32)); } fn issue939() { @@ -55,7 +56,7 @@ fn issue939() { fn issue6922() { // do not lint from an external macro - mut_mut!(); + external!(let mut_mut_ty: &mut &mut u32 = &mut &mut 1u32;); } mod issue9035 { diff --git a/tests/ui/mut_mut.stderr b/tests/ui/mut_mut.stderr index 6820a85aa54..93b857eb207 100644 --- a/tests/ui/mut_mut.stderr +++ b/tests/ui/mut_mut.stderr @@ -7,54 +7,51 @@ LL | fn fun(x: &mut &mut u32) -> bool { = note: `-D clippy::mut-mut` implied by `-D warnings` error: generally you want to avoid `&mut &mut _` if possible - --> $DIR/mut_mut.rs:25:17 + --> $DIR/mut_mut.rs:26:17 | LL | let mut x = &mut &mut 1u32; | ^^^^^^^^^^^^^^ error: generally you want to avoid `&mut &mut _` if possible - --> $DIR/mut_mut.rs:19:9 + --> $DIR/mut_mut.rs:41:25 | -LL | &mut $p - | ^^^^^^^ -... -LL | let mut z = mut_ptr!(&mut 3u32); - | ------------------- in this macro invocation +LL | let mut z = inline!(&mut $(&mut 3u32)); + | ^ | - = note: this error originates in the macro `mut_ptr` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info) error: this expression mutably borrows a mutable reference. Consider reborrowing - --> $DIR/mut_mut.rs:27:21 + --> $DIR/mut_mut.rs:28:21 | LL | let mut y = &mut x; | ^^^^^^ error: generally you want to avoid `&mut &mut _` if possible - --> $DIR/mut_mut.rs:31:32 + --> $DIR/mut_mut.rs:32:32 | LL | let y: &mut &mut u32 = &mut &mut 2; | ^^^^^^^^^^^ error: generally you want to avoid `&mut &mut _` if possible - --> $DIR/mut_mut.rs:31:16 + --> $DIR/mut_mut.rs:32:16 | LL | let y: &mut &mut u32 = &mut &mut 2; | ^^^^^^^^^^^^^ error: generally you want to avoid `&mut &mut _` if possible - --> $DIR/mut_mut.rs:36:37 + --> $DIR/mut_mut.rs:37:37 | LL | let y: &mut &mut &mut u32 = &mut &mut &mut 2; | ^^^^^^^^^^^^^^^^ error: generally you want to avoid `&mut &mut _` if possible - --> $DIR/mut_mut.rs:36:16 + --> $DIR/mut_mut.rs:37:16 | LL | let y: &mut &mut &mut u32 = &mut &mut &mut 2; | ^^^^^^^^^^^^^^^^^^ error: generally you want to avoid `&mut &mut _` if possible - --> $DIR/mut_mut.rs:36:21 + --> $DIR/mut_mut.rs:37:21 | LL | let y: &mut &mut &mut u32 = &mut &mut &mut 2; | ^^^^^^^^^^^^^ diff --git a/tests/ui/needless_late_init.fixed b/tests/ui/needless_late_init.fixed index 17f2227ba91..86d899bb46c 100644 --- a/tests/ui/needless_late_init.fixed +++ b/tests/ui/needless_late_init.fixed @@ -1,4 +1,5 @@ // run-rustfix +// aux-build:proc_macros.rs #![feature(let_chains)] #![allow(unused)] #![allow( @@ -10,6 +11,8 @@ clippy::uninlined_format_args )] +extern crate proc_macros; + use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet}; use std::rc::Rc; @@ -138,6 +141,7 @@ const fn in_const() -> &'static str { a } +#[proc_macros::inline_macros] fn does_not_lint() { let z; if false { @@ -195,35 +199,27 @@ fn does_not_lint() { } y = 3; - macro_rules! assign { - ($i:ident) => { - $i = 1; - }; - } let x; - assign!(x); + inline!($x = 1;); let x; if true { - assign!(x); + inline!($x = 1;); } else { x = 2; } - macro_rules! in_macro { - () => { - let x; - x = 1; + inline!({ + let x; + x = 1; - let x; - if true { - x = 1; - } else { - x = 2; - } - }; - } - in_macro!(); + let x; + if true { + x = 1; + } else { + x = 2; + } + }); // ignore if-lets - https://github.com/rust-lang/rust-clippy/issues/8613 let x; diff --git a/tests/ui/needless_late_init.rs b/tests/ui/needless_late_init.rs index d84457a2987..969afb38edf 100644 --- a/tests/ui/needless_late_init.rs +++ b/tests/ui/needless_late_init.rs @@ -1,4 +1,5 @@ // run-rustfix +// aux-build:proc_macros.rs #![feature(let_chains)] #![allow(unused)] #![allow( @@ -10,6 +11,8 @@ clippy::uninlined_format_args )] +extern crate proc_macros; + use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet}; use std::rc::Rc; @@ -138,6 +141,7 @@ const fn in_const() -> &'static str { a } +#[proc_macros::inline_macros] fn does_not_lint() { let z; if false { @@ -195,35 +199,27 @@ fn does_not_lint() { } y = 3; - macro_rules! assign { - ($i:ident) => { - $i = 1; - }; - } let x; - assign!(x); + inline!($x = 1;); let x; if true { - assign!(x); + inline!($x = 1;); } else { x = 2; } - macro_rules! in_macro { - () => { - let x; - x = 1; + inline!({ + let x; + x = 1; - let x; - if true { - x = 1; - } else { - x = 2; - } - }; - } - in_macro!(); + let x; + if true { + x = 1; + } else { + x = 2; + } + }); // ignore if-lets - https://github.com/rust-lang/rust-clippy/issues/8613 let x; diff --git a/tests/ui/needless_late_init.stderr b/tests/ui/needless_late_init.stderr index 0a256fb4a13..eff782f8bf1 100644 --- a/tests/ui/needless_late_init.stderr +++ b/tests/ui/needless_late_init.stderr @@ -1,5 +1,5 @@ error: unneeded late initialization - --> $DIR/needless_late_init.rs:24:5 + --> $DIR/needless_late_init.rs:27:5 | LL | let a; | ^^^^^^ created here @@ -13,7 +13,7 @@ LL | let a = "zero"; | ~~~~~ error: unneeded late initialization - --> $DIR/needless_late_init.rs:27:5 + --> $DIR/needless_late_init.rs:30:5 | LL | let b; | ^^^^^^ created here @@ -27,7 +27,7 @@ LL | let b = 1; | ~~~~~ error: unneeded late initialization - --> $DIR/needless_late_init.rs:28:5 + --> $DIR/needless_late_init.rs:31:5 | LL | let c; | ^^^^^^ created here @@ -41,7 +41,7 @@ LL | let c = 2; | ~~~~~ error: unneeded late initialization - --> $DIR/needless_late_init.rs:32:5 + --> $DIR/needless_late_init.rs:35:5 | LL | let d: usize; | ^^^^^^^^^^^^^ created here @@ -54,7 +54,7 @@ LL | let d: usize = 1; | ~~~~~~~~~~~~ error: unneeded late initialization - --> $DIR/needless_late_init.rs:35:5 + --> $DIR/needless_late_init.rs:38:5 | LL | let e; | ^^^^^^ created here @@ -67,7 +67,7 @@ LL | let e = format!("{}", d); | ~~~~~ error: unneeded late initialization - --> $DIR/needless_late_init.rs:40:5 + --> $DIR/needless_late_init.rs:43:5 | LL | let a; | ^^^^^^ @@ -88,7 +88,7 @@ LL | }; | + error: unneeded late initialization - --> $DIR/needless_late_init.rs:49:5 + --> $DIR/needless_late_init.rs:52:5 | LL | let b; | ^^^^^^ @@ -109,7 +109,7 @@ LL | }; | + error: unneeded late initialization - --> $DIR/needless_late_init.rs:56:5 + --> $DIR/needless_late_init.rs:59:5 | LL | let d; | ^^^^^^ @@ -130,7 +130,7 @@ LL | }; | + error: unneeded late initialization - --> $DIR/needless_late_init.rs:64:5 + --> $DIR/needless_late_init.rs:67:5 | LL | let e; | ^^^^^^ @@ -151,7 +151,7 @@ LL | }; | + error: unneeded late initialization - --> $DIR/needless_late_init.rs:71:5 + --> $DIR/needless_late_init.rs:74:5 | LL | let f; | ^^^^^^ @@ -167,7 +167,7 @@ LL + 1 => "three", | error: unneeded late initialization - --> $DIR/needless_late_init.rs:77:5 + --> $DIR/needless_late_init.rs:80:5 | LL | let g: usize; | ^^^^^^^^^^^^^ @@ -187,7 +187,7 @@ LL | }; | + error: unneeded late initialization - --> $DIR/needless_late_init.rs:85:5 + --> $DIR/needless_late_init.rs:88:5 | LL | let x; | ^^^^^^ created here @@ -201,7 +201,7 @@ LL | let x = 1; | ~~~~~ error: unneeded late initialization - --> $DIR/needless_late_init.rs:89:5 + --> $DIR/needless_late_init.rs:92:5 | LL | let x; | ^^^^^^ created here @@ -215,7 +215,7 @@ LL | let x = SignificantDrop; | ~~~~~ error: unneeded late initialization - --> $DIR/needless_late_init.rs:93:5 + --> $DIR/needless_late_init.rs:96:5 | LL | let x; | ^^^^^^ created here @@ -229,7 +229,7 @@ LL | let x = SignificantDrop; | ~~~~~ error: unneeded late initialization - --> $DIR/needless_late_init.rs:112:5 + --> $DIR/needless_late_init.rs:115:5 | LL | let a; | ^^^^^^ @@ -250,7 +250,7 @@ LL | }; | + error: unneeded late initialization - --> $DIR/needless_late_init.rs:129:5 + --> $DIR/needless_late_init.rs:132:5 | LL | let a; | ^^^^^^ diff --git a/tests/ui/needless_lifetimes.fixed b/tests/ui/needless_lifetimes.fixed index f0f1f9298ac..e6ead69d148 100644 --- a/tests/ui/needless_lifetimes.fixed +++ b/tests/ui/needless_lifetimes.fixed @@ -1,5 +1,5 @@ // run-rustfix -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs #![warn(clippy::needless_lifetimes)] #![allow( @@ -12,8 +12,8 @@ clippy::get_first )] -#[macro_use] -extern crate macro_rules; +extern crate proc_macros; +use proc_macros::inline_macros; fn distinct_lifetimes(_x: &u8, _y: &u8, _z: u8) {} @@ -502,30 +502,29 @@ mod pr_9743_output_lifetime_checks { } } +#[inline_macros] mod in_macro { - macro_rules! local_one_input_macro { - () => { - fn one_input(x: &u8) -> &u8 { - unimplemented!() - } - }; - } + use proc_macros::external; // lint local macro expands to function with needless lifetimes - local_one_input_macro!(); - - // no lint on external macro - macro_rules::needless_lifetime!(); - - macro_rules! expanded_lifetime { - ($l:lifetime) => { - fn f<$l>(arg: &$l str) -> &$l str { - arg - } + inline! { + fn one_input(x: &u8) -> &u8 { + unimplemented!() } } - expanded_lifetime!('a); + // no lint on external macro + external! { + fn needless_lifetime<'a>(x: &'a u8) -> &'a u8 { + unimplemented!() + } + } + + inline! { + fn f<$'a>(arg: &$'a str) -> &$'a str { + arg + } + } } mod issue5787 { diff --git a/tests/ui/needless_lifetimes.rs b/tests/ui/needless_lifetimes.rs index ddfd1043003..06eb430506f 100644 --- a/tests/ui/needless_lifetimes.rs +++ b/tests/ui/needless_lifetimes.rs @@ -1,5 +1,5 @@ // run-rustfix -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs #![warn(clippy::needless_lifetimes)] #![allow( @@ -12,8 +12,8 @@ clippy::get_first )] -#[macro_use] -extern crate macro_rules; +extern crate proc_macros; +use proc_macros::inline_macros; fn distinct_lifetimes<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: u8) {} @@ -502,30 +502,29 @@ mod pr_9743_output_lifetime_checks { } } +#[inline_macros] mod in_macro { - macro_rules! local_one_input_macro { - () => { - fn one_input<'a>(x: &'a u8) -> &'a u8 { - unimplemented!() - } - }; - } + use proc_macros::external; // lint local macro expands to function with needless lifetimes - local_one_input_macro!(); - - // no lint on external macro - macro_rules::needless_lifetime!(); - - macro_rules! expanded_lifetime { - ($l:lifetime) => { - fn f<$l>(arg: &$l str) -> &$l str { - arg - } + inline! { + fn one_input<'a>(x: &'a u8) -> &'a u8 { + unimplemented!() } } - expanded_lifetime!('a); + // no lint on external macro + external! { + fn needless_lifetime<'a>(x: &'a u8) -> &'a u8 { + unimplemented!() + } + } + + inline! { + fn f<$'a>(arg: &$'a str) -> &$'a str { + arg + } + } } mod issue5787 { diff --git a/tests/ui/needless_lifetimes.stderr b/tests/ui/needless_lifetimes.stderr index 4e3c8f20d8c..86acc4e0046 100644 --- a/tests/ui/needless_lifetimes.stderr +++ b/tests/ui/needless_lifetimes.stderr @@ -540,19 +540,16 @@ LL + fn multiple_inputs_output_not_elided<'b>(x: &u8, y: &'b u8, z: &'b u8) | error: the following explicit lifetimes could be elided: 'a - --> $DIR/needless_lifetimes.rs:508:13 + --> $DIR/needless_lifetimes.rs:511:9 | -LL | fn one_input<'a>(x: &'a u8) -> &'a u8 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -... -LL | local_one_input_macro!(); - | ------------------------ in this macro invocation +LL | fn one_input<'a>(x: &'a u8) -> &'a u8 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: this error originates in the macro `local_one_input_macro` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `__inline_mac_mod_in_macro` (in Nightly builds, run with -Z macro-backtrace for more info) help: elide the lifetimes | -LL - fn one_input<'a>(x: &'a u8) -> &'a u8 { -LL + fn one_input(x: &u8) -> &u8 { +LL - fn one_input<'a>(x: &'a u8) -> &'a u8 { +LL + fn one_input(x: &u8) -> &u8 { | error: aborting due to 46 previous errors diff --git a/tests/ui/needless_update.rs b/tests/ui/needless_update.rs index b93ff048a62..4e8517cad10 100644 --- a/tests/ui/needless_update.rs +++ b/tests/ui/needless_update.rs @@ -1,5 +1,5 @@ #![warn(clippy::needless_update)] -#![allow(clippy::no_effect)] +#![allow(clippy::no_effect, clippy::unnecessary_struct_initialization)] struct S { pub a: i32, diff --git a/tests/ui/no_effect.rs b/tests/ui/no_effect.rs index ec8a5aa28c5..1e42e1fbabf 100644 --- a/tests/ui/no_effect.rs +++ b/tests/ui/no_effect.rs @@ -1,7 +1,12 @@ #![feature(fn_traits, unboxed_closures)] #![warn(clippy::no_effect_underscore_binding)] #![allow(dead_code, path_statements)] -#![allow(clippy::deref_addrof, clippy::redundant_field_names, clippy::uninlined_format_args)] +#![allow( + clippy::deref_addrof, + clippy::redundant_field_names, + clippy::uninlined_format_args, + clippy::unnecessary_struct_initialization +)] struct Unit; struct Tuple(i32); diff --git a/tests/ui/no_effect.stderr b/tests/ui/no_effect.stderr index 92f6dbfbdba..f10f2bcf2a8 100644 --- a/tests/ui/no_effect.stderr +++ b/tests/ui/no_effect.stderr @@ -1,5 +1,5 @@ error: statement with no effect - --> $DIR/no_effect.rs:92:5 + --> $DIR/no_effect.rs:97:5 | LL | 0; | ^^ @@ -7,151 +7,151 @@ LL | 0; = note: `-D clippy::no-effect` implied by `-D warnings` error: statement with no effect - --> $DIR/no_effect.rs:93:5 + --> $DIR/no_effect.rs:98:5 | LL | s2; | ^^^ error: statement with no effect - --> $DIR/no_effect.rs:94:5 + --> $DIR/no_effect.rs:99:5 | LL | Unit; | ^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:95:5 + --> $DIR/no_effect.rs:100:5 | LL | Tuple(0); | ^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:96:5 + --> $DIR/no_effect.rs:101:5 | LL | Struct { field: 0 }; | ^^^^^^^^^^^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:97:5 + --> $DIR/no_effect.rs:102:5 | LL | Struct { ..s }; | ^^^^^^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:98:5 + --> $DIR/no_effect.rs:103:5 | LL | Union { a: 0 }; | ^^^^^^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:99:5 + --> $DIR/no_effect.rs:104:5 | LL | Enum::Tuple(0); | ^^^^^^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:100:5 + --> $DIR/no_effect.rs:105:5 | LL | Enum::Struct { field: 0 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:101:5 + --> $DIR/no_effect.rs:106:5 | LL | 5 + 6; | ^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:102:5 + --> $DIR/no_effect.rs:107:5 | LL | *&42; | ^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:103:5 + --> $DIR/no_effect.rs:108:5 | LL | &6; | ^^^ error: statement with no effect - --> $DIR/no_effect.rs:104:5 + --> $DIR/no_effect.rs:109:5 | LL | (5, 6, 7); | ^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:105:5 + --> $DIR/no_effect.rs:110:5 | LL | ..; | ^^^ error: statement with no effect - --> $DIR/no_effect.rs:106:5 + --> $DIR/no_effect.rs:111:5 | LL | 5..; | ^^^^ error: statement with no effect - --> $DIR/no_effect.rs:107:5 + --> $DIR/no_effect.rs:112:5 | LL | ..5; | ^^^^ error: statement with no effect - --> $DIR/no_effect.rs:108:5 + --> $DIR/no_effect.rs:113:5 | LL | 5..6; | ^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:109:5 + --> $DIR/no_effect.rs:114:5 | LL | 5..=6; | ^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:110:5 + --> $DIR/no_effect.rs:115:5 | LL | [42, 55]; | ^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:111:5 + --> $DIR/no_effect.rs:116:5 | LL | [42, 55][1]; | ^^^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:112:5 + --> $DIR/no_effect.rs:117:5 | LL | (42, 55).1; | ^^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:113:5 + --> $DIR/no_effect.rs:118:5 | LL | [42; 55]; | ^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:114:5 + --> $DIR/no_effect.rs:119:5 | LL | [42; 55][13]; | ^^^^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:116:5 + --> $DIR/no_effect.rs:121:5 | LL | || x += 5; | ^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:118:5 + --> $DIR/no_effect.rs:123:5 | LL | FooString { s: s }; | ^^^^^^^^^^^^^^^^^^^ error: binding to `_` prefixed variable with no side-effect - --> $DIR/no_effect.rs:119:5 + --> $DIR/no_effect.rs:124:5 | LL | let _unused = 1; | ^^^^^^^^^^^^^^^^ @@ -159,19 +159,19 @@ LL | let _unused = 1; = note: `-D clippy::no-effect-underscore-binding` implied by `-D warnings` error: binding to `_` prefixed variable with no side-effect - --> $DIR/no_effect.rs:120:5 + --> $DIR/no_effect.rs:125:5 | LL | let _penguin = || println!("Some helpful closure"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: binding to `_` prefixed variable with no side-effect - --> $DIR/no_effect.rs:121:5 + --> $DIR/no_effect.rs:126:5 | LL | let _duck = Struct { field: 0 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: binding to `_` prefixed variable with no side-effect - --> $DIR/no_effect.rs:122:5 + --> $DIR/no_effect.rs:127:5 | LL | let _cat = [2, 4, 6, 8][2]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/no_mangle_with_rust_abi.fixed b/tests/ui/no_mangle_with_rust_abi.fixed deleted file mode 100644 index d18dec22a8b..00000000000 --- a/tests/ui/no_mangle_with_rust_abi.fixed +++ /dev/null @@ -1,48 +0,0 @@ -// run-rustfix - -#![allow(unused)] -#![warn(clippy::no_mangle_with_rust_abi)] - -#[no_mangle] -extern "C" fn rust_abi_fn_one(arg_one: u32, arg_two: usize) {} - -#[no_mangle] -pub extern "C" fn rust_abi_fn_two(arg_one: u32, arg_two: usize) {} - -/// # Safety -/// This function shouldn't be called unless the horsemen are ready -#[no_mangle] -pub unsafe extern "C" fn rust_abi_fn_three(arg_one: u32, arg_two: usize) {} - -/// # Safety -/// This function shouldn't be called unless the horsemen are ready -#[no_mangle] -unsafe extern "C" fn rust_abi_fn_four(arg_one: u32, arg_two: usize) {} - -#[no_mangle] -extern "C" fn rust_abi_multiline_function_really_long_name_to_overflow_args_to_multiple_lines( - arg_one: u32, - arg_two: usize, -) -> u32 { - 0 -} - -// Must not run on functions that explicitly opt in to Rust ABI with `extern "Rust"` -#[no_mangle] -#[rustfmt::skip] -extern "Rust" fn rust_abi_fn_explicit_opt_in(arg_one: u32, arg_two: usize) {} - -fn rust_abi_fn_again(arg_one: u32, arg_two: usize) {} - -#[no_mangle] -extern "C" fn c_abi_fn(arg_one: u32, arg_two: usize) {} - -extern "C" fn c_abi_fn_again(arg_one: u32, arg_two: usize) {} - -extern "C" { - fn c_abi_in_block(arg_one: u32, arg_two: usize); -} - -fn main() { - // test code goes here -} diff --git a/tests/ui/no_mangle_with_rust_abi.rs b/tests/ui/no_mangle_with_rust_abi.rs index 481e1b6d961..b32e721110e 100644 --- a/tests/ui/no_mangle_with_rust_abi.rs +++ b/tests/ui/no_mangle_with_rust_abi.rs @@ -1,5 +1,3 @@ -// run-rustfix - #![allow(unused)] #![warn(clippy::no_mangle_with_rust_abi)] diff --git a/tests/ui/no_mangle_with_rust_abi.stderr b/tests/ui/no_mangle_with_rust_abi.stderr index 71517d31809..da5d31d8f2d 100644 --- a/tests/ui/no_mangle_with_rust_abi.stderr +++ b/tests/ui/no_mangle_with_rust_abi.stderr @@ -1,31 +1,66 @@ -error: attribute #[no_mangle] set on a Rust ABI function - --> $DIR/no_mangle_with_rust_abi.rs:7:1 +error: `#[no_mangle]` set on a function with the default (`Rust`) ABI + --> $DIR/no_mangle_with_rust_abi.rs:5:1 | LL | fn rust_abi_fn_one(arg_one: u32, arg_two: usize) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `extern "C" fn rust_abi_fn_one(arg_one: u32, arg_two: usize)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::no-mangle-with-rust-abi` implied by `-D warnings` +help: set an ABI + | +LL | extern "C" fn rust_abi_fn_one(arg_one: u32, arg_two: usize) {} + | ++++++++++ +help: or explicitly set the default + | +LL | extern "Rust" fn rust_abi_fn_one(arg_one: u32, arg_two: usize) {} + | +++++++++++++ -error: attribute #[no_mangle] set on a Rust ABI function - --> $DIR/no_mangle_with_rust_abi.rs:10:1 +error: `#[no_mangle]` set on a function with the default (`Rust`) ABI + --> $DIR/no_mangle_with_rust_abi.rs:8:1 | LL | pub fn rust_abi_fn_two(arg_one: u32, arg_two: usize) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `pub extern "C" fn rust_abi_fn_two(arg_one: u32, arg_two: usize)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: set an ABI + | +LL | pub extern "C" fn rust_abi_fn_two(arg_one: u32, arg_two: usize) {} + | ++++++++++ +help: or explicitly set the default + | +LL | pub extern "Rust" fn rust_abi_fn_two(arg_one: u32, arg_two: usize) {} + | +++++++++++++ -error: attribute #[no_mangle] set on a Rust ABI function - --> $DIR/no_mangle_with_rust_abi.rs:15:1 +error: `#[no_mangle]` set on a function with the default (`Rust`) ABI + --> $DIR/no_mangle_with_rust_abi.rs:13:1 | LL | pub unsafe fn rust_abi_fn_three(arg_one: u32, arg_two: usize) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `pub unsafe extern "C" fn rust_abi_fn_three(arg_one: u32, arg_two: usize)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: set an ABI + | +LL | pub unsafe extern "C" fn rust_abi_fn_three(arg_one: u32, arg_two: usize) {} + | ++++++++++ +help: or explicitly set the default + | +LL | pub unsafe extern "Rust" fn rust_abi_fn_three(arg_one: u32, arg_two: usize) {} + | +++++++++++++ -error: attribute #[no_mangle] set on a Rust ABI function - --> $DIR/no_mangle_with_rust_abi.rs:20:1 +error: `#[no_mangle]` set on a function with the default (`Rust`) ABI + --> $DIR/no_mangle_with_rust_abi.rs:18:1 | LL | unsafe fn rust_abi_fn_four(arg_one: u32, arg_two: usize) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unsafe extern "C" fn rust_abi_fn_four(arg_one: u32, arg_two: usize)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: set an ABI + | +LL | unsafe extern "C" fn rust_abi_fn_four(arg_one: u32, arg_two: usize) {} + | ++++++++++ +help: or explicitly set the default + | +LL | unsafe extern "Rust" fn rust_abi_fn_four(arg_one: u32, arg_two: usize) {} + | +++++++++++++ -error: attribute #[no_mangle] set on a Rust ABI function - --> $DIR/no_mangle_with_rust_abi.rs:23:1 +error: `#[no_mangle]` set on a function with the default (`Rust`) ABI + --> $DIR/no_mangle_with_rust_abi.rs:21:1 | LL | / fn rust_abi_multiline_function_really_long_name_to_overflow_args_to_multiple_lines( LL | | arg_one: u32, @@ -33,13 +68,14 @@ LL | | arg_two: usize, LL | | ) -> u32 { | |________^ | -help: try +help: set an ABI | -LL + extern "C" fn rust_abi_multiline_function_really_long_name_to_overflow_args_to_multiple_lines( -LL + arg_one: u32, -LL + arg_two: usize, -LL ~ ) -> u32 { +LL | extern "C" fn rust_abi_multiline_function_really_long_name_to_overflow_args_to_multiple_lines( + | ++++++++++ +help: or explicitly set the default | +LL | extern "Rust" fn rust_abi_multiline_function_really_long_name_to_overflow_args_to_multiple_lines( + | +++++++++++++ error: aborting due to 5 previous errors diff --git a/tests/ui/nonminimal_bool.rs b/tests/ui/nonminimal_bool.rs index e9b4367ca65..3b5a374b4a7 100644 --- a/tests/ui/nonminimal_bool.rs +++ b/tests/ui/nonminimal_bool.rs @@ -63,3 +63,32 @@ fn issue9428() { println!("foo"); } } + +fn issue_10523() { + macro_rules! a { + ($v:expr) => { + $v.is_some() + }; + } + let x: Option = None; + if !a!(x) {} +} + +fn issue_10523_1() { + macro_rules! a { + ($v:expr) => { + !$v.is_some() + }; + } + let x: Option = None; + if a!(x) {} +} + +fn issue_10523_2() { + macro_rules! a { + () => { + !None::.is_some() + }; + } + if a!() {} +} diff --git a/tests/ui/option_env_unwrap.rs b/tests/ui/option_env_unwrap.rs index 0141fb7856d..9a56cf40d8a 100644 --- a/tests/ui/option_env_unwrap.rs +++ b/tests/ui/option_env_unwrap.rs @@ -1,24 +1,16 @@ -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs #![warn(clippy::option_env_unwrap)] #![allow(clippy::map_flatten)] -#[macro_use] -extern crate macro_rules; - -macro_rules! option_env_unwrap { - ($env: expr) => { - option_env!($env).unwrap() - }; - ($env: expr, $message: expr) => { - option_env!($env).expect($message) - }; -} +extern crate proc_macros; +use proc_macros::{external, inline_macros}; +#[inline_macros] fn main() { let _ = option_env!("PATH").unwrap(); let _ = option_env!("PATH").expect("environment variable PATH isn't set"); - let _ = option_env_unwrap!("PATH"); - let _ = option_env_unwrap!("PATH", "environment variable PATH isn't set"); - let _ = option_env_unwrap_external!("PATH"); - let _ = option_env_unwrap_external!("PATH", "environment variable PATH isn't set"); + let _ = inline!(option_env!($"PATH").unwrap()); + let _ = inline!(option_env!($"PATH").expect($"environment variable PATH isn't set")); + let _ = external!(option_env!($"PATH").unwrap()); + let _ = external!(option_env!($"PATH").expect($"environment variable PATH isn't set")); } diff --git a/tests/ui/option_env_unwrap.stderr b/tests/ui/option_env_unwrap.stderr index bc188a07e9e..7bba62686ee 100644 --- a/tests/ui/option_env_unwrap.stderr +++ b/tests/ui/option_env_unwrap.stderr @@ -1,5 +1,5 @@ error: this will panic at run-time if the environment variable doesn't exist at compile-time - --> $DIR/option_env_unwrap.rs:18:13 + --> $DIR/option_env_unwrap.rs:10:13 | LL | let _ = option_env!("PATH").unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | let _ = option_env!("PATH").unwrap(); = note: `-D clippy::option-env-unwrap` implied by `-D warnings` error: this will panic at run-time if the environment variable doesn't exist at compile-time - --> $DIR/option_env_unwrap.rs:19:13 + --> $DIR/option_env_unwrap.rs:11:13 | LL | let _ = option_env!("PATH").expect("environment variable PATH isn't set"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -16,46 +16,40 @@ LL | let _ = option_env!("PATH").expect("environment variable PATH isn't set = help: consider using the `env!` macro instead error: this will panic at run-time if the environment variable doesn't exist at compile-time - --> $DIR/option_env_unwrap.rs:10:9 + --> $DIR/option_env_unwrap.rs:12:21 | -LL | option_env!($env).unwrap() - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -... -LL | let _ = option_env_unwrap!("PATH"); - | -------------------------- in this macro invocation +LL | let _ = inline!(option_env!($"PATH").unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: consider using the `env!` macro instead - = note: this error originates in the macro `option_env_unwrap` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info) error: this will panic at run-time if the environment variable doesn't exist at compile-time - --> $DIR/option_env_unwrap.rs:13:9 + --> $DIR/option_env_unwrap.rs:13:21 | -LL | option_env!($env).expect($message) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -... -LL | let _ = option_env_unwrap!("PATH", "environment variable PATH isn't set"); - | ----------------------------------------------------------------- in this macro invocation +LL | let _ = inline!(option_env!($"PATH").expect($"environment variable PATH isn't set")); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: consider using the `env!` macro instead - = note: this error originates in the macro `option_env_unwrap` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info) error: this will panic at run-time if the environment variable doesn't exist at compile-time - --> $DIR/option_env_unwrap.rs:22:13 + --> $DIR/option_env_unwrap.rs:14:13 | -LL | let _ = option_env_unwrap_external!("PATH"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | let _ = external!(option_env!($"PATH").unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: consider using the `env!` macro instead - = note: this error originates in the macro `option_env_unwrap_external` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `external` (in Nightly builds, run with -Z macro-backtrace for more info) error: this will panic at run-time if the environment variable doesn't exist at compile-time - --> $DIR/option_env_unwrap.rs:23:13 + --> $DIR/option_env_unwrap.rs:15:13 | -LL | let _ = option_env_unwrap_external!("PATH", "environment variable PATH isn't set"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | let _ = external!(option_env!($"PATH").expect($"environment variable PATH isn't set")); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: consider using the `env!` macro instead - = note: this error originates in the macro `option_env_unwrap_external` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `external` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 6 previous errors diff --git a/tests/ui/ptr_as_ptr.fixed b/tests/ui/ptr_as_ptr.fixed index df36a9b842b..ee7b998a0b2 100644 --- a/tests/ui/ptr_as_ptr.fixed +++ b/tests/ui/ptr_as_ptr.fixed @@ -1,16 +1,12 @@ // run-rustfix -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs #![warn(clippy::ptr_as_ptr)] -extern crate macro_rules; - -macro_rules! cast_it { - ($ptr: ident) => { - $ptr.cast::() - }; -} +extern crate proc_macros; +use proc_macros::{external, inline_macros}; +#[inline_macros] fn main() { let ptr: *const u32 = &42_u32; let mut_ptr: *mut u32 = &mut 42_u32; @@ -38,10 +34,10 @@ fn main() { let _: *mut i32 = mut_ptr.cast(); // Make sure the lint is triggered inside a macro - let _ = cast_it!(ptr); + let _ = inline!($ptr.cast::()); // Do not lint inside macros from external crates - let _ = macro_rules::ptr_as_ptr_cast!(ptr); + let _ = external!($ptr as *const i32); } #[clippy::msrv = "1.37"] diff --git a/tests/ui/ptr_as_ptr.rs b/tests/ui/ptr_as_ptr.rs index 302c66462d9..c88329ce4ec 100644 --- a/tests/ui/ptr_as_ptr.rs +++ b/tests/ui/ptr_as_ptr.rs @@ -1,16 +1,12 @@ // run-rustfix -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs #![warn(clippy::ptr_as_ptr)] -extern crate macro_rules; - -macro_rules! cast_it { - ($ptr: ident) => { - $ptr as *const i32 - }; -} +extern crate proc_macros; +use proc_macros::{external, inline_macros}; +#[inline_macros] fn main() { let ptr: *const u32 = &42_u32; let mut_ptr: *mut u32 = &mut 42_u32; @@ -38,10 +34,10 @@ fn main() { let _: *mut i32 = mut_ptr as _; // Make sure the lint is triggered inside a macro - let _ = cast_it!(ptr); + let _ = inline!($ptr as *const i32); // Do not lint inside macros from external crates - let _ = macro_rules::ptr_as_ptr_cast!(ptr); + let _ = external!($ptr as *const i32); } #[clippy::msrv = "1.37"] diff --git a/tests/ui/ptr_as_ptr.stderr b/tests/ui/ptr_as_ptr.stderr index a68e1cab6d3..78d733994ac 100644 --- a/tests/ui/ptr_as_ptr.stderr +++ b/tests/ui/ptr_as_ptr.stderr @@ -1,5 +1,5 @@ error: `as` casting between raw pointers without changing its mutability - --> $DIR/ptr_as_ptr.rs:18:13 + --> $DIR/ptr_as_ptr.rs:14:13 | LL | let _ = ptr as *const i32; | ^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `ptr.cast::()` @@ -7,48 +7,45 @@ LL | let _ = ptr as *const i32; = note: `-D clippy::ptr-as-ptr` implied by `-D warnings` error: `as` casting between raw pointers without changing its mutability - --> $DIR/ptr_as_ptr.rs:19:13 + --> $DIR/ptr_as_ptr.rs:15:13 | LL | let _ = mut_ptr as *mut i32; | ^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `mut_ptr.cast::()` error: `as` casting between raw pointers without changing its mutability - --> $DIR/ptr_as_ptr.rs:24:17 + --> $DIR/ptr_as_ptr.rs:20:17 | LL | let _ = *ptr_ptr as *const i32; | ^^^^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `(*ptr_ptr).cast::()` error: `as` casting between raw pointers without changing its mutability - --> $DIR/ptr_as_ptr.rs:37:25 + --> $DIR/ptr_as_ptr.rs:33:25 | LL | let _: *const i32 = ptr as *const _; | ^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `ptr.cast()` error: `as` casting between raw pointers without changing its mutability - --> $DIR/ptr_as_ptr.rs:38:23 + --> $DIR/ptr_as_ptr.rs:34:23 | LL | let _: *mut i32 = mut_ptr as _; | ^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `mut_ptr.cast()` error: `as` casting between raw pointers without changing its mutability - --> $DIR/ptr_as_ptr.rs:10:9 + --> $DIR/ptr_as_ptr.rs:37:21 | -LL | $ptr as *const i32 - | ^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `$ptr.cast::()` -... -LL | let _ = cast_it!(ptr); - | ------------- in this macro invocation +LL | let _ = inline!($ptr as *const i32); + | ^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `$ptr.cast::()` | - = note: this error originates in the macro `cast_it` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info) error: `as` casting between raw pointers without changing its mutability - --> $DIR/ptr_as_ptr.rs:62:13 + --> $DIR/ptr_as_ptr.rs:58:13 | LL | let _ = ptr as *const i32; | ^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `ptr.cast::()` error: `as` casting between raw pointers without changing its mutability - --> $DIR/ptr_as_ptr.rs:63:13 + --> $DIR/ptr_as_ptr.rs:59:13 | LL | let _ = mut_ptr as *mut i32; | ^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `mut_ptr.cast::()` diff --git a/tests/ui/redundant_async_block.fixed b/tests/ui/redundant_async_block.fixed index 5f9931df45e..d26b7a332cb 100644 --- a/tests/ui/redundant_async_block.fixed +++ b/tests/ui/redundant_async_block.fixed @@ -3,6 +3,8 @@ #![allow(unused)] #![warn(clippy::redundant_async_block)] +use std::future::Future; + async fn func1(n: usize) -> usize { n + 1 } @@ -62,3 +64,48 @@ fn main() { let fut = async_await_parameter_in_macro!(func2()); let fut = async_await_in_macro!(std::convert::identity); } + +#[allow(clippy::let_and_return)] +fn capture_local() -> impl Future { + // Lint + let fut = async { 17 }; + fut +} + +fn capture_local_closure(s: &str) -> impl Future { + let f = move || std::future::ready(s); + // Do not lint: `f` would not live long enough + async move { f().await } +} + +#[allow(clippy::let_and_return)] +fn capture_arg(s: &str) -> impl Future { + // Lint + let fut = async move { s }; + fut +} + +#[derive(Debug, Clone)] +struct F {} + +impl F { + async fn run(&self) {} +} + +pub async fn run() { + let f = F {}; + let c = f.clone(); + // Do not lint: `c` would not live long enough + spawn(async move { c.run().await }); + let _f = f; +} + +fn spawn(_: F) {} + +async fn work(_: &str) {} + +fn capture() { + let val = "Hello World".to_owned(); + // Do not lint: `val` would not live long enough + spawn(async { work(&{ val }).await }); +} diff --git a/tests/ui/redundant_async_block.rs b/tests/ui/redundant_async_block.rs index de3c9970c65..04726e62805 100644 --- a/tests/ui/redundant_async_block.rs +++ b/tests/ui/redundant_async_block.rs @@ -3,6 +3,8 @@ #![allow(unused)] #![warn(clippy::redundant_async_block)] +use std::future::Future; + async fn func1(n: usize) -> usize { n + 1 } @@ -62,3 +64,48 @@ fn main() { let fut = async_await_parameter_in_macro!(func2()); let fut = async_await_in_macro!(std::convert::identity); } + +#[allow(clippy::let_and_return)] +fn capture_local() -> impl Future { + // Lint + let fut = async { 17 }; + async move { fut.await } +} + +fn capture_local_closure(s: &str) -> impl Future { + let f = move || std::future::ready(s); + // Do not lint: `f` would not live long enough + async move { f().await } +} + +#[allow(clippy::let_and_return)] +fn capture_arg(s: &str) -> impl Future { + // Lint + let fut = async move { s }; + async move { fut.await } +} + +#[derive(Debug, Clone)] +struct F {} + +impl F { + async fn run(&self) {} +} + +pub async fn run() { + let f = F {}; + let c = f.clone(); + // Do not lint: `c` would not live long enough + spawn(async move { c.run().await }); + let _f = f; +} + +fn spawn(_: F) {} + +async fn work(_: &str) {} + +fn capture() { + let val = "Hello World".to_owned(); + // Do not lint: `val` would not live long enough + spawn(async { work(&{ val }).await }); +} diff --git a/tests/ui/redundant_async_block.stderr b/tests/ui/redundant_async_block.stderr index b16d96dce84..1a1c1603e08 100644 --- a/tests/ui/redundant_async_block.stderr +++ b/tests/ui/redundant_async_block.stderr @@ -1,5 +1,5 @@ error: this async expression only awaits a single future - --> $DIR/redundant_async_block.rs:13:13 + --> $DIR/redundant_async_block.rs:15:13 | LL | let x = async { f.await }; | ^^^^^^^^^^^^^^^^^ help: you can reduce it to: `f` @@ -7,22 +7,34 @@ LL | let x = async { f.await }; = note: `-D clippy::redundant-async-block` implied by `-D warnings` error: this async expression only awaits a single future - --> $DIR/redundant_async_block.rs:46:16 + --> $DIR/redundant_async_block.rs:48:16 | LL | let fut2 = async { fut1.await }; | ^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `fut1` error: this async expression only awaits a single future - --> $DIR/redundant_async_block.rs:49:16 + --> $DIR/redundant_async_block.rs:51:16 | LL | let fut2 = async move { fut1.await }; | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `fut1` error: this async expression only awaits a single future - --> $DIR/redundant_async_block.rs:51:15 + --> $DIR/redundant_async_block.rs:53:15 | LL | let fut = async { async { 42 }.await }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `async { 42 }` -error: aborting due to 4 previous errors +error: this async expression only awaits a single future + --> $DIR/redundant_async_block.rs:72:5 + | +LL | async move { fut.await } + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `fut` + +error: this async expression only awaits a single future + --> $DIR/redundant_async_block.rs:85:5 + | +LL | async move { fut.await } + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `fut` + +error: aborting due to 6 previous errors diff --git a/tests/ui/redundant_pattern_matching_result.fixed b/tests/ui/redundant_pattern_matching_result.fixed index b88c5d0bec8..42348df4480 100644 --- a/tests/ui/redundant_pattern_matching_result.fixed +++ b/tests/ui/redundant_pattern_matching_result.fixed @@ -69,8 +69,8 @@ fn issue5504() { } fn try_result_opt() -> Result { - while (r#try!(result_opt())).is_some() {} - if (r#try!(result_opt())).is_some() {} + while r#try!(result_opt()).is_some() {} + if r#try!(result_opt()).is_some() {} Ok(42) } diff --git a/tests/ui/redundant_pattern_matching_result.stderr b/tests/ui/redundant_pattern_matching_result.stderr index e6afe9eb78e..d6a46babb77 100644 --- a/tests/ui/redundant_pattern_matching_result.stderr +++ b/tests/ui/redundant_pattern_matching_result.stderr @@ -88,13 +88,13 @@ error: redundant pattern matching, consider using `is_some()` --> $DIR/redundant_pattern_matching_result.rs:84:19 | LL | while let Some(_) = r#try!(result_opt()) {} - | ----------^^^^^^^----------------------- help: try this: `while (r#try!(result_opt())).is_some()` + | ----------^^^^^^^----------------------- help: try this: `while r#try!(result_opt()).is_some()` error: redundant pattern matching, consider using `is_some()` --> $DIR/redundant_pattern_matching_result.rs:85:16 | LL | if let Some(_) = r#try!(result_opt()) {} - | -------^^^^^^^----------------------- help: try this: `if (r#try!(result_opt())).is_some()` + | -------^^^^^^^----------------------- help: try this: `if r#try!(result_opt()).is_some()` error: redundant pattern matching, consider using `is_some()` --> $DIR/redundant_pattern_matching_result.rs:91:12 diff --git a/tests/ui/single_match_else.rs b/tests/ui/single_match_else.rs index 5d03f77e932..3c86f41f3a6 100644 --- a/tests/ui/single_match_else.rs +++ b/tests/ui/single_match_else.rs @@ -1,9 +1,9 @@ -// aux-build: proc_macro_with_span.rs +// aux-build: proc_macros.rs #![warn(clippy::single_match_else)] #![allow(clippy::needless_return, clippy::no_effect, clippy::uninlined_format_args)] -extern crate proc_macro_with_span; -use proc_macro_with_span::with_span; +extern crate proc_macros; +use proc_macros::with_span; enum ExprNode { ExprAddrOf, diff --git a/tests/ui/string_add.rs b/tests/ui/string_add.rs index 16673c01e63..20edbe31fa9 100644 --- a/tests/ui/string_add.rs +++ b/tests/ui/string_add.rs @@ -1,7 +1,7 @@ -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs -#[macro_use] -extern crate macro_rules; +extern crate proc_macros; +use proc_macros::external; #[warn(clippy::string_add)] #[allow(clippy::string_add_assign, unused)] @@ -22,5 +22,8 @@ fn main() { x = x + 1; assert_eq!(2, x); - string_add!(); + external!({ + let y = "".to_owned(); + let z = y + "..."; + }); } diff --git a/tests/ui/swap.fixed b/tests/ui/swap.fixed index 04008c0d9b3..9703674d1a4 100644 --- a/tests/ui/swap.fixed +++ b/tests/ui/swap.fixed @@ -1,4 +1,5 @@ // run-rustfix +// aux-build: macro_rules.rs #![warn(clippy::all)] #![allow( @@ -8,7 +9,8 @@ redundant_semicolons, dead_code, unused_assignments, - unused_variables + unused_variables, + clippy::let_and_return )] struct Foo(u32); @@ -186,3 +188,14 @@ const fn issue_9864(mut u: u32) -> u32 { v = temp; u + v } + +#[macro_use] +extern crate macro_rules; + +const fn issue_10421(x: u32) -> u32 { + issue_10421!(); + let a = x; + let a = a; + let a = a; + a +} diff --git a/tests/ui/swap.rs b/tests/ui/swap.rs index ef8a81c8341..a0228065e46 100644 --- a/tests/ui/swap.rs +++ b/tests/ui/swap.rs @@ -1,4 +1,5 @@ // run-rustfix +// aux-build: macro_rules.rs #![warn(clippy::all)] #![allow( @@ -8,7 +9,8 @@ redundant_semicolons, dead_code, unused_assignments, - unused_variables + unused_variables, + clippy::let_and_return )] struct Foo(u32); @@ -215,3 +217,14 @@ const fn issue_9864(mut u: u32) -> u32 { v = temp; u + v } + +#[macro_use] +extern crate macro_rules; + +const fn issue_10421(x: u32) -> u32 { + issue_10421!(); + let a = x; + let a = a; + let a = a; + a +} diff --git a/tests/ui/swap.stderr b/tests/ui/swap.stderr index 825c9261e19..0c246268499 100644 --- a/tests/ui/swap.stderr +++ b/tests/ui/swap.stderr @@ -1,5 +1,5 @@ error: this looks like you are swapping `bar.a` and `bar.b` manually - --> $DIR/swap.rs:25:5 + --> $DIR/swap.rs:27:5 | LL | / let temp = bar.a; LL | | bar.a = bar.b; @@ -10,7 +10,7 @@ LL | | bar.b = temp; = note: `-D clippy::manual-swap` implied by `-D warnings` error: this looks like you are swapping elements of `foo` manually - --> $DIR/swap.rs:37:5 + --> $DIR/swap.rs:39:5 | LL | / let temp = foo[0]; LL | | foo[0] = foo[1]; @@ -18,7 +18,7 @@ LL | | foo[1] = temp; | |__________________^ help: try: `foo.swap(0, 1);` error: this looks like you are swapping elements of `foo` manually - --> $DIR/swap.rs:46:5 + --> $DIR/swap.rs:48:5 | LL | / let temp = foo[0]; LL | | foo[0] = foo[1]; @@ -26,7 +26,7 @@ LL | | foo[1] = temp; | |__________________^ help: try: `foo.swap(0, 1);` error: this looks like you are swapping elements of `foo` manually - --> $DIR/swap.rs:65:5 + --> $DIR/swap.rs:67:5 | LL | / let temp = foo[0]; LL | | foo[0] = foo[1]; @@ -34,7 +34,7 @@ LL | | foo[1] = temp; | |__________________^ help: try: `foo.swap(0, 1);` error: this looks like you are swapping `a` and `b` manually - --> $DIR/swap.rs:76:5 + --> $DIR/swap.rs:78:5 | LL | / a ^= b; LL | | b ^= a; @@ -42,7 +42,7 @@ LL | | a ^= b; | |___________^ help: try: `std::mem::swap(&mut a, &mut b);` error: this looks like you are swapping `bar.a` and `bar.b` manually - --> $DIR/swap.rs:84:5 + --> $DIR/swap.rs:86:5 | LL | / bar.a ^= bar.b; LL | | bar.b ^= bar.a; @@ -50,7 +50,7 @@ LL | | bar.a ^= bar.b; | |___________________^ help: try: `std::mem::swap(&mut bar.a, &mut bar.b);` error: this looks like you are swapping elements of `foo` manually - --> $DIR/swap.rs:92:5 + --> $DIR/swap.rs:94:5 | LL | / foo[0] ^= foo[1]; LL | | foo[1] ^= foo[0]; @@ -58,7 +58,7 @@ LL | | foo[0] ^= foo[1]; | |_____________________^ help: try: `foo.swap(0, 1);` error: this looks like you are swapping `foo[0][1]` and `bar[1][0]` manually - --> $DIR/swap.rs:121:5 + --> $DIR/swap.rs:123:5 | LL | / let temp = foo[0][1]; LL | | foo[0][1] = bar[1][0]; @@ -68,7 +68,7 @@ LL | | bar[1][0] = temp; = note: or maybe you should use `std::mem::replace`? error: this looks like you are swapping `a` and `b` manually - --> $DIR/swap.rs:135:7 + --> $DIR/swap.rs:137:7 | LL | ; let t = a; | _______^ @@ -79,7 +79,7 @@ LL | | b = t; = note: or maybe you should use `std::mem::replace`? error: this looks like you are swapping `c.0` and `a` manually - --> $DIR/swap.rs:144:7 + --> $DIR/swap.rs:146:7 | LL | ; let t = c.0; | _______^ @@ -90,7 +90,7 @@ LL | | a = t; = note: or maybe you should use `std::mem::replace`? error: this looks like you are swapping `b` and `a` manually - --> $DIR/swap.rs:170:5 + --> $DIR/swap.rs:172:5 | LL | / let t = b; LL | | b = a; @@ -100,7 +100,7 @@ LL | | a = t; = note: or maybe you should use `std::mem::replace`? error: this looks like you are trying to swap `a` and `b` - --> $DIR/swap.rs:132:5 + --> $DIR/swap.rs:134:5 | LL | / a = b; LL | | b = a; @@ -110,7 +110,7 @@ LL | | b = a; = note: `-D clippy::almost-swapped` implied by `-D warnings` error: this looks like you are trying to swap `c.0` and `a` - --> $DIR/swap.rs:141:5 + --> $DIR/swap.rs:143:5 | LL | / c.0 = a; LL | | a = c.0; @@ -119,7 +119,7 @@ LL | | a = c.0; = note: or maybe you should use `std::mem::replace`? error: this looks like you are trying to swap `a` and `b` - --> $DIR/swap.rs:148:5 + --> $DIR/swap.rs:150:5 | LL | / let a = b; LL | | let b = a; @@ -128,7 +128,7 @@ LL | | let b = a; = note: or maybe you should use `std::mem::replace`? error: this looks like you are trying to swap `d` and `c` - --> $DIR/swap.rs:153:5 + --> $DIR/swap.rs:155:5 | LL | / d = c; LL | | c = d; @@ -137,7 +137,7 @@ LL | | c = d; = note: or maybe you should use `std::mem::replace`? error: this looks like you are trying to swap `a` and `b` - --> $DIR/swap.rs:157:5 + --> $DIR/swap.rs:159:5 | LL | / let a = b; LL | | b = a; @@ -146,7 +146,7 @@ LL | | b = a; = note: or maybe you should use `std::mem::replace`? error: this looks like you are swapping `s.0.x` and `s.0.y` manually - --> $DIR/swap.rs:205:5 + --> $DIR/swap.rs:207:5 | LL | / let t = s.0.x; LL | | s.0.x = s.0.y; diff --git a/tests/ui/toplevel_ref_arg.fixed b/tests/ui/toplevel_ref_arg.fixed index 09fb66ca37e..174c858a47d 100644 --- a/tests/ui/toplevel_ref_arg.fixed +++ b/tests/ui/toplevel_ref_arg.fixed @@ -1,17 +1,12 @@ // run-rustfix -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs #![warn(clippy::toplevel_ref_arg)] -#![allow(clippy::uninlined_format_args)] +#![allow(clippy::uninlined_format_args, unused)] -#[macro_use] -extern crate macro_rules; - -macro_rules! gen_binding { - () => { - let _y = &42; - }; -} +extern crate proc_macros; +use proc_macros::{external, inline_macros}; +#[inline_macros] fn main() { // Closures should not warn let y = |ref x| println!("{:?}", x); @@ -38,13 +33,8 @@ fn main() { for ref _x in 0..10 {} // lint in macro - #[allow(unused)] - { - gen_binding!(); - } + inline!(let _y = &42;); // do not lint in external macro - { - ref_arg_binding!(); - } + external!(let ref _y = 42;); } diff --git a/tests/ui/toplevel_ref_arg.rs b/tests/ui/toplevel_ref_arg.rs index 9d1f2f81098..4b81a06112f 100644 --- a/tests/ui/toplevel_ref_arg.rs +++ b/tests/ui/toplevel_ref_arg.rs @@ -1,17 +1,12 @@ // run-rustfix -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs #![warn(clippy::toplevel_ref_arg)] -#![allow(clippy::uninlined_format_args)] +#![allow(clippy::uninlined_format_args, unused)] -#[macro_use] -extern crate macro_rules; - -macro_rules! gen_binding { - () => { - let ref _y = 42; - }; -} +extern crate proc_macros; +use proc_macros::{external, inline_macros}; +#[inline_macros] fn main() { // Closures should not warn let y = |ref x| println!("{:?}", x); @@ -38,13 +33,8 @@ fn main() { for ref _x in 0..10 {} // lint in macro - #[allow(unused)] - { - gen_binding!(); - } + inline!(let ref _y = 42;); // do not lint in external macro - { - ref_arg_binding!(); - } + external!(let ref _y = 42;); } diff --git a/tests/ui/toplevel_ref_arg.stderr b/tests/ui/toplevel_ref_arg.stderr index 9c853020ab0..407c2d9fcd3 100644 --- a/tests/ui/toplevel_ref_arg.stderr +++ b/tests/ui/toplevel_ref_arg.stderr @@ -1,5 +1,5 @@ error: `ref` on an entire `let` pattern is discouraged, take a reference with `&` instead - --> $DIR/toplevel_ref_arg.rs:20:9 + --> $DIR/toplevel_ref_arg.rs:15:9 | LL | let ref _x = 1; | ----^^^^^^----- help: try: `let _x = &1;` @@ -7,39 +7,36 @@ LL | let ref _x = 1; = note: `-D clippy::toplevel-ref-arg` implied by `-D warnings` error: `ref` on an entire `let` pattern is discouraged, take a reference with `&` instead - --> $DIR/toplevel_ref_arg.rs:22:9 + --> $DIR/toplevel_ref_arg.rs:17:9 | LL | let ref _y: (&_, u8) = (&1, 2); | ----^^^^^^--------------------- help: try: `let _y: &(&_, u8) = &(&1, 2);` error: `ref` on an entire `let` pattern is discouraged, take a reference with `&` instead - --> $DIR/toplevel_ref_arg.rs:24:9 + --> $DIR/toplevel_ref_arg.rs:19:9 | LL | let ref _z = 1 + 2; | ----^^^^^^--------- help: try: `let _z = &(1 + 2);` error: `ref` on an entire `let` pattern is discouraged, take a reference with `&` instead - --> $DIR/toplevel_ref_arg.rs:26:9 + --> $DIR/toplevel_ref_arg.rs:21:9 | LL | let ref mut _z = 1 + 2; | ----^^^^^^^^^^--------- help: try: `let _z = &mut (1 + 2);` error: `ref` on an entire `let` pattern is discouraged, take a reference with `&` instead - --> $DIR/toplevel_ref_arg.rs:31:9 + --> $DIR/toplevel_ref_arg.rs:26:9 | LL | let ref _x = vec![1, 2, 3]; | ----^^^^^^----------------- help: try: `let _x = &vec![1, 2, 3];` error: `ref` on an entire `let` pattern is discouraged, take a reference with `&` instead - --> $DIR/toplevel_ref_arg.rs:11:13 + --> $DIR/toplevel_ref_arg.rs:36:17 | -LL | let ref _y = 42; - | ----^^^^^^------ help: try: `let _y = &42;` -... -LL | gen_binding!(); - | -------------- in this macro invocation +LL | inline!(let ref _y = 42;); + | ----^^^^^^------ help: try: `let _y = &42;` | - = note: this error originates in the macro `gen_binding` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 6 previous errors diff --git a/tests/ui/toplevel_ref_arg_non_rustfix.rs b/tests/ui/toplevel_ref_arg_non_rustfix.rs index 1a493fbce0e..2047593e7e4 100644 --- a/tests/ui/toplevel_ref_arg_non_rustfix.rs +++ b/tests/ui/toplevel_ref_arg_non_rustfix.rs @@ -1,33 +1,27 @@ -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs #![warn(clippy::toplevel_ref_arg)] #![allow(unused)] -#[macro_use] -extern crate macro_rules; +extern crate proc_macros; +use proc_macros::{external, inline_macros}; fn the_answer(ref mut x: u8) { *x = 42; } -macro_rules! gen_function { - () => { - fn fun_example(ref _x: usize) {} - }; -} - +#[inline_macros] fn main() { let mut x = 0; the_answer(x); // lint in macro - #[allow(unused)] - { - gen_function!(); + inline! { + fn fun_example(ref _x: usize) {} } // do not lint in external macro - { - ref_arg_function!(); + external! { + fn fun_example2(ref _x: usize) {} } } diff --git a/tests/ui/toplevel_ref_arg_non_rustfix.stderr b/tests/ui/toplevel_ref_arg_non_rustfix.stderr index e97011c7fd5..7307bd599d9 100644 --- a/tests/ui/toplevel_ref_arg_non_rustfix.stderr +++ b/tests/ui/toplevel_ref_arg_non_rustfix.stderr @@ -7,15 +7,12 @@ LL | fn the_answer(ref mut x: u8) { = note: `-D clippy::toplevel-ref-arg` implied by `-D warnings` error: `ref` directly on a function argument is ignored. Consider using a reference type instead - --> $DIR/toplevel_ref_arg_non_rustfix.rs:15:24 + --> $DIR/toplevel_ref_arg_non_rustfix.rs:20:24 | LL | fn fun_example(ref _x: usize) {} | ^^^^^^ -... -LL | gen_function!(); - | --------------- in this macro invocation | - = note: this error originates in the macro `gen_function` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 2 previous errors diff --git a/tests/ui/try_err.fixed b/tests/ui/try_err.fixed index 264194419c7..dc497b1690f 100644 --- a/tests/ui/try_err.fixed +++ b/tests/ui/try_err.fixed @@ -1,11 +1,11 @@ // run-rustfix -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs #![deny(clippy::try_err)] #![allow(clippy::unnecessary_wraps, clippy::needless_question_mark)] -#[macro_use] -extern crate macro_rules; +extern crate proc_macros; +use proc_macros::{external, inline_macros}; use std::io; use std::task::Poll; @@ -79,36 +79,22 @@ fn nested_error() -> Result { Ok(1) } -// Bad suggestion when in macro (see #6242) -macro_rules! try_validation { - ($e: expr) => {{ - match $e { +#[inline_macros] +fn calling_macro() -> Result { + // macro + inline!( + match $(Ok::<_, i32>(5)) { Ok(_) => 0, Err(_) => return Err(1), } - }}; -} - -macro_rules! ret_one { - () => { - 1 - }; -} - -macro_rules! try_validation_in_macro { - ($e: expr) => {{ - match $e { - Ok(_) => 0, - Err(_) => return Err(ret_one!()), - } - }}; -} - -fn calling_macro() -> Result { - // macro - try_validation!(Ok::<_, i32>(5)); + ); // `Err` arg is another macro - try_validation_in_macro!(Ok::<_, i32>(5)); + inline!( + match $(Ok::<_, i32>(5)) { + Ok(_) => 0, + Err(_) => return Err(inline!(1)), + } + ); Ok(5) } @@ -121,24 +107,19 @@ fn main() { calling_macro().unwrap(); // We don't want to lint in external macros - try_err!(); -} - -macro_rules! bar { - () => { - String::from("aasdfasdfasdfa") - }; -} - -macro_rules! foo { - () => { - bar!() - }; + external! { + pub fn try_err_fn() -> Result { + let err: i32 = 1; + // To avoid warnings during rustfix + if true { Err(err)? } else { Ok(2) } + } + } } +#[inline_macros] pub fn macro_inside(fail: bool) -> Result { if fail { - return Err(foo!()); + return Err(inline!(inline!(String::from("aasdfasdfasdfa")))); } Ok(0) } diff --git a/tests/ui/try_err.rs b/tests/ui/try_err.rs index bc6979bf457..86aeb75cd96 100644 --- a/tests/ui/try_err.rs +++ b/tests/ui/try_err.rs @@ -1,11 +1,11 @@ // run-rustfix -// aux-build:macro_rules.rs +// aux-build:proc_macros.rs #![deny(clippy::try_err)] #![allow(clippy::unnecessary_wraps, clippy::needless_question_mark)] -#[macro_use] -extern crate macro_rules; +extern crate proc_macros; +use proc_macros::{external, inline_macros}; use std::io; use std::task::Poll; @@ -79,36 +79,22 @@ fn nested_error() -> Result { Ok(1) } -// Bad suggestion when in macro (see #6242) -macro_rules! try_validation { - ($e: expr) => {{ - match $e { +#[inline_macros] +fn calling_macro() -> Result { + // macro + inline!( + match $(Ok::<_, i32>(5)) { Ok(_) => 0, Err(_) => Err(1)?, } - }}; -} - -macro_rules! ret_one { - () => { - 1 - }; -} - -macro_rules! try_validation_in_macro { - ($e: expr) => {{ - match $e { - Ok(_) => 0, - Err(_) => Err(ret_one!())?, - } - }}; -} - -fn calling_macro() -> Result { - // macro - try_validation!(Ok::<_, i32>(5)); + ); // `Err` arg is another macro - try_validation_in_macro!(Ok::<_, i32>(5)); + inline!( + match $(Ok::<_, i32>(5)) { + Ok(_) => 0, + Err(_) => Err(inline!(1))?, + } + ); Ok(5) } @@ -121,24 +107,19 @@ fn main() { calling_macro().unwrap(); // We don't want to lint in external macros - try_err!(); -} - -macro_rules! bar { - () => { - String::from("aasdfasdfasdfa") - }; -} - -macro_rules! foo { - () => { - bar!() - }; + external! { + pub fn try_err_fn() -> Result { + let err: i32 = 1; + // To avoid warnings during rustfix + if true { Err(err)? } else { Ok(2) } + } + } } +#[inline_macros] pub fn macro_inside(fail: bool) -> Result { if fail { - Err(foo!())?; + Err(inline!(inline!(String::from("aasdfasdfasdfa"))))?; } Ok(0) } diff --git a/tests/ui/try_err.stderr b/tests/ui/try_err.stderr index 0cb1328fbfc..4ad0e2e56a4 100644 --- a/tests/ui/try_err.stderr +++ b/tests/ui/try_err.stderr @@ -29,53 +29,47 @@ LL | Err(err)?; | ^^^^^^^^^ help: try this: `return Err(err.into())` error: returning an `Err(_)` with the `?` operator - --> $DIR/try_err.rs:87:23 + --> $DIR/try_err.rs:88:23 | LL | Err(_) => Err(1)?, | ^^^^^^^ help: try this: `return Err(1)` -... -LL | try_validation!(Ok::<_, i32>(5)); - | -------------------------------- in this macro invocation | - = note: this error originates in the macro `try_validation` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `__inline_mac_fn_calling_macro` (in Nightly builds, run with -Z macro-backtrace for more info) error: returning an `Err(_)` with the `?` operator - --> $DIR/try_err.rs:102:23 + --> $DIR/try_err.rs:95:23 | -LL | Err(_) => Err(ret_one!())?, - | ^^^^^^^^^^^^^^^^ help: try this: `return Err(ret_one!())` -... -LL | try_validation_in_macro!(Ok::<_, i32>(5)); - | ----------------------------------------- in this macro invocation +LL | Err(_) => Err(inline!(1))?, + | ^^^^^^^^^^^^^^^^ help: try this: `return Err(inline!(1))` | - = note: this error originates in the macro `try_validation_in_macro` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `__inline_mac_fn_calling_macro` (in Nightly builds, run with -Z macro-backtrace for more info) error: returning an `Err(_)` with the `?` operator - --> $DIR/try_err.rs:141:9 + --> $DIR/try_err.rs:122:9 | -LL | Err(foo!())?; - | ^^^^^^^^^^^^ help: try this: `return Err(foo!())` +LL | Err(inline!(inline!(String::from("aasdfasdfasdfa"))))?; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `return Err(inline!(inline!(String::from("aasdfasdfasdfa"))))` error: returning an `Err(_)` with the `?` operator - --> $DIR/try_err.rs:148:9 + --> $DIR/try_err.rs:129:9 | LL | Err(io::ErrorKind::WriteZero)? | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `return Poll::Ready(Err(io::ErrorKind::WriteZero.into()))` error: returning an `Err(_)` with the `?` operator - --> $DIR/try_err.rs:150:9 + --> $DIR/try_err.rs:131:9 | LL | Err(io::Error::new(io::ErrorKind::InvalidInput, "error"))? | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `return Poll::Ready(Err(io::Error::new(io::ErrorKind::InvalidInput, "error")))` error: returning an `Err(_)` with the `?` operator - --> $DIR/try_err.rs:158:9 + --> $DIR/try_err.rs:139:9 | LL | Err(io::ErrorKind::NotFound)? | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `return Poll::Ready(Some(Err(io::ErrorKind::NotFound.into())))` error: returning an `Err(_)` with the `?` operator - --> $DIR/try_err.rs:167:16 + --> $DIR/try_err.rs:148:16 | LL | return Err(42)?; | ^^^^^^^^ help: try this: `Err(42)` diff --git a/tests/ui/uninit.rs b/tests/ui/uninit.rs index 21131731708..412b36b4ee8 100644 --- a/tests/ui/uninit.rs +++ b/tests/ui/uninit.rs @@ -3,13 +3,15 @@ use std::mem::{self, MaybeUninit}; +union MyOwnMaybeUninit { + value: u8, + uninit: (), +} + fn main() { let _: usize = unsafe { MaybeUninit::uninit().assume_init() }; - // edge case: For now we lint on empty arrays - let _: [u8; 0] = unsafe { MaybeUninit::uninit().assume_init() }; - - // edge case: For now we accept unit tuples + // This is OK, because ZSTs do not contain data. let _: () = unsafe { MaybeUninit::uninit().assume_init() }; // This is OK, because `MaybeUninit` allows uninitialized data. @@ -21,6 +23,19 @@ fn main() { // This is OK, because all constitutent types are uninit-compatible. let _: (MaybeUninit, [MaybeUninit; 2]) = unsafe { MaybeUninit::uninit().assume_init() }; + // This is OK, because our own MaybeUninit is just as fine as the one from core. + let _: MyOwnMaybeUninit = unsafe { MaybeUninit::uninit().assume_init() }; + + // This is OK, because empty arrays don't contain data. + let _: [u8; 0] = unsafe { MaybeUninit::uninit().assume_init() }; + // Was a false negative. let _: usize = unsafe { mem::MaybeUninit::uninit().assume_init() }; + + polymorphic::<()>(); + + fn polymorphic() { + // We are conservative around polymorphic types. + let _: T = unsafe { mem::MaybeUninit::uninit().assume_init() }; + } } diff --git a/tests/ui/uninit.stderr b/tests/ui/uninit.stderr index 15ef2349489..9e01b9a4aa8 100644 --- a/tests/ui/uninit.stderr +++ b/tests/ui/uninit.stderr @@ -1,5 +1,5 @@ error: this call for this type may be undefined behavior - --> $DIR/uninit.rs:7:29 + --> $DIR/uninit.rs:12:29 | LL | let _: usize = unsafe { MaybeUninit::uninit().assume_init() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,16 +7,16 @@ LL | let _: usize = unsafe { MaybeUninit::uninit().assume_init() }; = note: `#[deny(clippy::uninit_assumed_init)]` on by default error: this call for this type may be undefined behavior - --> $DIR/uninit.rs:10:31 - | -LL | let _: [u8; 0] = unsafe { MaybeUninit::uninit().assume_init() }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: this call for this type may be undefined behavior - --> $DIR/uninit.rs:25:29 + --> $DIR/uninit.rs:33:29 | LL | let _: usize = unsafe { mem::MaybeUninit::uninit().assume_init() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +error: this call for this type may be undefined behavior + --> $DIR/uninit.rs:39:29 + | +LL | let _: T = unsafe { mem::MaybeUninit::uninit().assume_init() }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + error: aborting due to 3 previous errors diff --git a/tests/ui/uninit_vec.rs b/tests/ui/uninit_vec.rs index 194e4fc157e..59ec64a7ab1 100644 --- a/tests/ui/uninit_vec.rs +++ b/tests/ui/uninit_vec.rs @@ -7,6 +7,11 @@ struct MyVec { vec: Vec, } +union MyOwnMaybeUninit { + value: u8, + uninit: (), +} + fn main() { // with_capacity() -> set_len() should be detected let mut vec: Vec = Vec::with_capacity(1000); @@ -97,4 +102,26 @@ fn main() { unsafe { vec.set_len(0); } + + // ZSTs should not be detected + let mut vec: Vec<()> = Vec::with_capacity(1000); + unsafe { + vec.set_len(10); + } + + // unions should not be detected + let mut vec: Vec = Vec::with_capacity(1000); + unsafe { + vec.set_len(10); + } + + polymorphic::<()>(); + + fn polymorphic() { + // We are conservative around polymorphic types. + let mut vec: Vec = Vec::with_capacity(1000); + unsafe { + vec.set_len(10); + } + } } diff --git a/tests/ui/uninit_vec.stderr b/tests/ui/uninit_vec.stderr index 77fc689f076..9cdf0c95ad9 100644 --- a/tests/ui/uninit_vec.stderr +++ b/tests/ui/uninit_vec.stderr @@ -1,5 +1,5 @@ error: calling `set_len()` immediately after reserving a buffer creates uninitialized values - --> $DIR/uninit_vec.rs:12:5 + --> $DIR/uninit_vec.rs:17:5 | LL | let mut vec: Vec = Vec::with_capacity(1000); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -11,7 +11,7 @@ LL | vec.set_len(200); = note: `-D clippy::uninit-vec` implied by `-D warnings` error: calling `set_len()` immediately after reserving a buffer creates uninitialized values - --> $DIR/uninit_vec.rs:18:5 + --> $DIR/uninit_vec.rs:23:5 | LL | vec.reserve(1000); | ^^^^^^^^^^^^^^^^^^ @@ -22,7 +22,7 @@ LL | vec.set_len(200); = help: initialize the buffer or wrap the content in `MaybeUninit` error: calling `set_len()` on empty `Vec` creates out-of-bound values - --> $DIR/uninit_vec.rs:24:5 + --> $DIR/uninit_vec.rs:29:5 | LL | let mut vec: Vec = Vec::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -31,7 +31,7 @@ LL | vec.set_len(200); | ^^^^^^^^^^^^^^^^ error: calling `set_len()` on empty `Vec` creates out-of-bound values - --> $DIR/uninit_vec.rs:30:5 + --> $DIR/uninit_vec.rs:35:5 | LL | let mut vec: Vec = Default::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -40,7 +40,7 @@ LL | vec.set_len(200); | ^^^^^^^^^^^^^^^^ error: calling `set_len()` on empty `Vec` creates out-of-bound values - --> $DIR/uninit_vec.rs:35:5 + --> $DIR/uninit_vec.rs:40:5 | LL | let mut vec: Vec = Vec::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL | vec.set_len(200); | ^^^^^^^^^^^^^^^^ error: calling `set_len()` immediately after reserving a buffer creates uninitialized values - --> $DIR/uninit_vec.rs:49:5 + --> $DIR/uninit_vec.rs:54:5 | LL | let mut vec: Vec = Vec::with_capacity(1000); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -60,7 +60,7 @@ LL | vec.set_len(200); = help: initialize the buffer or wrap the content in `MaybeUninit` error: calling `set_len()` immediately after reserving a buffer creates uninitialized values - --> $DIR/uninit_vec.rs:58:5 + --> $DIR/uninit_vec.rs:63:5 | LL | my_vec.vec.reserve(1000); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -71,7 +71,7 @@ LL | my_vec.vec.set_len(200); = help: initialize the buffer or wrap the content in `MaybeUninit` error: calling `set_len()` immediately after reserving a buffer creates uninitialized values - --> $DIR/uninit_vec.rs:63:5 + --> $DIR/uninit_vec.rs:68:5 | LL | my_vec.vec = Vec::with_capacity(1000); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -82,7 +82,7 @@ LL | my_vec.vec.set_len(200); = help: initialize the buffer or wrap the content in `MaybeUninit` error: calling `set_len()` immediately after reserving a buffer creates uninitialized values - --> $DIR/uninit_vec.rs:42:9 + --> $DIR/uninit_vec.rs:47:9 | LL | let mut vec: Vec = Vec::with_capacity(1000); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -92,7 +92,7 @@ LL | vec.set_len(200); = help: initialize the buffer or wrap the content in `MaybeUninit` error: calling `set_len()` immediately after reserving a buffer creates uninitialized values - --> $DIR/uninit_vec.rs:45:9 + --> $DIR/uninit_vec.rs:50:9 | LL | vec.reserve(1000); | ^^^^^^^^^^^^^^^^^^ @@ -101,5 +101,16 @@ LL | vec.set_len(200); | = help: initialize the buffer or wrap the content in `MaybeUninit` -error: aborting due to 10 previous errors +error: calling `set_len()` immediately after reserving a buffer creates uninitialized values + --> $DIR/uninit_vec.rs:122:9 + | +LL | let mut vec: Vec = Vec::with_capacity(1000); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | unsafe { +LL | vec.set_len(10); + | ^^^^^^^^^^^^^^^ + | + = help: initialize the buffer or wrap the content in `MaybeUninit` + +error: aborting due to 11 previous errors diff --git a/tests/ui/uninlined_format_args.fixed b/tests/ui/uninlined_format_args.fixed index cbd5cc5fcee..1475d781c67 100644 --- a/tests/ui/uninlined_format_args.fixed +++ b/tests/ui/uninlined_format_args.fixed @@ -1,11 +1,11 @@ -// aux-build:proc_macro_with_span.rs +// aux-build:proc_macros.rs // run-rustfix #![warn(clippy::uninlined_format_args)] #![allow(named_arguments_used_positionally, unused_imports, unused_macros, unused_variables)] #![allow(clippy::eq_op, clippy::format_in_format_args, clippy::print_literal)] -extern crate proc_macro_with_span; -use proc_macro_with_span::with_span; +extern crate proc_macros; +use proc_macros::with_span; macro_rules! no_param_str { () => { diff --git a/tests/ui/uninlined_format_args.rs b/tests/ui/uninlined_format_args.rs index cf0ea5be481..835afac393f 100644 --- a/tests/ui/uninlined_format_args.rs +++ b/tests/ui/uninlined_format_args.rs @@ -1,11 +1,11 @@ -// aux-build:proc_macro_with_span.rs +// aux-build:proc_macros.rs // run-rustfix #![warn(clippy::uninlined_format_args)] #![allow(named_arguments_used_positionally, unused_imports, unused_macros, unused_variables)] #![allow(clippy::eq_op, clippy::format_in_format_args, clippy::print_literal)] -extern crate proc_macro_with_span; -use proc_macro_with_span::with_span; +extern crate proc_macros; +use proc_macros::with_span; macro_rules! no_param_str { () => { diff --git a/tests/ui/unit_arg.rs b/tests/ui/unit_arg.rs index 07e70873a81..674ae4f1df9 100644 --- a/tests/ui/unit_arg.rs +++ b/tests/ui/unit_arg.rs @@ -1,4 +1,4 @@ -// aux-build: proc_macro_with_span.rs +// aux-build: proc_macros.rs #![warn(clippy::unit_arg)] #![allow(unused_must_use, unused_variables)] #![allow( @@ -13,9 +13,9 @@ clippy::unused_unit )] -extern crate proc_macro_with_span; +extern crate proc_macros; -use proc_macro_with_span::with_span; +use proc_macros::with_span; use std::fmt::Debug; fn foo(t: T) { diff --git a/tests/ui/unnecessary_lazy_eval.fixed b/tests/ui/unnecessary_lazy_eval.fixed index 22e9bd8bdc5..3b93800f8b7 100644 --- a/tests/ui/unnecessary_lazy_eval.fixed +++ b/tests/ui/unnecessary_lazy_eval.fixed @@ -1,12 +1,12 @@ // run-rustfix -// aux-build: proc_macro_with_span.rs +// aux-build: proc_macros.rs #![warn(clippy::unnecessary_lazy_evaluations)] #![allow(clippy::redundant_closure)] #![allow(clippy::bind_instead_of_map)] #![allow(clippy::map_identity)] -extern crate proc_macro_with_span; -use proc_macro_with_span::with_span; +extern crate proc_macros; +use proc_macros::with_span; struct Deep(Option); diff --git a/tests/ui/unnecessary_lazy_eval.rs b/tests/ui/unnecessary_lazy_eval.rs index 8726d84a23f..2851c0c5190 100644 --- a/tests/ui/unnecessary_lazy_eval.rs +++ b/tests/ui/unnecessary_lazy_eval.rs @@ -1,12 +1,12 @@ // run-rustfix -// aux-build: proc_macro_with_span.rs +// aux-build: proc_macros.rs #![warn(clippy::unnecessary_lazy_evaluations)] #![allow(clippy::redundant_closure)] #![allow(clippy::bind_instead_of_map)] #![allow(clippy::map_identity)] -extern crate proc_macro_with_span; -use proc_macro_with_span::with_span; +extern crate proc_macros; +use proc_macros::with_span; struct Deep(Option); diff --git a/tests/ui/unnecessary_operation.fixed b/tests/ui/unnecessary_operation.fixed index 65d9c910b82..b046694f8c6 100644 --- a/tests/ui/unnecessary_operation.fixed +++ b/tests/ui/unnecessary_operation.fixed @@ -1,6 +1,12 @@ // run-rustfix -#![allow(clippy::deref_addrof, dead_code, unused, clippy::no_effect)] +#![allow( + clippy::deref_addrof, + dead_code, + unused, + clippy::no_effect, + clippy::unnecessary_struct_initialization +)] #![warn(clippy::unnecessary_operation)] struct Tuple(i32); diff --git a/tests/ui/unnecessary_operation.rs b/tests/ui/unnecessary_operation.rs index 4e2acd59f04..9ed9679e938 100644 --- a/tests/ui/unnecessary_operation.rs +++ b/tests/ui/unnecessary_operation.rs @@ -1,6 +1,12 @@ // run-rustfix -#![allow(clippy::deref_addrof, dead_code, unused, clippy::no_effect)] +#![allow( + clippy::deref_addrof, + dead_code, + unused, + clippy::no_effect, + clippy::unnecessary_struct_initialization +)] #![warn(clippy::unnecessary_operation)] struct Tuple(i32); diff --git a/tests/ui/unnecessary_operation.stderr b/tests/ui/unnecessary_operation.stderr index 44cf2e01ff7..a1d0d93998a 100644 --- a/tests/ui/unnecessary_operation.stderr +++ b/tests/ui/unnecessary_operation.stderr @@ -1,5 +1,5 @@ error: unnecessary operation - --> $DIR/unnecessary_operation.rs:50:5 + --> $DIR/unnecessary_operation.rs:56:5 | LL | Tuple(get_number()); | ^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` @@ -7,103 +7,103 @@ LL | Tuple(get_number()); = note: `-D clippy::unnecessary-operation` implied by `-D warnings` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:51:5 + --> $DIR/unnecessary_operation.rs:57:5 | LL | Struct { field: get_number() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:52:5 + --> $DIR/unnecessary_operation.rs:58:5 | LL | Struct { ..get_struct() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_struct();` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:53:5 + --> $DIR/unnecessary_operation.rs:59:5 | LL | Enum::Tuple(get_number()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:54:5 + --> $DIR/unnecessary_operation.rs:60:5 | LL | Enum::Struct { field: get_number() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:55:5 + --> $DIR/unnecessary_operation.rs:61:5 | LL | 5 + get_number(); | ^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `5;get_number();` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:56:5 + --> $DIR/unnecessary_operation.rs:62:5 | LL | *&get_number(); | ^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:57:5 + --> $DIR/unnecessary_operation.rs:63:5 | LL | &get_number(); | ^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:58:5 + --> $DIR/unnecessary_operation.rs:64:5 | LL | (5, 6, get_number()); | ^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `5;6;get_number();` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:59:5 + --> $DIR/unnecessary_operation.rs:65:5 | LL | get_number()..; | ^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:60:5 + --> $DIR/unnecessary_operation.rs:66:5 | LL | ..get_number(); | ^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:61:5 + --> $DIR/unnecessary_operation.rs:67:5 | LL | 5..get_number(); | ^^^^^^^^^^^^^^^^ help: statement can be reduced to: `5;get_number();` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:62:5 + --> $DIR/unnecessary_operation.rs:68:5 | LL | [42, get_number()]; | ^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `42;get_number();` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:63:5 + --> $DIR/unnecessary_operation.rs:69:5 | LL | [42, 55][get_usize()]; | ^^^^^^^^^^^^^^^^^^^^^^ help: statement can be written as: `assert!([42, 55].len() > get_usize());` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:64:5 + --> $DIR/unnecessary_operation.rs:70:5 | LL | (42, get_number()).1; | ^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `42;get_number();` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:65:5 + --> $DIR/unnecessary_operation.rs:71:5 | LL | [get_number(); 55]; | ^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:66:5 + --> $DIR/unnecessary_operation.rs:72:5 | LL | [42; 55][get_usize()]; | ^^^^^^^^^^^^^^^^^^^^^^ help: statement can be written as: `assert!([42; 55].len() > get_usize());` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:67:5 + --> $DIR/unnecessary_operation.rs:73:5 | LL | / { LL | | get_number() @@ -111,7 +111,7 @@ LL | | }; | |______^ help: statement can be reduced to: `get_number();` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:70:5 + --> $DIR/unnecessary_operation.rs:76:5 | LL | / FooString { LL | | s: String::from("blah"), diff --git a/tests/ui/unnecessary_struct_initialization.fixed b/tests/ui/unnecessary_struct_initialization.fixed new file mode 100644 index 00000000000..b47129e4a36 --- /dev/null +++ b/tests/ui/unnecessary_struct_initialization.fixed @@ -0,0 +1,73 @@ +// run-rustfix + +#![allow(unused)] +#![warn(clippy::unnecessary_struct_initialization)] + +struct S { + f: String, +} + +#[derive(Clone, Copy)] +struct T { + f: u32, +} + +struct U { + f: u32, +} + +impl Clone for U { + fn clone(&self) -> Self { + // Do not lint: `Self` does not implement `Copy` + Self { ..*self } + } +} + +#[derive(Copy)] +struct V { + f: u32, +} + +impl Clone for V { + fn clone(&self) -> Self { + // Lint: `Self` implements `Copy` + *self + } +} + +fn main() { + // Should lint: `a` would be consumed anyway + let a = S { f: String::from("foo") }; + let mut b = a; + + // Should lint: `b` would be consumed, and is mutable + let c = &mut b; + + // Should not lint as `d` is not mutable + let d = S { f: String::from("foo") }; + let e = &mut S { ..d }; + + // Should lint as `f` would be consumed anyway + let f = S { f: String::from("foo") }; + let g = &f; + + // Should lint: the result of an expression is mutable + let h = &mut *Box::new(S { f: String::from("foo") }); + + // Should not lint: `m` would be both alive and borrowed + let m = T { f: 17 }; + let n = &T { ..m }; + + // Should not lint: `m` should not be modified + let o = &mut T { ..m }; + o.f = 32; + assert_eq!(m.f, 17); + + // Should not lint: `m` should not be modified + let o = &mut T { ..m } as *mut T; + unsafe { &mut *o }.f = 32; + assert_eq!(m.f, 17); + + // Should lint: the result of an expression is mutable and temporary + let p = &mut *Box::new(T { f: 5 }); +} diff --git a/tests/ui/unnecessary_struct_initialization.rs b/tests/ui/unnecessary_struct_initialization.rs new file mode 100644 index 00000000000..63b11c626e5 --- /dev/null +++ b/tests/ui/unnecessary_struct_initialization.rs @@ -0,0 +1,77 @@ +// run-rustfix + +#![allow(unused)] +#![warn(clippy::unnecessary_struct_initialization)] + +struct S { + f: String, +} + +#[derive(Clone, Copy)] +struct T { + f: u32, +} + +struct U { + f: u32, +} + +impl Clone for U { + fn clone(&self) -> Self { + // Do not lint: `Self` does not implement `Copy` + Self { ..*self } + } +} + +#[derive(Copy)] +struct V { + f: u32, +} + +impl Clone for V { + fn clone(&self) -> Self { + // Lint: `Self` implements `Copy` + Self { ..*self } + } +} + +fn main() { + // Should lint: `a` would be consumed anyway + let a = S { f: String::from("foo") }; + let mut b = S { ..a }; + + // Should lint: `b` would be consumed, and is mutable + let c = &mut S { ..b }; + + // Should not lint as `d` is not mutable + let d = S { f: String::from("foo") }; + let e = &mut S { ..d }; + + // Should lint as `f` would be consumed anyway + let f = S { f: String::from("foo") }; + let g = &S { ..f }; + + // Should lint: the result of an expression is mutable + let h = &mut S { + ..*Box::new(S { f: String::from("foo") }) + }; + + // Should not lint: `m` would be both alive and borrowed + let m = T { f: 17 }; + let n = &T { ..m }; + + // Should not lint: `m` should not be modified + let o = &mut T { ..m }; + o.f = 32; + assert_eq!(m.f, 17); + + // Should not lint: `m` should not be modified + let o = &mut T { ..m } as *mut T; + unsafe { &mut *o }.f = 32; + assert_eq!(m.f, 17); + + // Should lint: the result of an expression is mutable and temporary + let p = &mut T { + ..*Box::new(T { f: 5 }) + }; +} diff --git a/tests/ui/unnecessary_struct_initialization.stderr b/tests/ui/unnecessary_struct_initialization.stderr new file mode 100644 index 00000000000..ca497057702 --- /dev/null +++ b/tests/ui/unnecessary_struct_initialization.stderr @@ -0,0 +1,46 @@ +error: unnecessary struct building + --> $DIR/unnecessary_struct_initialization.rs:34:9 + | +LL | Self { ..*self } + | ^^^^^^^^^^^^^^^^ help: replace with: `*self` + | + = note: `-D clippy::unnecessary-struct-initialization` implied by `-D warnings` + +error: unnecessary struct building + --> $DIR/unnecessary_struct_initialization.rs:41:17 + | +LL | let mut b = S { ..a }; + | ^^^^^^^^^ help: replace with: `a` + +error: unnecessary struct building + --> $DIR/unnecessary_struct_initialization.rs:44:18 + | +LL | let c = &mut S { ..b }; + | ^^^^^^^^^ help: replace with: `b` + +error: unnecessary struct building + --> $DIR/unnecessary_struct_initialization.rs:52:14 + | +LL | let g = &S { ..f }; + | ^^^^^^^^^ help: replace with: `f` + +error: unnecessary struct building + --> $DIR/unnecessary_struct_initialization.rs:55:18 + | +LL | let h = &mut S { + | __________________^ +LL | | ..*Box::new(S { f: String::from("foo") }) +LL | | }; + | |_____^ help: replace with: `*Box::new(S { f: String::from("foo") })` + +error: unnecessary struct building + --> $DIR/unnecessary_struct_initialization.rs:74:18 + | +LL | let p = &mut T { + | __________________^ +LL | | ..*Box::new(T { f: 5 }) +LL | | }; + | |_____^ help: replace with: `*Box::new(T { f: 5 })` + +error: aborting due to 6 previous errors + diff --git a/tests/ui/unnecessary_unsafety_doc.rs b/tests/ui/unnecessary_unsafety_doc.rs index c160e31afd3..431093ab369 100644 --- a/tests/ui/unnecessary_unsafety_doc.rs +++ b/tests/ui/unnecessary_unsafety_doc.rs @@ -1,10 +1,10 @@ -// aux-build:doc_unsafe_macros.rs +// aux-build:proc_macros.rs #![allow(clippy::let_unit_value)] #![warn(clippy::unnecessary_safety_doc)] -#[macro_use] -extern crate doc_unsafe_macros; +extern crate proc_macros; +use proc_macros::external; /// This is has no safety section, and does not need one either pub fn destroy_the_planet() { @@ -129,7 +129,11 @@ macro_rules! very_safe { very_safe!(); // we don't lint code from external macros -undocd_safe!(); +external!( + pub fn vey_oy() { + unimplemented!(); + } +); fn main() {} diff --git a/tests/ui/unnecessary_unsafety_doc.stderr b/tests/ui/unnecessary_unsafety_doc.stderr index 72898c93fa1..b0f20fdac5f 100644 --- a/tests/ui/unnecessary_unsafety_doc.stderr +++ b/tests/ui/unnecessary_unsafety_doc.stderr @@ -42,7 +42,7 @@ LL | very_safe!(); = note: this error originates in the macro `very_safe` (in Nightly builds, run with -Z macro-backtrace for more info) error: docs for safe trait have unnecessary `# Safety` section - --> $DIR/unnecessary_unsafety_doc.rs:147:1 + --> $DIR/unnecessary_unsafety_doc.rs:151:1 | LL | pub trait DocumentedSafeTraitWithImplementationHeader { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/triagebot.toml b/triagebot.toml index 6f50ef932e1..3f8f6a7b98c 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -17,6 +17,7 @@ contributing_url = "https://github.com/rust-lang/rust-clippy/blob/master/CONTRIB [assign.owners] "/.github" = ["@flip1995"] +"/util/gh-pages" = ["@xFrednet"] "*" = [ "@flip1995", "@Manishearth", From db4e4afce8f87eb73db3808981215cd28e97095d Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 26 Mar 2023 20:33:54 +0000 Subject: [PATCH 4/7] Don't elaborate non-obligations into obligations --- clippy_lints/src/needless_pass_by_value.rs | 4 ++-- clippy_utils/src/lib.rs | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs index 1ab81aee7b8..327e090d38b 100644 --- a/clippy_lints/src/needless_pass_by_value.rs +++ b/clippy_lints/src/needless_pass_by_value.rs @@ -124,9 +124,9 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { let preds = traits::elaborate_predicates(cx.tcx, cx.param_env.caller_bounds().iter()) .filter(|p| !p.is_global()) - .filter_map(|obligation| { + .filter_map(|pred| { // Note that we do not want to deal with qualified predicates here. - match obligation.predicate.kind().no_bound_vars() { + match pred.kind().no_bound_vars() { Some(ty::PredicateKind::Clause(ty::Clause::Trait(pred))) if pred.def_id() != sized_trait => { Some(pred) }, diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 29830557a44..fd06c0b8677 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -2106,7 +2106,6 @@ pub fn fn_has_unsatisfiable_preds(cx: &LateContext<'_>, did: DefId) -> bool { traits::impossible_predicates( cx.tcx, traits::elaborate_predicates(cx.tcx, predicates) - .map(|o| o.predicate) .collect::>(), ) } From 28b80059ed3ff5ade532e5547af8be0612927fe5 Mon Sep 17 00:00:00 2001 From: Jamen Marz Date: Mon, 27 Mar 2023 10:14:08 -0400 Subject: [PATCH 5/7] Add notes to non-structural const in pattern error message --- tests/ui/crashes/ice-6254.stderr | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/ui/crashes/ice-6254.stderr b/tests/ui/crashes/ice-6254.stderr index 22d82a30c6a..263c27d3d64 100644 --- a/tests/ui/crashes/ice-6254.stderr +++ b/tests/ui/crashes/ice-6254.stderr @@ -6,6 +6,8 @@ LL | FOO_REF_REF => {}, | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #62411 + = note: the traits must be derived, manual `impl`s are not sufficient + = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details = note: `-D indirect-structural-match` implied by `-D warnings` error: aborting due to previous error From fc6262fa0c0cd9bd3e32b3db4f3df5c268acf291 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 16 Mar 2023 22:00:08 +0000 Subject: [PATCH 6/7] Add `(..)` syntax for RTN --- clippy_lints/src/ref_option_ref.rs | 4 ++-- clippy_lints/src/types/borrowed_box.rs | 2 +- clippy_lints/src/types/utils.rs | 4 ++-- clippy_lints/src/use_self.rs | 5 +++-- clippy_utils/src/hir_utils.rs | 7 +------ 5 files changed, 9 insertions(+), 13 deletions(-) diff --git a/clippy_lints/src/ref_option_ref.rs b/clippy_lints/src/ref_option_ref.rs index 448a32b77c0..c984a8286eb 100644 --- a/clippy_lints/src/ref_option_ref.rs +++ b/clippy_lints/src/ref_option_ref.rs @@ -3,7 +3,7 @@ use clippy_utils::last_path_segment; use clippy_utils::source::snippet; use if_chain::if_chain; use rustc_errors::Applicability; -use rustc_hir::{GenericArg, Mutability, Ty, TyKind}; +use rustc_hir::{GenericArg, GenericArgsParentheses, Mutability, Ty, TyKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::symbol::sym; @@ -47,7 +47,7 @@ impl<'tcx> LateLintPass<'tcx> for RefOptionRef { if cx.tcx.is_diagnostic_item(sym::Option, def_id); if let Some(params) = last_path_segment(qpath).args ; - if !params.parenthesized; + if params.parenthesized == GenericArgsParentheses::No; if let Some(inner_ty) = params.args.iter().find_map(|arg| match arg { GenericArg::Type(inner_ty) => Some(inner_ty), _ => None, diff --git a/clippy_lints/src/types/borrowed_box.rs b/clippy_lints/src/types/borrowed_box.rs index 65dfe7637ea..acdf5471069 100644 --- a/clippy_lints/src/types/borrowed_box.rs +++ b/clippy_lints/src/types/borrowed_box.rs @@ -20,7 +20,7 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, lt: &Lifetime, m if let QPath::Resolved(None, path) = *qpath; if let [ref bx] = *path.segments; if let Some(params) = bx.args; - if !params.parenthesized; + if params.parenthesized == hir::GenericArgsParentheses::No; if let Some(inner) = params.args.iter().find_map(|arg| match arg { GenericArg::Type(ty) => Some(ty), _ => None, diff --git a/clippy_lints/src/types/utils.rs b/clippy_lints/src/types/utils.rs index 7f43b7841ff..a30748db88f 100644 --- a/clippy_lints/src/types/utils.rs +++ b/clippy_lints/src/types/utils.rs @@ -1,6 +1,6 @@ use clippy_utils::last_path_segment; use if_chain::if_chain; -use rustc_hir::{GenericArg, QPath, TyKind}; +use rustc_hir::{GenericArg, GenericArgsParentheses, QPath, TyKind}; use rustc_lint::LateContext; use rustc_span::source_map::Span; @@ -8,7 +8,7 @@ pub(super) fn match_borrows_parameter(_cx: &LateContext<'_>, qpath: &QPath<'_>) let last = last_path_segment(qpath); if_chain! { if let Some(params) = last.args; - if !params.parenthesized; + if params.parenthesized == GenericArgsParentheses::No; if let Some(ty) = params.args.iter().find_map(|arg| match arg { GenericArg::Type(ty) => Some(ty), _ => None, diff --git a/clippy_lints/src/use_self.rs b/clippy_lints/src/use_self.rs index 8ea5475fb25..7dfb0956077 100644 --- a/clippy_lints/src/use_self.rs +++ b/clippy_lints/src/use_self.rs @@ -10,7 +10,7 @@ use rustc_hir::{ def::{CtorOf, DefKind, Res}, def_id::LocalDefId, intravisit::{walk_inf, walk_ty, Visitor}, - Expr, ExprKind, FnRetTy, FnSig, GenericArg, GenericParam, GenericParamKind, HirId, Impl, ImplItemKind, Item, + Expr, ExprKind, FnRetTy, FnSig, GenericArg, GenericArgsParentheses, GenericParam, GenericParamKind, HirId, Impl, ImplItemKind, Item, ItemKind, Pat, PatKind, Path, QPath, Ty, TyKind, }; use rustc_hir_analysis::hir_ty_to_ty; @@ -100,7 +100,8 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf { if let TyKind::Path(QPath::Resolved(_, item_path)) = self_ty.kind; let parameters = &item_path.segments.last().expect(SEGMENTS_MSG).args; if parameters.as_ref().map_or(true, |params| { - !params.parenthesized && !params.args.iter().any(|arg| matches!(arg, GenericArg::Lifetime(_))) + params.parenthesized == GenericArgsParentheses::No + && !params.args.iter().any(|arg| matches!(arg, GenericArg::Lifetime(_))) }); if !item.span.from_expansion(); if !is_from_proc_macro(cx, item); // expensive, should be last check diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs index 3a6d23ca5c1..3ee7147828b 100644 --- a/clippy_utils/src/hir_utils.rs +++ b/clippy_utils/src/hir_utils.rs @@ -401,14 +401,9 @@ impl HirEqInterExpr<'_, '_, '_> { } fn eq_path_parameters(&mut self, left: &GenericArgs<'_>, right: &GenericArgs<'_>) -> bool { - if !(left.parenthesized || right.parenthesized) { + if left.parenthesized == right.parenthesized { over(left.args, right.args, |l, r| self.eq_generic_arg(l, r)) // FIXME(flip1995): may not work && over(left.bindings, right.bindings, |l, r| self.eq_type_binding(l, r)) - } else if left.parenthesized && right.parenthesized { - over(left.inputs(), right.inputs(), |l, r| self.eq_ty(l, r)) - && both(&Some(&left.bindings[0].ty()), &Some(&right.bindings[0].ty()), |l, r| { - self.eq_ty(l, r) - }) } else { false } From 4cf5bdc60c7ccec3b5f395ee393615c224e28555 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 12 Dec 2022 00:42:45 -0500 Subject: [PATCH 7/7] Stabilize a portion of 'once_cell' Move items not part of this stabilization to 'lazy_cell' or 'once_cell_try' --- clippy_dev/src/lib.rs | 1 - clippy_lints/src/lib.rs | 1 - clippy_utils/src/lib.rs | 1 - src/driver.rs | 2 +- tests/compile-test.rs | 2 +- tests/dogfood.rs | 2 +- tests/lint_message_convention.rs | 2 +- tests/workspace.rs | 2 +- 8 files changed, 5 insertions(+), 8 deletions(-) diff --git a/clippy_dev/src/lib.rs b/clippy_dev/src/lib.rs index e70488165b9..8871873c661 100644 --- a/clippy_dev/src/lib.rs +++ b/clippy_dev/src/lib.rs @@ -1,5 +1,4 @@ #![feature(let_chains)] -#![feature(once_cell)] #![feature(rustc_private)] #![cfg_attr(feature = "deny-warnings", deny(warnings))] // warn on lints, that are included in `rust-lang/rust`s bootstrap diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index c9210bf73f8..3da7f95c1b9 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -7,7 +7,6 @@ #![feature(let_chains)] #![feature(lint_reasons)] #![feature(never_type)] -#![feature(once_cell)] #![feature(rustc_private)] #![feature(stmt_expr_attributes)] #![recursion_limit = "512"] diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index fd06c0b8677..619aa9f4bf6 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -3,7 +3,6 @@ #![feature(let_chains)] #![feature(lint_reasons)] #![feature(never_type)] -#![feature(once_cell)] #![feature(rustc_private)] #![recursion_limit = "512"] #![cfg_attr(feature = "deny-warnings", deny(warnings))] diff --git a/src/driver.rs b/src/driver.rs index f08393c303e..9e0822404b6 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -1,6 +1,6 @@ #![feature(rustc_private)] #![feature(let_chains)] -#![feature(once_cell)] +#![feature(lazy_cell)] #![feature(lint_reasons)] #![cfg_attr(feature = "deny-warnings", deny(warnings))] // warn on lints, that are included in `rust-lang/rust`s bootstrap diff --git a/tests/compile-test.rs b/tests/compile-test.rs index c10ee969c01..57890ff3173 100644 --- a/tests/compile-test.rs +++ b/tests/compile-test.rs @@ -1,5 +1,5 @@ #![feature(test)] // compiletest_rs requires this attribute -#![feature(once_cell)] +#![feature(lazy_cell)] #![feature(is_sorted)] #![cfg_attr(feature = "deny-warnings", deny(warnings))] #![warn(rust_2018_idioms, unused_lifetimes)] diff --git a/tests/dogfood.rs b/tests/dogfood.rs index 3a5d478fa31..68a878e9a3d 100644 --- a/tests/dogfood.rs +++ b/tests/dogfood.rs @@ -3,7 +3,7 @@ //! //! See [Eating your own dog food](https://en.wikipedia.org/wiki/Eating_your_own_dog_food) for context -#![feature(once_cell)] +#![feature(lazy_cell)] #![cfg_attr(feature = "deny-warnings", deny(warnings))] #![warn(rust_2018_idioms, unused_lifetimes)] diff --git a/tests/lint_message_convention.rs b/tests/lint_message_convention.rs index abd0d1bc593..8feea800fdb 100644 --- a/tests/lint_message_convention.rs +++ b/tests/lint_message_convention.rs @@ -1,4 +1,4 @@ -#![feature(once_cell)] +#![feature(lazy_cell)] #![cfg_attr(feature = "deny-warnings", deny(warnings))] #![warn(rust_2018_idioms, unused_lifetimes)] diff --git a/tests/workspace.rs b/tests/workspace.rs index 95325e06037..c9cbc50546c 100644 --- a/tests/workspace.rs +++ b/tests/workspace.rs @@ -1,4 +1,4 @@ -#![feature(once_cell)] +#![feature(lazy_cell)] use std::path::PathBuf; use std::process::Command;