From f5ac844296335590c30caeef9fddb1af0692ab76 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Sat, 8 Oct 2022 23:47:59 +0100 Subject: [PATCH 01/86] Refactor unwind from Option to a new enum --- clippy_utils/src/qualify_min_const_fn.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clippy_utils/src/qualify_min_const_fn.rs b/clippy_utils/src/qualify_min_const_fn.rs index d66640ba0b7a7..ff195cd728802 100644 --- a/clippy_utils/src/qualify_min_const_fn.rs +++ b/clippy_utils/src/qualify_min_const_fn.rs @@ -318,7 +318,7 @@ fn check_terminator<'tcx>( from_hir_call: _, destination: _, target: _, - cleanup: _, + unwind: _, fn_span: _, } => { let fn_ty = func.ty(body, tcx); @@ -361,7 +361,7 @@ fn check_terminator<'tcx>( expected: _, msg: _, target: _, - cleanup: _, + unwind: _, } => check_operand(tcx, cond, span, body), TerminatorKind::InlineAsm { .. } => Err((span, "cannot use inline assembly in const fn".into())), From 293c1a1a6a8ee0b56e1086a5d66e0bacb75a76df Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Mon, 10 Oct 2022 23:17:07 +0100 Subject: [PATCH 02/86] Fix tools --- 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 ff195cd728802..354b6d71aa466 100644 --- a/clippy_utils/src/qualify_min_const_fn.rs +++ b/clippy_utils/src/qualify_min_const_fn.rs @@ -301,13 +301,13 @@ fn check_terminator<'tcx>( | TerminatorKind::Goto { .. } | TerminatorKind::Return | TerminatorKind::Resume + | TerminatorKind::Terminate | TerminatorKind::Unreachable => Ok(()), TerminatorKind::Drop { place, .. } => check_place(tcx, *place, span, body), TerminatorKind::SwitchInt { discr, targets: _ } => check_operand(tcx, discr, span, body), - TerminatorKind::Abort => Err((span, "abort is not stable in const fn".into())), TerminatorKind::GeneratorDrop | TerminatorKind::Yield { .. } => { Err((span, "const fn generators are unstable".into())) }, From 0963a66ab3f6413a47c7c08524c3e86b02feebaf Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 6 Apr 2023 23:11:19 +0000 Subject: [PATCH 03/86] Make elaborator generic --- clippy_lints/src/needless_pass_by_value.rs | 2 +- clippy_utils/src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs index 327e090d38be8..0bb1775aae9cf 100644 --- a/clippy_lints/src/needless_pass_by_value.rs +++ b/clippy_lints/src/needless_pass_by_value.rs @@ -122,7 +122,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { let sized_trait = need!(cx.tcx.lang_items().sized_trait()); - let preds = traits::elaborate_predicates(cx.tcx, cx.param_env.caller_bounds().iter()) + let preds = traits::elaborate(cx.tcx, cx.param_env.caller_bounds().iter()) .filter(|p| !p.is_global()) .filter_map(|pred| { // Note that we do not want to deal with qualified predicates here. diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 619aa9f4bf6fa..9051cf51658df 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -2104,7 +2104,7 @@ pub fn fn_has_unsatisfiable_preds(cx: &LateContext<'_>, did: DefId) -> bool { .filter_map(|(p, _)| if p.is_global() { Some(*p) } else { None }); traits::impossible_predicates( cx.tcx, - traits::elaborate_predicates(cx.tcx, predicates) + traits::elaborate(cx.tcx, predicates) .collect::>(), ) } From 6b95029f176e5cdaa88de8ca7f5f59fd15a6d850 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Tue, 11 Apr 2023 15:31:08 +0200 Subject: [PATCH 04/86] Merge commit '83e42a2337dadac915c956d125f1d69132f36425' into clippyup --- .cargo/config.toml | 3 + .editorconfig | 1 + .github/workflows/clippy_bors.yml | 2 + .github/workflows/remark.yml | 2 +- CHANGELOG.md | 7 + README.md | 6 +- book/src/README.md | 2 +- book/src/SUMMARY.md | 1 + book/src/configuration.md | 29 +- book/src/development/README.md | 2 +- book/src/development/adding_lints.md | 32 +- book/src/development/basics.md | 6 +- .../development/common_tools_writing_lints.md | 14 +- book/src/development/infrastructure/book.md | 4 +- .../infrastructure/changelog_update.md | 2 +- .../src/development/infrastructure/release.md | 2 +- book/src/development/infrastructure/sync.md | 13 +- book/src/development/proposals/README.md | 2 +- .../src/development/proposals/roadmap-2021.md | 6 +- .../proposals/syntax-tree-patterns.md | 28 +- book/src/development/type_checking.md | 144 ++++ book/src/installation.md | 4 +- book/src/lint_configuration.md | 18 +- book/src/lints.md | 10 +- book/src/usage.md | 4 +- clippy_dev/src/lib.rs | 1 + clippy_dev/src/new_lint.rs | 8 +- clippy_dev/src/update_lints.rs | 14 +- clippy_lints/Cargo.toml | 1 + clippy_lints/src/booleans.rs | 39 +- .../src/casts/cast_possible_truncation.rs | 42 +- clippy_lints/src/collection_is_never_read.rs | 39 +- clippy_lints/src/declared_lints.rs | 7 + clippy_lints/src/disallowed_script_idents.rs | 2 +- clippy_lints/src/explicit_write.rs | 29 +- .../src/extra_unused_type_parameters.rs | 177 ++-- clippy_lints/src/format.rs | 91 +- clippy_lints/src/format_args.rs | 224 +++-- clippy_lints/src/format_impl.rs | 60 +- clippy_lints/src/functions/must_use.rs | 18 +- clippy_lints/src/items_after_statements.rs | 31 +- clippy_lints/src/large_futures.rs | 87 ++ clippy_lints/src/lib.rs | 36 +- clippy_lints/src/lines_filter_map_ok.rs | 100 +++ .../src/manual_slice_size_calculation.rs | 93 ++ clippy_lints/src/mem_replace.rs | 71 +- clippy_lints/src/methods/clear_with_drain.rs | 53 ++ clippy_lints/src/methods/expect_fun_call.rs | 27 +- clippy_lints/src/methods/iter_with_drain.rs | 24 +- clippy_lints/src/methods/mod.rs | 40 +- clippy_lints/src/missing_const_for_fn.rs | 1 + .../src/operators/arithmetic_side_effects.rs | 12 +- clippy_lints/src/redundant_async_block.rs | 145 ++-- .../src/redundant_static_lifetimes.rs | 4 +- clippy_lints/src/returns.rs | 32 +- .../src/single_component_path_imports.rs | 59 +- clippy_lints/src/suspicious_doc_comments.rs | 94 ++ clippy_lints/src/tests_outside_test_module.rs | 71 ++ .../transmutes_expressible_as_ptr_casts.rs | 11 +- clippy_lints/src/unnecessary_box_returns.rs | 120 +++ .../src/unnecessary_struct_initialization.rs | 8 +- clippy_lints/src/use_self.rs | 4 +- clippy_lints/src/utils/conf.rs | 36 +- .../src/utils/format_args_collector.rs | 79 +- clippy_lints/src/write.rs | 14 +- clippy_utils/src/ast_utils.rs | 39 +- clippy_utils/src/lib.rs | 72 +- clippy_utils/src/macros.rs | 800 ++---------------- clippy_utils/src/paths.rs | 2 + clippy_utils/src/ty.rs | 22 +- etc/relicense/RELICENSE_DOCUMENTATION.md | 4 +- lintcheck/README.md | 2 +- rust-toolchain | 2 +- src/driver.rs | 2 +- .../warn/src/main.stderr | 6 +- .../uninlined_format_args.stderr | 22 +- .../extra_unused_type_parameters/clippy.toml | 1 + .../extra_unused_type_parameters.rs | 9 + tests/ui-toml/large_futures/clippy.toml | 1 + tests/ui-toml/large_futures/large_futures.rs | 27 + .../large_futures/large_futures.stderr | 10 + .../toml_unknown_key/conf_unknown_key.stderr | 1 + tests/ui/arithmetic_side_effects.rs | 4 + tests/ui/arithmetic_side_effects.stderr | 14 +- tests/ui/auxiliary/proc_macros.rs | 2 +- tests/ui/cast.rs | 6 + tests/ui/cast.stderr | 112 ++- tests/ui/clear_with_drain.fixed | 358 ++++++++ tests/ui/clear_with_drain.rs | 358 ++++++++ tests/ui/clear_with_drain.stderr | 130 +++ tests/ui/collection_is_never_read.rs | 31 +- tests/ui/collection_is_never_read.stderr | 34 +- tests/ui/double_must_use.rs | 11 + tests/ui/double_must_use.stderr | 10 +- tests/ui/extra_unused_type_parameters.fixed | 105 +++ tests/ui/extra_unused_type_parameters.rs | 11 +- tests/ui/extra_unused_type_parameters.stderr | 79 +- .../extra_unused_type_parameters_unfixable.rs | 24 + ...ra_unused_type_parameters_unfixable.stderr | 27 + tests/ui/format_args_unfixable.rs | 44 + tests/ui/format_args_unfixable.stderr | 36 +- ..._statement.rs => items_after_statement.rs} | 17 + ...nt.stderr => items_after_statement.stderr} | 6 +- tests/ui/large_futures.rs | 61 ++ tests/ui/large_futures.stderr | 82 ++ tests/ui/lines_filter_map_ok.fixed | 29 + tests/ui/lines_filter_map_ok.rs | 29 + tests/ui/lines_filter_map_ok.stderr | 51 ++ tests/ui/manual_slice_size_calculation.rs | 36 + tests/ui/manual_slice_size_calculation.stderr | 51 ++ tests/ui/mem_replace.fixed | 34 + tests/ui/mem_replace.rs | 34 + tests/ui/mem_replace.stderr | 26 +- tests/ui/needless_return.fixed | 9 + tests/ui/needless_return.rs | 9 + tests/ui/nonminimal_bool.rs | 18 + tests/ui/print_literal.rs | 4 + tests/ui/redundant_async_block.fixed | 148 +++- tests/ui/redundant_async_block.rs | 148 +++- tests/ui/redundant_async_block.stderr | 46 +- tests/ui/single_component_path_imports.fixed | 6 + tests/ui/single_component_path_imports.rs | 6 + tests/ui/single_component_path_imports.stderr | 4 +- tests/ui/suspicious_doc_comments.fixed | 81 ++ tests/ui/suspicious_doc_comments.rs | 81 ++ tests/ui/suspicious_doc_comments.stderr | 114 +++ tests/ui/suspicious_doc_comments_unfixable.rs | 16 + .../suspicious_doc_comments_unfixable.stderr | 37 + tests/ui/tests_outside_test_module.rs | 18 + tests/ui/tests_outside_test_module.stderr | 11 + .../transmutes_expressible_as_ptr_casts.fixed | 8 +- .../ui/transmutes_expressible_as_ptr_casts.rs | 8 +- ...transmutes_expressible_as_ptr_casts.stderr | 8 +- tests/ui/uninit.rs | 18 +- tests/ui/uninit.stderr | 10 +- tests/ui/uninit_vec.rs | 8 + tests/ui/uninlined_format_args.fixed | 88 +- tests/ui/uninlined_format_args.rs | 86 +- tests/ui/uninlined_format_args.stderr | 14 +- tests/ui/unnecessary_box_returns.rs | 60 ++ tests/ui/unnecessary_box_returns.stderr | 35 + tests/ui/unused_format_specs.fixed | 18 - tests/ui/unused_format_specs.rs | 18 - tests/ui/unused_format_specs.stderr | 54 -- tests/ui/unused_format_specs_unfixable.stderr | 12 +- 145 files changed, 4728 insertions(+), 1695 deletions(-) create mode 100644 book/src/development/type_checking.md create mode 100644 clippy_lints/src/large_futures.rs create mode 100644 clippy_lints/src/lines_filter_map_ok.rs create mode 100644 clippy_lints/src/manual_slice_size_calculation.rs create mode 100644 clippy_lints/src/methods/clear_with_drain.rs create mode 100644 clippy_lints/src/suspicious_doc_comments.rs create mode 100644 clippy_lints/src/tests_outside_test_module.rs create mode 100644 clippy_lints/src/unnecessary_box_returns.rs create mode 100644 tests/ui-toml/extra_unused_type_parameters/clippy.toml create mode 100644 tests/ui-toml/extra_unused_type_parameters/extra_unused_type_parameters.rs create mode 100644 tests/ui-toml/large_futures/clippy.toml create mode 100644 tests/ui-toml/large_futures/large_futures.rs create mode 100644 tests/ui-toml/large_futures/large_futures.stderr create mode 100644 tests/ui/clear_with_drain.fixed create mode 100644 tests/ui/clear_with_drain.rs create mode 100644 tests/ui/clear_with_drain.stderr create mode 100644 tests/ui/extra_unused_type_parameters.fixed create mode 100644 tests/ui/extra_unused_type_parameters_unfixable.rs create mode 100644 tests/ui/extra_unused_type_parameters_unfixable.stderr rename tests/ui/{item_after_statement.rs => items_after_statement.rs} (69%) rename tests/ui/{item_after_statement.stderr => items_after_statement.stderr} (87%) create mode 100644 tests/ui/large_futures.rs create mode 100644 tests/ui/large_futures.stderr create mode 100644 tests/ui/lines_filter_map_ok.fixed create mode 100644 tests/ui/lines_filter_map_ok.rs create mode 100644 tests/ui/lines_filter_map_ok.stderr create mode 100644 tests/ui/manual_slice_size_calculation.rs create mode 100644 tests/ui/manual_slice_size_calculation.stderr create mode 100644 tests/ui/suspicious_doc_comments.fixed create mode 100644 tests/ui/suspicious_doc_comments.rs create mode 100644 tests/ui/suspicious_doc_comments.stderr create mode 100644 tests/ui/suspicious_doc_comments_unfixable.rs create mode 100644 tests/ui/suspicious_doc_comments_unfixable.stderr create mode 100644 tests/ui/tests_outside_test_module.rs create mode 100644 tests/ui/tests_outside_test_module.stderr create mode 100644 tests/ui/unnecessary_box_returns.rs create mode 100644 tests/ui/unnecessary_box_returns.stderr delete mode 100644 tests/ui/unused_format_specs.fixed delete mode 100644 tests/ui/unused_format_specs.rs delete mode 100644 tests/ui/unused_format_specs.stderr diff --git a/.cargo/config.toml b/.cargo/config.toml index f3dd9275a42be..4d80d3ce63dac 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -11,3 +11,6 @@ target-dir = "target" [unstable] binary-dep-depinfo = true + +[profile.dev] +split-debuginfo = "unpacked" diff --git a/.editorconfig b/.editorconfig index ec6e107d547f0..bc7642bf8c7c9 100644 --- a/.editorconfig +++ b/.editorconfig @@ -11,6 +11,7 @@ trim_trailing_whitespace = true insert_final_newline = true indent_style = space indent_size = 4 +max_line_length = 120 [*.md] # double whitespace at end of line diff --git a/.github/workflows/clippy_bors.yml b/.github/workflows/clippy_bors.yml index 24e677ce8e170..93198aabdb5f5 100644 --- a/.github/workflows/clippy_bors.yml +++ b/.github/workflows/clippy_bors.yml @@ -180,6 +180,8 @@ jobs: # Run - name: Build Integration Test + env: + CARGO_PROFILE_DEV_SPLIT_DEBUGINFO: off run: cargo test --test integration --features integration --no-run # Upload diff --git a/.github/workflows/remark.yml b/.github/workflows/remark.yml index 81ef072bbb07f..116058b7c7538 100644 --- a/.github/workflows/remark.yml +++ b/.github/workflows/remark.yml @@ -29,7 +29,7 @@ jobs: - name: Install mdbook run: | mkdir mdbook - curl -Lf https://github.com/rust-lang/mdBook/releases/download/v0.4.18/mdbook-v0.4.18-x86_64-unknown-linux-gnu.tar.gz | tar -xz --directory=./mdbook + curl -Lf https://github.com/rust-lang/mdBook/releases/download/v0.4.28/mdbook-v0.4.28-x86_64-unknown-linux-gnu.tar.gz | tar -xz --directory=./mdbook echo `pwd`/mdbook >> $GITHUB_PATH # Run diff --git a/CHANGELOG.md b/CHANGELOG.md index 1323f973ccfdd..559b560dde4ba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4441,6 +4441,7 @@ Released 2018-09-13 [`chars_last_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#chars_last_cmp [`chars_next_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#chars_next_cmp [`checked_conversions`]: https://rust-lang.github.io/rust-clippy/master/index.html#checked_conversions +[`clear_with_drain`]: https://rust-lang.github.io/rust-clippy/master/index.html#clear_with_drain [`clone_double_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#clone_double_ref [`clone_on_copy`]: https://rust-lang.github.io/rust-clippy/master/index.html#clone_on_copy [`clone_on_ref_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#clone_on_ref_ptr @@ -4632,6 +4633,7 @@ Released 2018-09-13 [`large_const_arrays`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_const_arrays [`large_digit_groups`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_digit_groups [`large_enum_variant`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_enum_variant +[`large_futures`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_futures [`large_include_file`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_include_file [`large_stack_arrays`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_stack_arrays [`large_types_passed_by_value`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_types_passed_by_value @@ -4645,6 +4647,7 @@ Released 2018-09-13 [`let_underscore_untyped`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_underscore_untyped [`let_unit_value`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_unit_value [`let_with_type_underscore`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_with_type_underscore +[`lines_filter_map_ok`]: https://rust-lang.github.io/rust-clippy/master/index.html#lines_filter_map_ok [`linkedlist`]: https://rust-lang.github.io/rust-clippy/master/index.html#linkedlist [`logic_bug`]: https://rust-lang.github.io/rust-clippy/master/index.html#logic_bug [`lossy_float_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#lossy_float_literal @@ -4671,6 +4674,7 @@ Released 2018-09-13 [`manual_rem_euclid`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_rem_euclid [`manual_retain`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_retain [`manual_saturating_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_saturating_arithmetic +[`manual_slice_size_calculation`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_slice_size_calculation [`manual_split_once`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_split_once [`manual_str_repeat`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_str_repeat [`manual_string_new`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_string_new @@ -4921,6 +4925,7 @@ Released 2018-09-13 [`suspicious_arithmetic_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_arithmetic_impl [`suspicious_assignment_formatting`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_assignment_formatting [`suspicious_command_arg_space`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_command_arg_space +[`suspicious_doc_comments`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_doc_comments [`suspicious_else_formatting`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_else_formatting [`suspicious_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_map [`suspicious_op_assign_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_op_assign_impl @@ -4933,6 +4938,7 @@ Released 2018-09-13 [`tabs_in_doc_comments`]: https://rust-lang.github.io/rust-clippy/master/index.html#tabs_in_doc_comments [`temporary_assignment`]: https://rust-lang.github.io/rust-clippy/master/index.html#temporary_assignment [`temporary_cstring_as_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#temporary_cstring_as_ptr +[`tests_outside_test_module`]: https://rust-lang.github.io/rust-clippy/master/index.html#tests_outside_test_module [`to_digit_is_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#to_digit_is_some [`to_string_in_display`]: https://rust-lang.github.io/rust-clippy/master/index.html#to_string_in_display [`to_string_in_format_args`]: https://rust-lang.github.io/rust-clippy/master/index.html#to_string_in_format_args @@ -4974,6 +4980,7 @@ Released 2018-09-13 [`unit_hash`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_hash [`unit_return_expecting_ord`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_return_expecting_ord [`unknown_clippy_lints`]: https://rust-lang.github.io/rust-clippy/master/index.html#unknown_clippy_lints +[`unnecessary_box_returns`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_box_returns [`unnecessary_cast`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_cast [`unnecessary_filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_filter_map [`unnecessary_find_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_find_map diff --git a/README.md b/README.md index b69ed8900a491..85798e0e80c15 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ Lints are divided into categories, each with a default [lint level](https://doc. You can choose how much Clippy is supposed to ~~annoy~~ help you by changing the lint level by category. | Category | Description | Default level | -| --------------------- | ----------------------------------------------------------------------------------- | ------------- | +|-----------------------|-------------------------------------------------------------------------------------|---------------| | `clippy::all` | all lints that are on by default (correctness, suspicious, style, complexity, perf) | **warn/deny** | | `clippy::correctness` | code that is outright wrong or useless | **deny** | | `clippy::suspicious` | code that is most likely wrong or useless | **warn** | @@ -130,7 +130,7 @@ for example. You can add Clippy to Travis CI in the same way you use it locally: -```yml +```yaml language: rust rust: - stable @@ -253,7 +253,7 @@ rust-version = "1.30" The MSRV can also be specified as an attribute, like below. -```rust +```rust,ignore #![feature(custom_inner_attributes)] #![clippy::msrv = "1.30.0"] diff --git a/book/src/README.md b/book/src/README.md index df4a1f2702e47..3b6270962680e 100644 --- a/book/src/README.md +++ b/book/src/README.md @@ -14,7 +14,7 @@ much Clippy is supposed to ~~annoy~~ help you by changing the lint level by category. | Category | Description | Default level | -| --------------------- | ----------------------------------------------------------------------------------- | ------------- | +|-----------------------|-------------------------------------------------------------------------------------|---------------| | `clippy::all` | all lints that are on by default (correctness, suspicious, style, complexity, perf) | **warn/deny** | | `clippy::correctness` | code that is outright wrong or useless | **deny** | | `clippy::suspicious` | code that is most likely wrong or useless | **warn** | diff --git a/book/src/SUMMARY.md b/book/src/SUMMARY.md index 0649f7a631df4..cbd73376dfa07 100644 --- a/book/src/SUMMARY.md +++ b/book/src/SUMMARY.md @@ -13,6 +13,7 @@ - [Development](development/README.md) - [Basics](development/basics.md) - [Adding Lints](development/adding_lints.md) + - [Type Checking](development/type_checking.md) - [Common Tools](development/common_tools_writing_lints.md) - [Infrastructure](development/infrastructure/README.md) - [Syncing changes between Clippy and rust-lang/rust](development/infrastructure/sync.md) diff --git a/book/src/configuration.md b/book/src/configuration.md index 87f4a697af9fd..1304f6a8c2f09 100644 --- a/book/src/configuration.md +++ b/book/src/configuration.md @@ -3,7 +3,7 @@ > **Note:** The configuration file is unstable and may be deprecated in the future. Some lints can be configured in a TOML file named `clippy.toml` or `.clippy.toml`. It contains a -basic `variable = value` mapping eg. +basic `variable = value` mapping e.g. ```toml avoid-breaking-exported-api = false @@ -60,7 +60,7 @@ And to warn on `lint_name`, run cargo clippy -- -W clippy::lint_name ``` -This also works with lint groups. For example you can run Clippy with warnings for all lints enabled: +This also works with lint groups. For example, you can run Clippy with warnings for all lints enabled: ```terminal cargo clippy -- -W clippy::pedantic @@ -84,7 +84,7 @@ msrv = "1.30.0" The MSRV can also be specified as an attribute, like below. -```rust +```rust,ignore #![feature(custom_inner_attributes)] #![clippy::msrv = "1.30.0"] @@ -96,7 +96,28 @@ fn main() { You can also omit the patch version when specifying the MSRV, so `msrv = 1.30` is equivalent to `msrv = 1.30.0`. -Note: `custom_inner_attributes` is an unstable feature so it has to be enabled explicitly. +Note: `custom_inner_attributes` is an unstable feature, so it has to be enabled explicitly. Lints that recognize this configuration option can be found [here](https://rust-lang.github.io/rust-clippy/master/index.html#msrv) + +### Disabling evaluation of certain code + +> **Note:** This should only be used in cases where other solutions, like `#[allow(clippy::all)]`, are not sufficient. + +Very rarely, you may wish to prevent Clippy from evaluating certain sections of code entirely. You can do this with +[conditional compilation](https://doc.rust-lang.org/reference/conditional-compilation.html) by checking that the +`cargo-clippy` feature is not set. You may need to provide a stub so that the code compiles: + +```rust +#[cfg(not(feature = "cargo-clippy"))] +include!(concat!(env!("OUT_DIR"), "/my_big_function-generated.rs")); + +#[cfg(feature = "cargo-clippy")] +fn my_big_function(_input: &str) -> Option { + None +} +``` + +This feature is not actually part of your crate, so specifying `--all-features` to other tools, e.g. `cargo test +--all-features`, will not disable it. diff --git a/book/src/development/README.md b/book/src/development/README.md index 5cf7201cffad7..616e6d182b729 100644 --- a/book/src/development/README.md +++ b/book/src/development/README.md @@ -5,7 +5,7 @@ making Clippy better by contributing to it. In that case, welcome to the project! > _Note:_ If you're just interested in using Clippy, there's nothing to see from -> this point onward and you should return to one of the earlier chapters. +> this point onward, and you should return to one of the earlier chapters. ## Getting started diff --git a/book/src/development/adding_lints.md b/book/src/development/adding_lints.md index f57dc627dce4c..9dacaaaae5c92 100644 --- a/book/src/development/adding_lints.md +++ b/book/src/development/adding_lints.md @@ -18,6 +18,7 @@ because that's clearly a non-descriptive name. - [Cargo lints](#cargo-lints) - [Rustfix tests](#rustfix-tests) - [Testing manually](#testing-manually) + - [Running directly](#running-directly) - [Lint declaration](#lint-declaration) - [Lint registration](#lint-registration) - [Lint passes](#lint-passes) @@ -186,6 +187,15 @@ cargo dev lint input.rs from the working copy root. With tests in place, let's have a look at implementing our lint now. +## Running directly + +While it's easier to just use `cargo dev lint`, it might be desirable to get +`target/release/cargo-clippy` and `target/release/clippy-driver` to work as well in some cases. +By default, they don't work because clippy dynamically links rustc. To help them find rustc, +add the path printed by`rustc --print target-libdir` (ran inside this workspace so that the rustc version matches) +to your library search path. +On linux, this can be done by setting the `LD_LIBRARY_PATH` environment variable to that path. + ## Lint declaration Let's start by opening the new file created in the `clippy_lints` crate at @@ -265,7 +275,7 @@ When declaring a new lint by hand and `cargo dev update_lints` is used, the lint pass may have to be registered manually in the `register_plugins` function in `clippy_lints/src/lib.rs`: -```rust +```rust,ignore store.register_early_pass(|| Box::new(foo_functions::FooFunctions)); ``` @@ -291,7 +301,7 @@ either [`EarlyLintPass`][early_lint_pass] or [`LateLintPass`][late_lint_pass]. In short, the `LateLintPass` has access to type information while the `EarlyLintPass` doesn't. If you don't need access to type information, use the -`EarlyLintPass`. The `EarlyLintPass` is also faster. However linting speed +`EarlyLintPass`. The `EarlyLintPass` is also faster. However, linting speed hasn't really been a concern with Clippy so far. Since we don't need type information for checking the function name, we used @@ -308,7 +318,7 @@ implementation of the lint logic. Let's start by implementing the `EarlyLintPass` for our `FooFunctions`: -```rust +```rust,ignore impl EarlyLintPass for FooFunctions { fn check_fn(&mut self, cx: &EarlyContext<'_>, fn_kind: FnKind<'_>, span: Span, _: NodeId) { // TODO: Emit lint here @@ -327,10 +337,10 @@ variety of lint emission functions. They can all be found in [`clippy_utils/src/diagnostics.rs`][diagnostics]. `span_lint_and_help` seems most appropriate in this case. It allows us to -provide an extra help message and we can't really suggest a better name +provide an extra help message, and we can't really suggest a better name automatically. This is how it looks: -```rust +```rust,ignore impl EarlyLintPass for FooFunctions { fn check_fn(&mut self, cx: &EarlyContext<'_>, fn_kind: FnKind<'_>, span: Span, _: NodeId) { span_lint_and_help( @@ -469,7 +479,7 @@ the value from `clippy.toml`. This can be accounted for using the `extract_msrv_attr!(LintContext)` macro and passing `LateContext`/`EarlyContext`. -```rust +```rust,ignore impl<'tcx> LateLintPass<'tcx> for ManualStrip { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { ... @@ -483,7 +493,7 @@ the lint's test file, `tests/ui/manual_strip.rs` in this example. It should have a case for the version below the MSRV and one with the same contents but for the MSRV version itself. -```rust +```rust,ignore ... #[clippy::msrv = "1.44"] @@ -514,7 +524,7 @@ define_Conf! { If you have trouble implementing your lint, there is also the internal `author` lint to generate Clippy code that detects the offending pattern. It does not -work for all of the Rust syntax, but can give a good starting point. +work for all the Rust syntax, but can give a good starting point. The quickest way to use it, is the [Rust playground: play.rust-lang.org][author_example]. Put the code you want to lint into the @@ -607,7 +617,7 @@ output in the `stdout` part. ## PR Checklist -Before submitting your PR make sure you followed all of the basic requirements: +Before submitting your PR make sure you followed all the basic requirements: @@ -627,7 +637,7 @@ for some users. Adding a configuration is done in the following steps: 1. Adding a new configuration entry to [`clippy_lints::utils::conf`] like this: - ```rust + ```rust,ignore /// Lint: LINT_NAME. /// /// @@ -680,7 +690,7 @@ for some users. Adding a configuration is done in the following steps: configuration value is now cloned or copied into a local value that is then passed to the impl struct like this: - ```rust + ```rust,ignore // Default generated registration: store.register_*_pass(|| box module::StructName); diff --git a/book/src/development/basics.md b/book/src/development/basics.md index 6fb53236e6f1a..7615dc12f9ebe 100644 --- a/book/src/development/basics.md +++ b/book/src/development/basics.md @@ -4,8 +4,8 @@ This document explains the basics for hacking on Clippy. Besides others, this includes how to build and test Clippy. For a more in depth description on the codebase take a look at [Adding Lints] or [Common Tools]. -[Adding Lints]: https://github.com/rust-lang/rust-clippy/blob/master/book/src/development/adding_lints.md -[Common Tools]: https://github.com/rust-lang/rust-clippy/blob/master/book/src/development/common_tools_writing_lints.md +[Adding Lints]: adding_lints.md +[Common Tools]: common_tools_writing_lints.md - [Basics for hacking on Clippy](#basics-for-hacking-on-clippy) - [Get the Code](#get-the-code) @@ -125,7 +125,7 @@ We follow a rustc no merge-commit policy. See ## Common Abbreviations | Abbreviation | Meaning | -| ------------ | -------------------------------------- | +|--------------|----------------------------------------| | UB | Undefined Behavior | | FP | False Positive | | FN | False Negative | diff --git a/book/src/development/common_tools_writing_lints.md b/book/src/development/common_tools_writing_lints.md index f5aa06e4bf653..09171d86a2097 100644 --- a/book/src/development/common_tools_writing_lints.md +++ b/book/src/development/common_tools_writing_lints.md @@ -3,7 +3,7 @@ You may need following tooltips to catch up with common operations. - [Common tools for writing lints](#common-tools-for-writing-lints) - - [Retrieving the type of an expression](#retrieving-the-type-of-an-expression) + - [Retrieving the type of expression](#retrieving-the-type-of-expression) - [Checking if an expr is calling a specific method](#checking-if-an-expr-is-calling-a-specific-method) - [Checking for a specific type](#checking-for-a-specific-type) - [Checking if a type implements a specific trait](#checking-if-a-type-implements-a-specific-trait) @@ -16,7 +16,7 @@ Useful Rustc dev guide links: - [Type checking](https://rustc-dev-guide.rust-lang.org/type-checking.html) - [Ty module](https://rustc-dev-guide.rust-lang.org/ty.html) -## Retrieving the type of an expression +## Retrieving the type of expression Sometimes you may want to retrieve the type `Ty` of an expression `Expr`, for example to answer following questions: @@ -45,7 +45,7 @@ impl LateLintPass<'_> for MyStructLint { } ``` -Similarly in [`TypeckResults`][TypeckResults] methods, you have the +Similarly, in [`TypeckResults`][TypeckResults] methods, you have the [`pat_ty()`][pat_ty] method to retrieve a type from a pattern. Two noticeable items here: @@ -192,7 +192,7 @@ functions to deal with macros: - `span.from_expansion()`: detects if a span is from macro expansion or desugaring. Checking this is a common first step in a lint. - ```rust + ```rust,ignore if expr.span.from_expansion() { // just forget it return; @@ -203,11 +203,11 @@ functions to deal with macros: if so, which macro call expanded it. It is sometimes useful to check if the context of two spans are equal. - ```rust + ```rust,ignore // expands to `1 + 0`, but don't lint 1 + mac!() ``` - ```rust + ```rust,ignore if left.span.ctxt() != right.span.ctxt() { // the coder most likely cannot modify this expression return; @@ -246,7 +246,7 @@ functions to deal with macros: `macro_rules!` with `a == $b`, `$b` is expanded to some expression with a different context from `a`. - ```rust + ```rust,ignore macro_rules! m { ($a:expr, $b:expr) => { if $a.is_some() { diff --git a/book/src/development/infrastructure/book.md b/book/src/development/infrastructure/book.md index dbd624ecd7382..de5de4bebaa91 100644 --- a/book/src/development/infrastructure/book.md +++ b/book/src/development/infrastructure/book.md @@ -13,7 +13,7 @@ guide to Clippy that you're reading right now. The Clippy book is formatted with While not strictly necessary since the book source is simply Markdown text files, having mdBook locally will allow you to build, test and serve the book locally to view changes before you commit them to the repository. You likely -already have `cargo` installed, so the easiest option is to simply: +already have `cargo` installed, so the easiest option is to: ```shell cargo install mdbook @@ -26,7 +26,7 @@ instructions for other options. The book's [src](https://github.com/rust-lang/rust-clippy/tree/master/book/src) -directory contains all of the markdown files used to generate the book. If you +directory contains all the markdown files used to generate the book. If you want to see your changes in real time, you can use the mdBook `serve` command to run a web server locally that will automatically update changes as they are made. From the top level of your `rust-clippy` directory: diff --git a/book/src/development/infrastructure/changelog_update.md b/book/src/development/infrastructure/changelog_update.md index d1ac7237b5e35..df9b1bbe18f32 100644 --- a/book/src/development/infrastructure/changelog_update.md +++ b/book/src/development/infrastructure/changelog_update.md @@ -101,7 +101,7 @@ Look for the [`beta-accepted`] label and make sure to also include the PRs with that label in the changelog. If you can, remove the `beta-accepted` labels **after** the changelog PR was merged. -> _Note:_ Some of those PRs might even got backported to the previous `beta`. +> _Note:_ Some of those PRs might even get backported to the previous `beta`. > Those have to be included in the changelog of the _previous_ release. ### 4. Update `clippy::version` attributes diff --git a/book/src/development/infrastructure/release.md b/book/src/development/infrastructure/release.md index 0572281803e71..98fabf8e89aee 100644 --- a/book/src/development/infrastructure/release.md +++ b/book/src/development/infrastructure/release.md @@ -44,7 +44,7 @@ $ git push origin backport_remerge # This can be pushed to your fork ``` After this, open a PR to the master branch. In this PR, the commit hash of the -`HEAD` of the `beta` branch must exists. In addition to that, no files should be +`HEAD` of the `beta` branch must exist. In addition to that, no files should be changed by this PR. ## Update the `beta` branch diff --git a/book/src/development/infrastructure/sync.md b/book/src/development/infrastructure/sync.md index 02cfc11b55acb..e1fe92f95250d 100644 --- a/book/src/development/infrastructure/sync.md +++ b/book/src/development/infrastructure/sync.md @@ -19,8 +19,7 @@ to beta. For reference, the first sync following this cadence was performed the 2020-08-27. This process is described in detail in the following sections. For general -information about `subtree`s in the Rust repository see [Rust's -`CONTRIBUTING.md`][subtree]. +information about `subtree`s in the Rust repository see [the rustc-dev-guide][subtree]. ## Patching git-subtree to work with big repos @@ -47,7 +46,7 @@ sudo chown --reference=/usr/lib/git-core/git-subtree~ /usr/lib/git-core/git-subt > _Note:_ If you are a Debian user, `dash` is the shell used by default for > scripts instead of `sh`. This shell has a hardcoded recursion limit set to -> 1000. In order to make this process work, you need to force the script to run +> 1,000. In order to make this process work, you need to force the script to run > `bash` instead. You can do this by editing the first line of the `git-subtree` > script and changing `sh` to `bash`. @@ -71,10 +70,10 @@ $ git remote add clippy-local /path/to/rust-clippy ## Performing the sync from [`rust-lang/rust`] to Clippy -Here is a TL;DR version of the sync process (all of the following commands have +Here is a TL;DR version of the sync process (all the following commands have to be run inside the `rust` directory): -1. Clone the [`rust-lang/rust`] repository or make sure it is up to date. +1. Clone the [`rust-lang/rust`] repository or make sure it is up-to-date. 2. Checkout the commit from the latest available nightly. You can get it using `rustup check`. 3. Sync the changes to the rust-copy of Clippy to your Clippy fork: @@ -107,7 +106,7 @@ to be run inside the `rust` directory): ## Performing the sync from Clippy to [`rust-lang/rust`] -All of the following commands have to be run inside the `rust` directory. +All the following commands have to be run inside the `rust` directory. 1. Make sure you have checked out the latest `master` of `rust-lang/rust`. 2. Sync the `rust-lang/rust-clippy` master to the rust-copy of Clippy: @@ -118,5 +117,5 @@ All of the following commands have to be run inside the `rust` directory. 3. Open a PR to [`rust-lang/rust`] [gitgitgadget-pr]: https://github.com/gitgitgadget/git/pull/493 -[subtree]: https://rustc-dev-guide.rust-lang.org/contributing.html#external-dependencies-subtree +[subtree]: https://rustc-dev-guide.rust-lang.org/external-repos.html#external-dependencies-subtree [`rust-lang/rust`]: https://github.com/rust-lang/rust diff --git a/book/src/development/proposals/README.md b/book/src/development/proposals/README.md index 78fe34ebf8faf..059c22ce1ce8c 100644 --- a/book/src/development/proposals/README.md +++ b/book/src/development/proposals/README.md @@ -6,6 +6,6 @@ or around Clippy in the long run. Besides adding more and more lints and improve the lints that Clippy already has, Clippy is also interested in making the experience of its users, developers and maintainers better over time. Projects that address bigger picture things -like this usually take more time and it is useful to have a proposal for those +like this usually take more time, and it is useful to have a proposal for those first. This is the place where such proposals are collected, so that we can refer to them when working on them. diff --git a/book/src/development/proposals/roadmap-2021.md b/book/src/development/proposals/roadmap-2021.md index fe8b080f56f2b..4406616bbb613 100644 --- a/book/src/development/proposals/roadmap-2021.md +++ b/book/src/development/proposals/roadmap-2021.md @@ -52,8 +52,8 @@ In the following, plans to improve the usability are covered. #### No Output After `cargo check` -Currently when `cargo clippy` is run after `cargo check`, it does not produce -any output. This is especially problematic since `rust-analyzer` is on the rise +Currently, when `cargo clippy` is run after `cargo check`, it does not produce +any output. This is especially problematic since `rust-analyzer` is on the rise, and it uses `cargo check` for checking code. A fix is already implemented, but it still has to be pushed over the finish line. This also includes the stabilization of the `cargo clippy --fix` command or the support of multi-span @@ -221,7 +221,7 @@ regarding the user facing issues. Rust's roadmap process was established by [RFC 1728] in 2016. Since then every year a roadmap was published, that defined the bigger plans for the coming -years. This years roadmap can be found [here][Rust Roadmap 2021]. +years. This year roadmap can be found [here][Rust Roadmap 2021]. [RFC 1728]: https://rust-lang.github.io/rfcs/1728-north-star.html diff --git a/book/src/development/proposals/syntax-tree-patterns.md b/book/src/development/proposals/syntax-tree-patterns.md index ea4978011b19c..36d722609f4ac 100644 --- a/book/src/development/proposals/syntax-tree-patterns.md +++ b/book/src/development/proposals/syntax-tree-patterns.md @@ -16,7 +16,7 @@ lints. For non-trivial lints, it often requires nested pattern matching of AST / HIR nodes. For example, testing that an expression is a boolean literal requires the following checks: -```rust +```rust,ignore if let ast::ExprKind::Lit(lit) = &expr.node { if let ast::LitKind::Bool(_) = &lit.node { ... @@ -28,7 +28,7 @@ Writing this kind of matching code quickly becomes a complex task and the resulting code is often hard to comprehend. The code below shows a simplified version of the pattern matching required by the `collapsible_if` lint: -```rust +```rust,ignore // simplified version of the collapsible_if lint if let ast::ExprKind::If(check, then, None) = &expr.node { if then.stmts.len() == 1 { @@ -111,7 +111,7 @@ expressions that are boolean literals with value `false`. The pattern can then be used to implement lints in the following way: -```rust +```rust,ignore ... impl EarlyLintPass for MyAwesomeLint { @@ -346,7 +346,7 @@ pattern!{ one could get references to the nodes that matched the subpatterns in the following way: -```rust +```rust,ignore ... fn check_expr(expr: &syntax::ast::Expr) { if let Some(result) = my_pattern(expr) { @@ -372,7 +372,7 @@ matches arrays that consist of any number of literal expressions. Because those expressions are named `foo`, the result struct contains a `foo` attribute which is a vector of expressions: -```rust +```rust,ignore ... if let Some(result) = my_pattern_seq(expr) { result.foo // type: Vec<&syntax::ast::Expr> @@ -394,7 +394,7 @@ In the pattern above, the `bar` name is only defined if the pattern matches a boolean literal. If it matches an integer literal, the name isn't set. To account for this, the result struct's `bar` attribute is an option type: -```rust +```rust,ignore ... if let Some(result) = my_pattern_alt(expr) { result.bar // type: Option<&bool> @@ -404,7 +404,7 @@ if let Some(result) = my_pattern_alt(expr) { It's also possible to use a name in multiple alternation branches if they have compatible types: -```rust +```rust,ignore pattern!{ // matches if expression is a boolean or integer literal my_pattern_mult: Expr = @@ -519,7 +519,7 @@ The `Alt`, `Seq` and `Opt` structs look like these: > Note: The current implementation can be found > [here](https://github.com/fkohlgrueber/pattern-matching/blob/dfb3bc9fbab69cec7c91e72564a63ebaa2ede638/pattern-match/src/matchers.rs#L35-L60). -```rust +```rust,ignore pub enum Alt { Any, Elmt(Box), @@ -580,7 +580,7 @@ implementations is the `IsMatch` trait. It defines how to match *PatternTree* nodes against specific syntax tree nodes. A simplified implementation of the `IsMatch` trait is shown below: -```rust +```rust,ignore pub trait IsMatch { fn is_match(&self, other: &'o O) -> bool; } @@ -619,7 +619,7 @@ approach (matching against the coarse pattern first and checking for additional properties later) might be slower than the current practice of checking for structure and additional properties in one pass. For example, the following lint -```rust +```rust,ignore pattern!{ pat_if_without_else: Expr = If( @@ -644,7 +644,7 @@ first matches against the pattern and then checks that the `then` block doesn't start with a comment. Using clippy's current approach, it's possible to check for these conditions earlier: -```rust +```rust,ignore fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) { if_chain! { if let ast::ExprKind::If(ref check, ref then, None) = expr.node; @@ -708,7 +708,7 @@ is similar to actual Rust syntax (probably like the `quote!` macro). For example, a pattern that matches `if` expressions that have `false` in their condition could look like this: -```rust +```rust,ignore if false { #[*] } @@ -742,7 +742,7 @@ affects the structure of the resulting AST. `1 + 0 + 0` is parsed as `(1 + 0) + Another example of a problem would be named submatches. Take a look at this pattern: -```rust +```rust,ignore fn test() { 1 #foo } @@ -862,7 +862,7 @@ op b` and recommends changing it to `a op= b` requires that both occurrences of `a` are the same. Using `=#...` as syntax for backreferences, the lint could be implemented like this: -```rust +```rust,ignore pattern!{ assign_op_pattern: Expr = Assign(_#target, Binary(_, =#target, _) diff --git a/book/src/development/type_checking.md b/book/src/development/type_checking.md new file mode 100644 index 0000000000000..5ce434b99a1a6 --- /dev/null +++ b/book/src/development/type_checking.md @@ -0,0 +1,144 @@ +# Type Checking + +When we work on a new lint or improve an existing lint, we might want +to retrieve the type `Ty` of an expression `Expr` for a variety of +reasons. This can be achieved by utilizing the [`LateContext`][LateContext] +that is available for [`LateLintPass`][LateLintPass]. + +## `LateContext` and `TypeckResults` + +The lint context [`LateContext`][LateContext] and [`TypeckResults`][TypeckResults] +(returned by `LateContext::typeck_results`) are the two most useful data structures +in `LateLintPass`. They allow us to jump to type definitions and other compilation +stages such as HIR. + +> Note: `LateContext.typeck_results`'s return value is [`TypeckResults`][TypeckResults] +> and is created in the type checking step, it includes useful information such as types of +> expressions, ways to resolve methods and so on. + +`TypeckResults` contains useful methods such as [`expr_ty`][expr_ty], +which gives us access to the underlying structure [`Ty`][Ty] of a given expression. + +```rust +pub fn expr_ty(&self, expr: &Expr<'_>) -> Ty<'tcx> +``` + +As a side note, besides `expr_ty`, [`TypeckResults`][TypeckResults] contains a +[`pat_ty()`][pat_ty] method that is useful for retrieving a type from a pattern. + +## `Ty` + +`Ty` struct contains the type information of an expression. +Let's take a look at `rustc_middle`'s [`Ty`][Ty] struct to examine this struct: + +```rust +pub struct Ty<'tcx>(Interned<'tcx, WithStableHash>>); +``` + +At a first glance, this struct looks quite esoteric. But at a closer look, +we will see that this struct contains many useful methods for type checking. + +For instance, [`is_char`][is_char] checks if the given `Ty` struct corresponds +to the primitive character type. + +### `is_*` Usage + +In some scenarios, all we need to do is check if the `Ty` of an expression +is a specific type, such as `char` type, so we could write the following: + +```rust +impl LateLintPass<'_> for MyStructLint { + fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { + // Get type of `expr` + let ty = cx.typeck_results().expr_ty(expr); + + // Check if the `Ty` of this expression is of character type + if ty.is_char() { + println!("Our expression is a char!"); + } + } +} +``` + +Furthermore, if we examine the [source code][is_char_source] for `is_char`, +we find something very interesting: + +```rust +#[inline] +pub fn is_char(self) -> bool { + matches!(self.kind(), Char) +} +``` + +Indeed, we just discovered `Ty`'s [`kind` method][kind], which provides us +with [`TyKind`][TyKind] of a `Ty`. + +## `TyKind` + +`TyKind` defines the kinds of types in Rust's type system. +Peeking into [`TyKind` documentation][TyKind], we will see that it is an +enum of 27 variants, including items such as `Bool`, `Int`, `Ref`, etc. + +### `kind` Usage + +The `TyKind` of `Ty` can be returned by calling [`Ty.kind` method][kind]. +We often use this method to perform pattern matching in Clippy. + +For instance, if we want to check for a `struct`, we could examine if the +`ty.kind` corresponds to an [`Adt`][Adt] (algebraic data type) and if its +[`AdtDef`][AdtDef] is a struct: + +```rust +impl LateLintPass<'_> for MyStructLint { + fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { + // Get type of `expr` + let ty = cx.typeck_results().expr_ty(expr); + // Match its kind to enter the type + match ty.kind { + ty::Adt(adt_def, _) if adt_def.is_struct() => println!("Our `expr` is a struct!"), + _ => () + } + } +} +``` + +## `hir::Ty` and `ty::Ty` + +We've been talking about [`ty::Ty`][middle_ty] this whole time without addressing [`hir::Ty`][hir_ty], but the latter +is also important to understand. + +`hir::Ty` would represent *what* an user wrote, while `ty::Ty` would understand the meaning of it (because it has more +information). + +**Example: `fn foo(x: u32) -> u32 { x }`** + +Here the HIR sees the types without "thinking" about them, it knows that the function takes an `u32` and returns +an `u32`. But at the `ty::Ty` level the compiler understands that they're the same type, in-depth lifetimes, etc... + +you can use the [`hir_ty_to_ty`][hir_ty_to_ty] function to convert from a `hir::Ty` to a `ty::Ty` + +## Useful Links + +Below are some useful links to further explore the concepts covered +in this chapter: + +- [Stages of compilation](https://rustc-dev-guide.rust-lang.org/compiler-src.html#the-main-stages-of-compilation) +- [Diagnostic items](https://rustc-dev-guide.rust-lang.org/diagnostics/diagnostic-items.html) +- [Type checking](https://rustc-dev-guide.rust-lang.org/type-checking.html) +- [Ty module](https://rustc-dev-guide.rust-lang.org/ty.html) + +[Adt]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/enum.TyKind.html#variant.Adt +[AdtDef]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/adt/struct.AdtDef.html +[expr_ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TypeckResults.html#method.expr_ty +[is_char]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.Ty.html#method.is_char +[is_char_source]: https://doc.rust-lang.org/nightly/nightly-rustc/src/rustc_middle/ty/sty.rs.html#1831-1834 +[kind]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.Ty.html#method.kind +[LateContext]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/struct.LateContext.html +[LateLintPass]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/trait.LateLintPass.html +[pat_ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/context/struct.TypeckResults.html#method.pat_ty +[Ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.Ty.html +[TyKind]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/enum.TyKind.html +[TypeckResults]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TypeckResults.html +[middle_ty]: https://doc.rust-lang.org/beta/nightly-rustc/rustc_middle/ty/struct.Ty.html +[hir_ty]: https://doc.rust-lang.org/beta/nightly-rustc/rustc_hir/struct.Ty.html +[hir_ty_to_ty]: https://doc.rust-lang.org/beta/nightly-rustc/rustc_hir_analysis/fn.hir_ty_to_ty.html diff --git a/book/src/installation.md b/book/src/installation.md index cce888b17d4d3..d54fff9deba18 100644 --- a/book/src/installation.md +++ b/book/src/installation.md @@ -17,8 +17,8 @@ $ rustup component add clippy [--toolchain=] ## From Source -Take a look at the [Basics] chapter in the Clippy developer guide to find step -by step instructions on how to build and install Clippy from source. +Take a look at the [Basics] chapter in the Clippy developer guide to find step-by-step +instructions on how to build and install Clippy from source. [Basics]: development/basics.md#install-from-source [Usage]: usage.md diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md index 9ed6627b74130..78e1a55cff32e 100644 --- a/book/src/lint_configuration.md +++ b/book/src/lint_configuration.md @@ -54,6 +54,7 @@ Please use that command to update the file and do not edit it by hand. | [allow-mixed-uninlined-format-args](#allow-mixed-uninlined-format-args) | `true` | | [suppress-restriction-lint-in-const](#suppress-restriction-lint-in-const) | `false` | | [missing-docs-in-crate-items](#missing-docs-in-crate-items) | `false` | +| [future-size-threshold](#future-size-threshold) | `16384` | ### arithmetic-side-effects-allowed Suppress checking of the passed type names in all types of operations. @@ -130,6 +131,7 @@ Suppress lints whenever the suggested change would cause breakage for other crat * [option_option](https://rust-lang.github.io/rust-clippy/master/index.html#option_option) * [linkedlist](https://rust-lang.github.io/rust-clippy/master/index.html#linkedlist) * [rc_mutex](https://rust-lang.github.io/rust-clippy/master/index.html#rc_mutex) +* [unnecessary_box_returns](https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_box_returns) ### msrv @@ -193,7 +195,7 @@ The maximum cognitive complexity a function can have ### disallowed-names The list of disallowed names to lint about. NB: `bar` is not here since it has legitimate uses. The value `".."` can be used as part of the list to indicate, that the configured values should be appended to the -default configuration of Clippy. By default any configuration will replace the default value. +default configuration of Clippy. By default, any configuration will replace the default value. **Default Value:** `["foo", "baz", "quux"]` (`Vec`) @@ -203,7 +205,7 @@ default configuration of Clippy. By default any configuration will replace the d ### doc-valid-idents The list of words this lint should not consider as identifiers needing ticks. The value `".."` can be used as part of the list to indicate, that the configured values should be appended to the -default configuration of Clippy. By default any configuraction will replace the default value. For example: +default configuration of Clippy. By default, any configuration will replace the default value. For example: * `doc-valid-idents = ["ClipPy"]` would replace the default list with `["ClipPy"]`. * `doc-valid-idents = ["ClipPy", ".."]` would append `ClipPy` to the default list. @@ -413,7 +415,7 @@ For internal testing only, ignores the current `publish` settings in the Cargo m Enforce the named macros always use the braces specified. A `MacroMatcher` can be added like so `{ name = "macro_name", brace = "(" }`. If the macro -is could be used with a full path two `MacroMatcher`s have to be added one with the full path +could be used with a full path two `MacroMatcher`s have to be added one with the full path `crate_name::macro_name` and one with just the macro name. **Default Value:** `[]` (`Vec`) @@ -447,7 +449,7 @@ Whether to apply the raw pointer heuristic to determine if a type is `Send`. ### max-suggested-slice-pattern-length When Clippy suggests using a slice pattern, this is the maximum number of elements allowed in -the slice pattern that is suggested. If more elements would be necessary, the lint is suppressed. +the slice pattern that is suggested. If more elements are necessary, the lint is suppressed. For example, `[_, _, _, e, ..]` is a slice pattern with 4 elements. **Default Value:** `3` (`u64`) @@ -551,4 +553,12 @@ crate. For example, `pub(crate)` items. * [missing_docs_in_private_items](https://rust-lang.github.io/rust-clippy/master/index.html#missing_docs_in_private_items) +### future-size-threshold +The maximum byte size a `Future` can have, before it triggers the `clippy::large_futures` lint + +**Default Value:** `16384` (`u64`) + +* [large_futures](https://rust-lang.github.io/rust-clippy/master/index.html#large_futures) + + diff --git a/book/src/lints.md b/book/src/lints.md index 35e30960b56c6..442dc63914e9d 100644 --- a/book/src/lints.md +++ b/book/src/lints.md @@ -17,7 +17,7 @@ The different lint groups were defined in the [Clippy 1.0 RFC]. The `clippy::correctness` group is the only lint group in Clippy which lints are deny-by-default and abort the compilation when triggered. This is for good reason: If you see a `correctness` lint, it means that your code is outright -wrong or useless and you should try to fix it. +wrong or useless, and you should try to fix it. Lints in this category are carefully picked and should be free of false positives. So just `#[allow]`ing those lints is not recommended. @@ -41,7 +41,7 @@ simplify your code. It mostly focuses on code that can be written in a shorter and more readable way, while preserving the semantics. If you should see a complexity lint, it usually means that you can remove or -replace some code and it is recommended to do so. However, if you need the more +replace some code, and it is recommended to do so. However, if you need the more complex code for some expressiveness reason, it is recommended to allow complexity lints on a case-by-case basis. @@ -50,9 +50,9 @@ complexity lints on a case-by-case basis. The `clippy::perf` group gives you suggestions on how you can increase the performance of your code. Those lints are mostly about code that the compiler can't trivially optimize, but has to be written in a slightly different way to -make the optimizer's job easier. +make the optimizer job easier. -Perf lints are usually easy to apply and it is recommended to do so. +Perf lints are usually easy to apply, and it is recommended to do so. ## Style @@ -91,7 +91,7 @@ and your use case. Lints from this group will restrict you in some way. If you enable a restriction lint for your crate it is recommended to also fix code that this lint triggers -on. However, those lints are really strict by design and you might want to +on. However, those lints are really strict by design, and you might want to `#[allow]` them in some special cases, with a comment justifying that. ## Cargo diff --git a/book/src/usage.md b/book/src/usage.md index 61a90445d753c..32084a9199b73 100644 --- a/book/src/usage.md +++ b/book/src/usage.md @@ -19,7 +19,7 @@ cargo clippy ### Lint configuration The above command will run the default set of lints, which are included in the -lint group `clippy::all`. You might want to use even more lints or you might not +lint group `clippy::all`. You might want to use even more lints, or you may not agree with every Clippy lint, and for that there are ways to configure lint levels. @@ -98,7 +98,7 @@ other of Clippy's lint groups. You can configure lint levels in source code the same way you can configure `rustc` lints: -```rust +```rust,ignore #![allow(clippy::style)] #[warn(clippy::double_neg)] diff --git a/clippy_dev/src/lib.rs b/clippy_dev/src/lib.rs index 8871873c6612f..3a8b070d73516 100644 --- a/clippy_dev/src/lib.rs +++ b/clippy_dev/src/lib.rs @@ -1,3 +1,4 @@ +#![feature(lazy_cell)] #![feature(let_chains)] #![feature(rustc_private)] #![cfg_attr(feature = "deny-warnings", deny(warnings))] diff --git a/clippy_dev/src/new_lint.rs b/clippy_dev/src/new_lint.rs index 420214d9256d8..13a2770342781 100644 --- a/clippy_dev/src/new_lint.rs +++ b/clippy_dev/src/new_lint.rs @@ -369,9 +369,7 @@ fn create_lint_for_ty(lint: &LintData<'_>, enable_msrv: bool, ty: &str) -> io::R }} todo!(); }} - "#, - context_import = context_import, - name_upper = name_upper, + "# ); } else { let _: fmt::Result = writedoc!( @@ -385,9 +383,7 @@ fn create_lint_for_ty(lint: &LintData<'_>, enable_msrv: bool, ty: &str) -> io::R pub(super) fn check(cx: &{context_import}) {{ todo!(); }} - "#, - context_import = context_import, - name_upper = name_upper, + "# ); } diff --git a/clippy_dev/src/update_lints.rs b/clippy_dev/src/update_lints.rs index 779e4d0e1e308..95222a9acdfc5 100644 --- a/clippy_dev/src/update_lints.rs +++ b/clippy_dev/src/update_lints.rs @@ -537,17 +537,13 @@ fn declare_deprecated(name: &str, path: &Path, reason: &str) -> io::Result<()> { /// Nothing. This lint has been deprecated. /// /// ### Deprecation reason - /// {} - #[clippy::version = \"{}\"] - pub {}, - \"{}\" + /// {deprecation_reason} + #[clippy::version = \"{version}\"] + pub {name}, + \"{reason}\" }} - ", - deprecation_reason, - version, - name, - reason, + " ) } diff --git a/clippy_lints/Cargo.toml b/clippy_lints/Cargo.toml index 0b3846c13163d..18e8bf77225cf 100644 --- a/clippy_lints/Cargo.toml +++ b/clippy_lints/Cargo.toml @@ -9,6 +9,7 @@ keywords = ["clippy", "lint", "plugin"] edition = "2021" [dependencies] +arrayvec = { version = "0.7", default-features = false } cargo_metadata = "0.15.3" clippy_utils = { path = "../clippy_utils" } declare_clippy_lint = { path = "../declare_clippy_lint" } diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs index 29fde9336c0b9..455f0df7cd0ad 100644 --- a/clippy_lints/src/booleans.rs +++ b/clippy_lints/src/booleans.rs @@ -7,7 +7,7 @@ use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_expr, FnKind, Visitor}; use rustc_hir::{BinOpKind, Body, Expr, ExprKind, FnDecl, UnOp}; -use rustc_lint::{LateContext, LateLintPass}; +use rustc_lint::{LateContext, LateLintPass, Level}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::def_id::LocalDefId; use rustc_span::source_map::Span; @@ -430,23 +430,25 @@ impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> { } } let nonminimal_bool_lint = |suggestions: Vec<_>| { - span_lint_hir_and_then( - self.cx, - NONMINIMAL_BOOL, - e.hir_id, - e.span, - "this boolean expression can be simplified", - |diag| { - diag.span_suggestions( - e.span, - "try", - suggestions.into_iter(), - // nonminimal_bool can produce minimal but - // not human readable expressions (#3141) - Applicability::Unspecified, - ); - }, - ); + if self.cx.tcx.lint_level_at_node(NONMINIMAL_BOOL, e.hir_id).0 != Level::Allow { + span_lint_hir_and_then( + self.cx, + NONMINIMAL_BOOL, + e.hir_id, + e.span, + "this boolean expression can be simplified", + |diag| { + diag.span_suggestions( + e.span, + "try", + suggestions.into_iter(), + // nonminimal_bool can produce minimal but + // not human readable expressions (#3141) + Applicability::Unspecified, + ); + }, + ); + } }; if improvements.is_empty() { let mut visitor = NotSimplificationVisitor { cx: self.cx }; @@ -498,6 +500,7 @@ impl<'a, 'tcx> Visitor<'tcx> for NotSimplificationVisitor<'a, 'tcx> { if let ExprKind::Unary(UnOp::Not, inner) = &expr.kind && !inner.span.from_expansion() && let Some(suggestion) = simplify_not(self.cx, inner) + && self.cx.tcx.lint_level_at_node(NONMINIMAL_BOOL, expr.hir_id).0 != Level::Allow { span_lint_and_sugg( self.cx, diff --git a/clippy_lints/src/casts/cast_possible_truncation.rs b/clippy_lints/src/casts/cast_possible_truncation.rs index 823970e35abbd..95c2ecbf791b5 100644 --- a/clippy_lints/src/casts/cast_possible_truncation.rs +++ b/clippy_lints/src/casts/cast_possible_truncation.rs @@ -2,8 +2,9 @@ use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; use clippy_utils::expr_or_init; use clippy_utils::source::snippet; +use clippy_utils::sugg::Sugg; use clippy_utils::ty::{get_discriminant_value, is_isize_or_usize}; -use rustc_errors::{Applicability, SuggestionStyle}; +use rustc_errors::{Applicability, Diagnostic, SuggestionStyle}; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::LateContext; @@ -163,19 +164,34 @@ pub(super) fn check( _ => return, }; - let name_of_cast_from = snippet(cx, cast_expr.span, ".."); - let cast_to_snip = snippet(cx, cast_to_span, ".."); - let suggestion = format!("{cast_to_snip}::try_from({name_of_cast_from})"); - span_lint_and_then(cx, CAST_POSSIBLE_TRUNCATION, expr.span, &msg, |diag| { diag.help("if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ..."); - diag.span_suggestion_with_style( - expr.span, - "... or use `try_from` and handle the error accordingly", - suggestion, - Applicability::Unspecified, - // always show the suggestion in a separate line - SuggestionStyle::ShowAlways, - ); + if !cast_from.is_floating_point() { + offer_suggestion(cx, expr, cast_expr, cast_to_span, diag); + } }); } + +fn offer_suggestion( + cx: &LateContext<'_>, + expr: &Expr<'_>, + cast_expr: &Expr<'_>, + cast_to_span: Span, + diag: &mut Diagnostic, +) { + let cast_to_snip = snippet(cx, cast_to_span, ".."); + let suggestion = if cast_to_snip == "_" { + format!("{}.try_into()", Sugg::hir(cx, cast_expr, "..").maybe_par()) + } else { + format!("{cast_to_snip}::try_from({})", Sugg::hir(cx, cast_expr, "..")) + }; + + diag.span_suggestion_with_style( + expr.span, + "... or use `try_from` and handle the error accordingly", + suggestion, + Applicability::Unspecified, + // always show the suggestion in a separate line + SuggestionStyle::ShowAlways, + ); +} diff --git a/clippy_lints/src/collection_is_never_read.rs b/clippy_lints/src/collection_is_never_read.rs index 10f2bef268a24..5e2eb5789f627 100644 --- a/clippy_lints/src/collection_is_never_read.rs +++ b/clippy_lints/src/collection_is_never_read.rs @@ -1,9 +1,9 @@ use clippy_utils::diagnostics::span_lint; -use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item}; use clippy_utils::visitors::for_each_expr_with_closures; use clippy_utils::{get_enclosing_block, get_parent_node, path_to_local_id}; use core::ops::ControlFlow; -use rustc_hir::{Block, ExprKind, HirId, Local, Node, PatKind}; +use rustc_hir::{Block, ExprKind, HirId, LangItem, Local, Node, PatKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::symbol::sym; @@ -44,7 +44,8 @@ declare_clippy_lint! { } declare_lint_pass!(CollectionIsNeverRead => [COLLECTION_IS_NEVER_READ]); -static COLLECTIONS: [Symbol; 10] = [ +// Add `String` here when it is added to diagnostic items +static COLLECTIONS: [Symbol; 9] = [ sym::BTreeMap, sym::BTreeSet, sym::BinaryHeap, @@ -52,7 +53,6 @@ static COLLECTIONS: [Symbol; 10] = [ sym::HashSet, sym::LinkedList, sym::Option, - sym::String, sym::Vec, sym::VecDeque, ]; @@ -60,8 +60,7 @@ static COLLECTIONS: [Symbol; 10] = [ impl<'tcx> LateLintPass<'tcx> for CollectionIsNeverRead { fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'tcx>) { // Look for local variables whose type is a container. Search surrounding bock for read access. - let ty = cx.typeck_results().pat_ty(local.pat); - if COLLECTIONS.iter().any(|&sym| is_type_diagnostic_item(cx, ty, sym)) + if match_acceptable_type(cx, local, &COLLECTIONS) && let PatKind::Binding(_, local_id, _, _) = local.pat.kind && let Some(enclosing_block) = get_enclosing_block(cx, local.hir_id) && has_no_read_access(cx, local_id, enclosing_block) @@ -71,6 +70,13 @@ impl<'tcx> LateLintPass<'tcx> for CollectionIsNeverRead { } } +fn match_acceptable_type(cx: &LateContext<'_>, local: &Local<'_>, collections: &[rustc_span::Symbol]) -> bool { + let ty = cx.typeck_results().pat_ty(local.pat); + collections.iter().any(|&sym| is_type_diagnostic_item(cx, ty, sym)) + // String type is a lang item but not a diagnostic item for now so we need a separate check + || is_type_lang_item(cx, ty, LangItem::String) +} + fn has_no_read_access<'tcx>(cx: &LateContext<'tcx>, id: HirId, block: &'tcx Block<'tcx>) -> bool { let mut has_access = false; let mut has_read_access = false; @@ -95,9 +101,9 @@ fn has_no_read_access<'tcx>(cx: &LateContext<'tcx>, id: HirId, block: &'tcx Bloc return ControlFlow::Continue(()); } - // Method call on `id` in a statement ignores any return value, so it's not a read access: + // Look for method call with receiver `id`. It might be a non-read access: // - // id.foo(...); // Not reading `id`. + // id.foo(args) // // Only assuming this for "official" methods defined on the type. For methods defined in extension // traits (identified as local, based on the orphan rule), pessimistically assume that they might @@ -105,11 +111,24 @@ fn has_no_read_access<'tcx>(cx: &LateContext<'tcx>, id: HirId, block: &'tcx Bloc if let Some(Node::Expr(parent)) = get_parent_node(cx.tcx, expr.hir_id) && let ExprKind::MethodCall(_, receiver, _, _) = parent.kind && path_to_local_id(receiver, id) - && let Some(Node::Stmt(..)) = get_parent_node(cx.tcx, parent.hir_id) && let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(parent.hir_id) && !method_def_id.is_local() { - return ControlFlow::Continue(()); + // The method call is a statement, so the return value is not used. That's not a read access: + // + // id.foo(args); + if let Some(Node::Stmt(..)) = get_parent_node(cx.tcx, parent.hir_id) { + return ControlFlow::Continue(()); + } + + // The method call is not a statement, so its return value is used somehow but its type is the + // unit type, so this is not a real read access. Examples: + // + // let y = x.clear(); + // println!("{:?}", x.clear()); + if cx.typeck_results().expr_ty(parent).is_unit() { + return ControlFlow::Continue(()); + } } // Any other access to `id` is a read access. Stop searching. diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 8ca91301472e6..f24dab6278095 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -218,6 +218,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::iter_not_returning_iterator::ITER_NOT_RETURNING_ITERATOR_INFO, crate::large_const_arrays::LARGE_CONST_ARRAYS_INFO, crate::large_enum_variant::LARGE_ENUM_VARIANT_INFO, + crate::large_futures::LARGE_FUTURES_INFO, crate::large_include_file::LARGE_INCLUDE_FILE_INFO, crate::large_stack_arrays::LARGE_STACK_ARRAYS_INFO, crate::len_zero::COMPARISON_TO_EMPTY_INFO, @@ -231,6 +232,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::let_with_type_underscore::LET_WITH_TYPE_UNDERSCORE_INFO, crate::lifetimes::EXTRA_UNUSED_LIFETIMES_INFO, crate::lifetimes::NEEDLESS_LIFETIMES_INFO, + crate::lines_filter_map_ok::LINES_FILTER_MAP_OK_INFO, crate::literal_representation::DECIMAL_LITERAL_REPRESENTATION_INFO, crate::literal_representation::INCONSISTENT_DIGIT_GROUPING_INFO, crate::literal_representation::LARGE_DIGIT_GROUPS_INFO, @@ -267,6 +269,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE_INFO, crate::manual_rem_euclid::MANUAL_REM_EUCLID_INFO, crate::manual_retain::MANUAL_RETAIN_INFO, + crate::manual_slice_size_calculation::MANUAL_SLICE_SIZE_CALCULATION_INFO, crate::manual_string_new::MANUAL_STRING_NEW_INFO, crate::manual_strip::MANUAL_STRIP_INFO, crate::map_unit_fn::OPTION_MAP_UNIT_FN_INFO, @@ -307,6 +310,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::methods::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS_INFO, crate::methods::CHARS_LAST_CMP_INFO, crate::methods::CHARS_NEXT_CMP_INFO, + crate::methods::CLEAR_WITH_DRAIN_INFO, crate::methods::CLONED_INSTEAD_OF_COPIED_INFO, crate::methods::CLONE_DOUBLE_REF_INFO, crate::methods::CLONE_ON_COPY_INFO, @@ -565,6 +569,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::strings::STR_TO_STRING_INFO, crate::strings::TRIM_SPLIT_WHITESPACE_INFO, crate::strlen_on_c_strings::STRLEN_ON_C_STRINGS_INFO, + crate::suspicious_doc_comments::SUSPICIOUS_DOC_COMMENTS_INFO, crate::suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS_INFO, crate::suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL_INFO, crate::suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL_INFO, @@ -574,6 +579,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::swap_ptr_to_ref::SWAP_PTR_TO_REF_INFO, crate::tabs_in_doc_comments::TABS_IN_DOC_COMMENTS_INFO, crate::temporary_assignment::TEMPORARY_ASSIGNMENT_INFO, + crate::tests_outside_test_module::TESTS_OUTSIDE_TEST_MODULE_INFO, crate::to_digit_is_some::TO_DIGIT_IS_SOME_INFO, crate::trailing_empty_array::TRAILING_EMPTY_ARRAY_INFO, crate::trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS_INFO, @@ -616,6 +622,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::unit_types::UNIT_CMP_INFO, crate::unnamed_address::FN_ADDRESS_COMPARISONS_INFO, crate::unnamed_address::VTABLE_ADDRESS_COMPARISONS_INFO, + crate::unnecessary_box_returns::UNNECESSARY_BOX_RETURNS_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, diff --git a/clippy_lints/src/disallowed_script_idents.rs b/clippy_lints/src/disallowed_script_idents.rs index 084190f00132c..c9fad98e43730 100644 --- a/clippy_lints/src/disallowed_script_idents.rs +++ b/clippy_lints/src/disallowed_script_idents.rs @@ -32,7 +32,7 @@ declare_clippy_lint! { /// ### Example /// ```rust /// // Assuming that `clippy.toml` contains the following line: - /// // allowed-locales = ["Latin", "Cyrillic"] + /// // allowed-scripts = ["Latin", "Cyrillic"] /// let counter = 10; // OK, latin is allowed. /// let счётчик = 10; // OK, cyrillic is allowed. /// let zähler = 10; // OK, it's still latin. diff --git a/clippy_lints/src/explicit_write.rs b/clippy_lints/src/explicit_write.rs index c0ea6f338a230..315df6c714ffc 100644 --- a/clippy_lints/src/explicit_write.rs +++ b/clippy_lints/src/explicit_write.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::macros::FormatArgsExpn; +use clippy_utils::macros::{find_format_args, format_args_inputs_span}; use clippy_utils::source::snippet_with_applicability; use clippy_utils::{is_expn_of, match_function_call, paths}; use if_chain::if_chain; @@ -8,7 +8,7 @@ use rustc_hir::def::Res; use rustc_hir::{BindingAnnotation, Block, BlockCheckMode, Expr, ExprKind, Node, PatKind, QPath, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::sym; +use rustc_span::{sym, ExpnId}; declare_clippy_lint! { /// ### What it does @@ -43,23 +43,22 @@ declare_lint_pass!(ExplicitWrite => [EXPLICIT_WRITE]); impl<'tcx> LateLintPass<'tcx> for ExplicitWrite { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if_chain! { - // match call to unwrap - if let ExprKind::MethodCall(unwrap_fun, write_call, [], _) = expr.kind; - if unwrap_fun.ident.name == sym::unwrap; + // match call to unwrap + if let ExprKind::MethodCall(unwrap_fun, write_call, [], _) = expr.kind + && unwrap_fun.ident.name == sym::unwrap // match call to write_fmt - if let ExprKind::MethodCall(write_fun, write_recv, [write_arg], _) = look_in_block(cx, &write_call.kind); - if write_fun.ident.name == sym!(write_fmt); + && let ExprKind::MethodCall(write_fun, write_recv, [write_arg], _) = look_in_block(cx, &write_call.kind) + && write_fun.ident.name == sym!(write_fmt) // match calls to std::io::stdout() / std::io::stderr () - if let Some(dest_name) = if match_function_call(cx, write_recv, &paths::STDOUT).is_some() { + && let Some(dest_name) = if match_function_call(cx, write_recv, &paths::STDOUT).is_some() { Some("stdout") } else if match_function_call(cx, write_recv, &paths::STDERR).is_some() { Some("stderr") } else { None - }; - if let Some(format_args) = FormatArgsExpn::parse(cx, write_arg); - then { + } + { + find_format_args(cx, write_arg, ExpnId::root(), |format_args| { let calling_macro = // ordering is important here, since `writeln!` uses `write!` internally if is_expn_of(write_call.span, "writeln").is_some() { @@ -92,7 +91,7 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitWrite { let mut applicability = Applicability::MachineApplicable; let inputs_snippet = snippet_with_applicability( cx, - format_args.inputs_span(), + format_args_inputs_span(format_args), "..", &mut applicability, ); @@ -104,8 +103,8 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitWrite { "try this", format!("{prefix}{sugg_mac}!({inputs_snippet})"), applicability, - ) - } + ); + }); } } } diff --git a/clippy_lints/src/extra_unused_type_parameters.rs b/clippy_lints/src/extra_unused_type_parameters.rs index 20565e1d232ee..eeb4de8b58f48 100644 --- a/clippy_lints/src/extra_unused_type_parameters.rs +++ b/clippy_lints/src/extra_unused_type_parameters.rs @@ -1,10 +1,10 @@ -use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then}; use clippy_utils::trait_ref_of_method; -use rustc_data_structures::fx::FxHashMap; -use rustc_errors::MultiSpan; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_impl_item, walk_item, walk_param_bound, walk_ty, Visitor}; use rustc_hir::{ - BodyId, ExprKind, GenericBound, GenericParamKind, Generics, ImplItem, ImplItemKind, Item, ItemKind, + BodyId, ExprKind, GenericBound, GenericParam, GenericParamKind, Generics, ImplItem, ImplItemKind, Item, ItemKind, PredicateOrigin, Ty, TyKind, WherePredicate, }; use rustc_lint::{LateContext, LateLintPass, LintContext}; @@ -53,13 +53,19 @@ impl ExtraUnusedTypeParameters { } } - /// Don't lint external macros or functions with empty bodies. Also, don't lint public items if - /// the `avoid_breaking_exported_api` config option is set. - fn check_false_positive(&self, cx: &LateContext<'_>, span: Span, def_id: LocalDefId, body_id: BodyId) -> bool { + /// Don't lint external macros or functions with empty bodies. Also, don't lint exported items + /// if the `avoid_breaking_exported_api` config option is set. + fn is_empty_exported_or_macro( + &self, + cx: &LateContext<'_>, + span: Span, + def_id: LocalDefId, + body_id: BodyId, + ) -> bool { let body = cx.tcx.hir().body(body_id).value; let fn_empty = matches!(&body.kind, ExprKind::Block(blk, None) if blk.stmts.is_empty() && blk.expr.is_none()); let is_exported = cx.effective_visibilities.is_exported(def_id); - in_external_macro(cx.sess(), span) || (self.avoid_breaking_exported_api && is_exported) || fn_empty + in_external_macro(cx.sess(), span) || fn_empty || (is_exported && self.avoid_breaking_exported_api) } } @@ -69,85 +75,129 @@ impl_lint_pass!(ExtraUnusedTypeParameters => [EXTRA_UNUSED_TYPE_PARAMETERS]); /// trait bounds those parameters have. struct TypeWalker<'cx, 'tcx> { cx: &'cx LateContext<'tcx>, - /// Collection of all the function's type parameters. + /// Collection of the function's type parameters. Once the function has been walked, this will + /// contain only unused type parameters. ty_params: FxHashMap, - /// Collection of any (inline) trait bounds corresponding to each type parameter. - bounds: FxHashMap, + /// Collection of any inline trait bounds corresponding to each type parameter. + inline_bounds: FxHashMap, + /// Collection of any type parameters with trait bounds that appear in a where clause. + where_bounds: FxHashSet, /// The entire `Generics` object of the function, useful for querying purposes. generics: &'tcx Generics<'tcx>, - /// The value of this will remain `true` if *every* parameter: - /// 1. Is a type parameter, and - /// 2. Goes unused in the function. - /// Otherwise, if any type parameters end up being used, or if any lifetime or const-generic - /// parameters are present, this will be set to `false`. - all_params_unused: bool, } impl<'cx, 'tcx> TypeWalker<'cx, 'tcx> { fn new(cx: &'cx LateContext<'tcx>, generics: &'tcx Generics<'tcx>) -> Self { - let mut all_params_unused = true; let ty_params = generics .params .iter() - .filter_map(|param| { - if let GenericParamKind::Type { synthetic, .. } = param.kind { - (!synthetic).then_some((param.def_id.into(), param.span)) - } else { - if !param.is_elided_lifetime() { - all_params_unused = false; - } - None - } + .filter_map(|param| match param.kind { + GenericParamKind::Type { synthetic, .. } if !synthetic => Some((param.def_id.into(), param.span)), + _ => None, }) .collect(); Self { cx, ty_params, - bounds: FxHashMap::default(), + inline_bounds: FxHashMap::default(), + where_bounds: FxHashSet::default(), generics, - all_params_unused, } } - fn mark_param_used(&mut self, def_id: DefId) { - if self.ty_params.remove(&def_id).is_some() { - self.all_params_unused = false; - } + fn get_bound_span(&self, param: &'tcx GenericParam<'tcx>) -> Span { + self.inline_bounds + .get(¶m.def_id.to_def_id()) + .map_or(param.span, |bound_span| param.span.with_hi(bound_span.hi())) + } + + fn emit_help(&self, spans: Vec, msg: &str, help: &'static str) { + span_lint_and_help(self.cx, EXTRA_UNUSED_TYPE_PARAMETERS, spans, msg, None, help); + } + + fn emit_sugg(&self, spans: Vec, msg: &str, help: &'static str) { + let suggestions: Vec<(Span, String)> = spans.iter().copied().zip(std::iter::repeat(String::new())).collect(); + span_lint_and_then(self.cx, EXTRA_UNUSED_TYPE_PARAMETERS, spans, msg, |diag| { + diag.multipart_suggestion(help, suggestions, Applicability::MachineApplicable); + }); } fn emit_lint(&self) { - let (msg, help) = match self.ty_params.len() { + let explicit_params = self + .generics + .params + .iter() + .filter(|param| !param.is_elided_lifetime() && !param.is_impl_trait()) + .collect::>(); + + let extra_params = explicit_params + .iter() + .enumerate() + .filter(|(_, param)| self.ty_params.contains_key(¶m.def_id.to_def_id())) + .collect::>(); + + let (msg, help) = match extra_params.len() { 0 => return, 1 => ( - "type parameter goes unused in function definition", + format!( + "type parameter `{}` goes unused in function definition", + extra_params[0].1.name.ident() + ), "consider removing the parameter", ), _ => ( - "type parameters go unused in function definition", + format!( + "type parameters go unused in function definition: {}", + extra_params + .iter() + .map(|(_, param)| param.name.ident().to_string()) + .collect::>() + .join(", ") + ), "consider removing the parameters", ), }; - let source_map = self.cx.sess().source_map(); - let span = if self.all_params_unused { - self.generics.span.into() // Remove the entire list of generics + // If any parameters are bounded in where clauses, don't try to form a suggestion. + // Otherwise, the leftover where bound would produce code that wouldn't compile. + if extra_params + .iter() + .any(|(_, param)| self.where_bounds.contains(¶m.def_id.to_def_id())) + { + let spans = extra_params + .iter() + .map(|(_, param)| self.get_bound_span(param)) + .collect::>(); + self.emit_help(spans, &msg, help); } else { - MultiSpan::from_spans( - self.ty_params + let spans = if explicit_params.len() == extra_params.len() { + vec![self.generics.span] // Remove the entire list of generics + } else { + let mut end: Option = None; + extra_params .iter() - .map(|(def_id, &span)| { - // Extend the span past any trait bounds, and include the comma at the end. - let span_to_extend = self.bounds.get(def_id).copied().map_or(span, Span::shrink_to_hi); - let comma_range = source_map.span_extend_to_next_char(span_to_extend, '>', false); - let comma_span = source_map.span_through_char(comma_range, ','); - span.with_hi(comma_span.hi()) + .rev() + .map(|(idx, param)| { + if let Some(next) = explicit_params.get(idx + 1) && end != Some(next.def_id) { + // Extend the current span forward, up until the next param in the list. + param.span.until(next.span) + } else { + // Extend the current span back to include the comma following the previous + // param. If the span of the next param in the list has already been + // extended, we continue the chain. This is why we're iterating in reverse. + end = Some(param.def_id); + + // idx will never be 0, else we'd be removing the entire list of generics + let prev = explicit_params[idx - 1]; + let prev_span = self.get_bound_span(prev); + self.get_bound_span(param).with_lo(prev_span.hi()) + } }) - .collect(), - ) + .collect() + }; + self.emit_sugg(spans, &msg, help); }; - - span_lint_and_help(self.cx, EXTRA_UNUSED_TYPE_PARAMETERS, span, msg, None, help); } } @@ -162,7 +212,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for TypeWalker<'cx, 'tcx> { fn visit_ty(&mut self, t: &'tcx Ty<'tcx>) { if let Some((def_id, _)) = t.peel_refs().as_generic_param() { - self.mark_param_used(def_id); + self.ty_params.remove(&def_id); } else if let TyKind::OpaqueDef(id, _, _) = t.kind { // Explicitly walk OpaqueDef. Normally `walk_ty` would do the job, but it calls // `visit_nested_item`, which checks that `Self::NestedFilter::INTER` is set. We're @@ -176,9 +226,18 @@ impl<'cx, 'tcx> Visitor<'tcx> for TypeWalker<'cx, 'tcx> { fn visit_where_predicate(&mut self, predicate: &'tcx WherePredicate<'tcx>) { if let WherePredicate::BoundPredicate(predicate) = predicate { - // Collect spans for any bounds on type parameters. We only keep bounds that appear in - // the list of generics (not in a where-clause). + // Collect spans for any bounds on type parameters. if let Some((def_id, _)) = predicate.bounded_ty.peel_refs().as_generic_param() { + match predicate.origin { + PredicateOrigin::GenericParam => { + self.inline_bounds.insert(def_id, predicate.span); + }, + PredicateOrigin::WhereClause => { + self.where_bounds.insert(def_id); + }, + PredicateOrigin::ImplTrait => (), + } + // If the bound contains non-public traits, err on the safe side and don't lint the // corresponding parameter. if !predicate @@ -187,12 +246,10 @@ impl<'cx, 'tcx> Visitor<'tcx> for TypeWalker<'cx, 'tcx> { .filter_map(bound_to_trait_def_id) .all(|id| self.cx.effective_visibilities.is_exported(id)) { - self.mark_param_used(def_id); - } else if let PredicateOrigin::GenericParam = predicate.origin { - self.bounds.insert(def_id, predicate.span); + self.ty_params.remove(&def_id); } } - // Only walk the right-hand side of where-bounds + // Only walk the right-hand side of where bounds for bound in predicate.bounds { walk_param_bound(self, bound); } @@ -207,7 +264,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for TypeWalker<'cx, 'tcx> { impl<'tcx> LateLintPass<'tcx> for ExtraUnusedTypeParameters { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { if let ItemKind::Fn(_, generics, body_id) = item.kind - && !self.check_false_positive(cx, item.span, item.owner_id.def_id, body_id) + && !self.is_empty_exported_or_macro(cx, item.span, item.owner_id.def_id, body_id) { let mut walker = TypeWalker::new(cx, generics); walk_item(&mut walker, item); @@ -219,7 +276,7 @@ impl<'tcx> LateLintPass<'tcx> for ExtraUnusedTypeParameters { // Only lint on inherent methods, not trait methods. if let ImplItemKind::Fn(.., body_id) = item.kind && trait_ref_of_method(cx, item.owner_id.def_id).is_none() - && !self.check_false_positive(cx, item.span, item.owner_id.def_id, body_id) + && !self.is_empty_exported_or_macro(cx, item.span, item.owner_id.def_id, body_id) { let mut walker = TypeWalker::new(cx, item.generics); walk_impl_item(&mut walker, item); diff --git a/clippy_lints/src/format.rs b/clippy_lints/src/format.rs index 8040938c6263e..d34d6e9279e4d 100644 --- a/clippy_lints/src/format.rs +++ b/clippy_lints/src/format.rs @@ -1,14 +1,13 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::macros::{root_macro_call_first_node, FormatArgsExpn}; -use clippy_utils::source::snippet_with_context; +use clippy_utils::macros::{find_format_arg_expr, find_format_args, root_macro_call_first_node}; +use clippy_utils::source::{snippet_opt, snippet_with_context}; use clippy_utils::sugg::Sugg; -use if_chain::if_chain; +use rustc_ast::{FormatArgsPiece, FormatOptions, FormatTrait}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::symbol::kw; use rustc_span::{sym, Span}; declare_clippy_lint! { @@ -44,55 +43,53 @@ declare_lint_pass!(UselessFormat => [USELESS_FORMAT]); impl<'tcx> LateLintPass<'tcx> for UselessFormat { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - let (format_args, call_site) = if_chain! { - if let Some(macro_call) = root_macro_call_first_node(cx, expr); - if cx.tcx.is_diagnostic_item(sym::format_macro, macro_call.def_id); - if let Some(format_args) = FormatArgsExpn::find_nested(cx, expr, macro_call.expn); - then { - (format_args, macro_call.span) - } else { - return - } - }; + let Some(macro_call) = root_macro_call_first_node(cx, expr) else { return }; + if !cx.tcx.is_diagnostic_item(sym::format_macro, macro_call.def_id) { + return; + } + + find_format_args(cx, expr, macro_call.expn, |format_args| { + let mut applicability = Applicability::MachineApplicable; + let call_site = macro_call.span; - let mut applicability = Applicability::MachineApplicable; - if format_args.args.is_empty() { - match *format_args.format_string.parts { - [] => span_useless_format_empty(cx, call_site, "String::new()".to_owned(), applicability), - [_] => { + match (format_args.arguments.all_args(), &format_args.template[..]) { + ([], []) => span_useless_format_empty(cx, call_site, "String::new()".to_owned(), applicability), + ([], [_]) => { // Simulate macro expansion, converting {{ and }} to { and }. - let s_expand = format_args.format_string.snippet.replace("{{", "{").replace("}}", "}"); + let Some(snippet) = snippet_opt(cx, format_args.span) else { return }; + let s_expand = snippet.replace("{{", "{").replace("}}", "}"); let sugg = format!("{s_expand}.to_string()"); span_useless_format(cx, call_site, sugg, applicability); }, - [..] => {}, - } - } else if let [arg] = &*format_args.args { - let value = arg.param.value; - if_chain! { - if format_args.format_string.parts == [kw::Empty]; - if arg.format.is_default(); - if match cx.typeck_results().expr_ty(value).peel_refs().kind() { - ty::Adt(adt, _) => Some(adt.did()) == cx.tcx.lang_items().string(), - ty::Str => true, - _ => false, - }; - then { - let is_new_string = match value.kind { - ExprKind::Binary(..) => true, - ExprKind::MethodCall(path, ..) => path.ident.name == sym::to_string, - _ => false, - }; - let sugg = if is_new_string { - snippet_with_context(cx, value.span, call_site.ctxt(), "..", &mut applicability).0.into_owned() - } else { - let sugg = Sugg::hir_with_context(cx, value, call_site.ctxt(), "", &mut applicability); - format!("{}.to_string()", sugg.maybe_par()) - }; - span_useless_format(cx, call_site, sugg, applicability); - } + ([arg], [piece]) => { + if let Ok(value) = find_format_arg_expr(expr, arg) + && let FormatArgsPiece::Placeholder(placeholder) = piece + && placeholder.format_trait == FormatTrait::Display + && placeholder.format_options == FormatOptions::default() + && match cx.typeck_results().expr_ty(value).peel_refs().kind() { + ty::Adt(adt, _) => Some(adt.did()) == cx.tcx.lang_items().string(), + ty::Str => true, + _ => false, + } + { + let is_new_string = match value.kind { + ExprKind::Binary(..) => true, + ExprKind::MethodCall(path, ..) => path.ident.name == sym::to_string, + _ => false, + }; + let sugg = if is_new_string { + snippet_with_context(cx, value.span, call_site.ctxt(), "..", &mut applicability).0.into_owned() + } else { + let sugg = Sugg::hir_with_context(cx, value, call_site.ctxt(), "", &mut applicability); + format!("{}.to_string()", sugg.maybe_par()) + }; + span_useless_format(cx, call_site, sugg, applicability); + + } + }, + _ => {}, } - }; + }); } } diff --git a/clippy_lints/src/format_args.rs b/clippy_lints/src/format_args.rs index c511d85e9cf29..08e45ed7d0ec8 100644 --- a/clippy_lints/src/format_args.rs +++ b/clippy_lints/src/format_args.rs @@ -1,27 +1,31 @@ +use arrayvec::ArrayVec; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::is_diag_trait_item; -use clippy_utils::macros::FormatParamKind::{Implicit, Named, NamedInline, Numbered, Starred}; use clippy_utils::macros::{ - is_assert_macro, is_format_macro, is_panic, root_macro_call, Count, FormatArg, FormatArgsExpn, FormatParam, - FormatParamUsage, + find_format_arg_expr, find_format_args, format_arg_removal_span, format_placeholder_format_span, is_assert_macro, + is_format_macro, is_panic, root_macro_call, root_macro_call_first_node, FormatParamUsage, }; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_opt; use clippy_utils::ty::{implements_trait, is_type_lang_item}; use if_chain::if_chain; use itertools::Itertools; +use rustc_ast::{ + FormatArgPosition, FormatArgPositionKind, FormatArgsPiece, FormatArgumentKind, FormatCount, FormatOptions, + FormatPlaceholder, FormatTrait, +}; use rustc_errors::{ Applicability, SuggestionStyle::{CompletelyHidden, ShowCode}, }; -use rustc_hir::{Expr, ExprKind, HirId, LangItem, QPath}; +use rustc_hir::{Expr, ExprKind, LangItem}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::ty::adjustment::{Adjust, Adjustment}; use rustc_middle::ty::Ty; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::def_id::DefId; use rustc_span::edition::Edition::Edition2021; -use rustc_span::{sym, ExpnData, ExpnKind, Span, Symbol}; +use rustc_span::{sym, Span, Symbol}; declare_clippy_lint! { /// ### What it does @@ -184,72 +188,79 @@ impl FormatArgs { impl<'tcx> LateLintPass<'tcx> for FormatArgs { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { - if let Some(format_args) = FormatArgsExpn::parse(cx, expr) - && let expr_expn_data = expr.span.ctxt().outer_expn_data() - && let outermost_expn_data = outermost_expn_data(expr_expn_data) - && let Some(macro_def_id) = outermost_expn_data.macro_def_id - && is_format_macro(cx, macro_def_id) - && let ExpnKind::Macro(_, name) = outermost_expn_data.kind - { - for arg in &format_args.args { - check_unused_format_specifier(cx, arg); - if !arg.format.is_default() { - continue; - } - if is_aliased(&format_args, arg.param.value.hir_id) { - continue; + let Some(macro_call) = root_macro_call_first_node(cx, expr) else { return }; + if !is_format_macro(cx, macro_call.def_id) { + return; + } + let name = cx.tcx.item_name(macro_call.def_id); + + find_format_args(cx, expr, macro_call.expn, |format_args| { + for piece in &format_args.template { + if let FormatArgsPiece::Placeholder(placeholder) = piece + && let Ok(index) = placeholder.argument.index + && let Some(arg) = format_args.arguments.all_args().get(index) + { + let arg_expr = find_format_arg_expr(expr, arg); + + check_unused_format_specifier(cx, placeholder, arg_expr); + + if placeholder.format_trait != FormatTrait::Display + || placeholder.format_options != FormatOptions::default() + || is_aliased(format_args, index) + { + continue; + } + + if let Ok(arg_hir_expr) = arg_expr { + check_format_in_format_args(cx, macro_call.span, name, arg_hir_expr); + check_to_string_in_format_args(cx, name, arg_hir_expr); + } } - check_format_in_format_args(cx, outermost_expn_data.call_site, name, arg.param.value); - check_to_string_in_format_args(cx, name, arg.param.value); } + if self.msrv.meets(msrvs::FORMAT_ARGS_CAPTURE) { - check_uninlined_args(cx, &format_args, outermost_expn_data.call_site, macro_def_id, self.ignore_mixed); + check_uninlined_args(cx, format_args, macro_call.span, macro_call.def_id, self.ignore_mixed); } - } + }); } extract_msrv_attr!(LateContext); } -fn check_unused_format_specifier(cx: &LateContext<'_>, arg: &FormatArg<'_>) { - let param_ty = cx.typeck_results().expr_ty(arg.param.value).peel_refs(); +fn check_unused_format_specifier( + cx: &LateContext<'_>, + placeholder: &FormatPlaceholder, + arg_expr: Result<&Expr<'_>, &rustc_ast::Expr>, +) { + let ty_or_ast_expr = arg_expr.map(|expr| cx.typeck_results().expr_ty(expr).peel_refs()); - if let Count::Implied(Some(mut span)) = arg.format.precision - && !span.is_empty() - { - span_lint_and_then( - cx, - UNUSED_FORMAT_SPECS, - span, - "empty precision specifier has no effect", - |diag| { - if param_ty.is_floating_point() { - diag.note("a precision specifier is not required to format floats"); - } + let is_format_args = match ty_or_ast_expr { + Ok(ty) => is_type_lang_item(cx, ty, LangItem::FormatArguments), + Err(expr) => matches!(expr.peel_parens_and_refs().kind, rustc_ast::ExprKind::FormatArgs(_)), + }; - if arg.format.is_default() { - // If there's no other specifiers remove the `:` too - span = arg.format_span(); - } + let options = &placeholder.format_options; - diag.span_suggestion_verbose(span, "remove the `.`", "", Applicability::MachineApplicable); - }, - ); - } + let arg_span = match arg_expr { + Ok(expr) => expr.span, + Err(expr) => expr.span, + }; - if is_type_lang_item(cx, param_ty, LangItem::FormatArguments) && !arg.format.is_default_for_trait() { + if let Some(placeholder_span) = placeholder.span + && is_format_args + && *options != FormatOptions::default() + { span_lint_and_then( cx, UNUSED_FORMAT_SPECS, - arg.span, + placeholder_span, "format specifiers have no effect on `format_args!()`", |diag| { - let mut suggest_format = |spec, span| { + let mut suggest_format = |spec| { let message = format!("for the {spec} to apply consider using `format!()`"); - if let Some(mac_call) = root_macro_call(arg.param.value.span) + if let Some(mac_call) = root_macro_call(arg_span) && cx.tcx.is_diagnostic_item(sym::format_args_macro, mac_call.def_id) - && arg.span.eq_ctxt(mac_call.span) { diag.span_suggestion( cx.sess().source_map().span_until_char(mac_call.span, '!'), @@ -257,25 +268,27 @@ fn check_unused_format_specifier(cx: &LateContext<'_>, arg: &FormatArg<'_>) { "format", Applicability::MaybeIncorrect, ); - } else if let Some(span) = span { - diag.span_help(span, message); + } else { + diag.help(message); } }; - if !arg.format.width.is_implied() { - suggest_format("width", arg.format.width.span()); + if options.width.is_some() { + suggest_format("width"); } - if !arg.format.precision.is_implied() { - suggest_format("precision", arg.format.precision.span()); + if options.precision.is_some() { + suggest_format("precision"); } - diag.span_suggestion_verbose( - arg.format_span(), - "if the current behavior is intentional, remove the format specifiers", - "", - Applicability::MaybeIncorrect, - ); + if let Some(format_span) = format_placeholder_format_span(placeholder) { + diag.span_suggestion_verbose( + format_span, + "if the current behavior is intentional, remove the format specifiers", + "", + Applicability::MaybeIncorrect, + ); + } }, ); } @@ -283,12 +296,12 @@ fn check_unused_format_specifier(cx: &LateContext<'_>, arg: &FormatArg<'_>) { fn check_uninlined_args( cx: &LateContext<'_>, - args: &FormatArgsExpn<'_>, + args: &rustc_ast::FormatArgs, call_site: Span, def_id: DefId, ignore_mixed: bool, ) { - if args.format_string.span.from_expansion() { + if args.span.from_expansion() { return; } if call_site.edition() < Edition2021 && (is_panic(cx, def_id) || is_assert_macro(cx, def_id)) { @@ -303,7 +316,13 @@ fn check_uninlined_args( // we cannot remove any other arguments in the format string, // because the index numbers might be wrong after inlining. // Example of an un-inlinable format: print!("{}{1}", foo, 2) - if !args.params().all(|p| check_one_arg(args, &p, &mut fixes, ignore_mixed)) || fixes.is_empty() { + for (pos, usage) in format_arg_positions(args) { + if !check_one_arg(args, pos, usage, &mut fixes, ignore_mixed) { + return; + } + } + + if fixes.is_empty() { return; } @@ -332,47 +351,40 @@ fn check_uninlined_args( } fn check_one_arg( - args: &FormatArgsExpn<'_>, - param: &FormatParam<'_>, + args: &rustc_ast::FormatArgs, + pos: &FormatArgPosition, + usage: FormatParamUsage, fixes: &mut Vec<(Span, String)>, ignore_mixed: bool, ) -> bool { - if matches!(param.kind, Implicit | Starred | Named(_) | Numbered) - && let ExprKind::Path(QPath::Resolved(None, path)) = param.value.kind - && let [segment] = path.segments + let index = pos.index.unwrap(); + let arg = &args.arguments.all_args()[index]; + + if !matches!(arg.kind, FormatArgumentKind::Captured(_)) + && let rustc_ast::ExprKind::Path(None, path) = &arg.expr.kind + && let [segment] = path.segments.as_slice() && segment.args.is_none() - && let Some(arg_span) = args.value_with_prev_comma_span(param.value.hir_id) + && let Some(arg_span) = format_arg_removal_span(args, index) + && let Some(pos_span) = pos.span { - let replacement = match param.usage { + let replacement = match usage { FormatParamUsage::Argument => segment.ident.name.to_string(), FormatParamUsage::Width => format!("{}$", segment.ident.name), FormatParamUsage::Precision => format!(".{}$", segment.ident.name), }; - fixes.push((param.span, replacement)); + fixes.push((pos_span, replacement)); fixes.push((arg_span, String::new())); true // successful inlining, continue checking } else { // Do not continue inlining (return false) in case // * if we can't inline a numbered argument, e.g. `print!("{0} ...", foo.bar, ...)` // * if allow_mixed_uninlined_format_args is false and this arg hasn't been inlined already - param.kind != Numbered && (!ignore_mixed || matches!(param.kind, NamedInline(_))) - } -} - -fn outermost_expn_data(expn_data: ExpnData) -> ExpnData { - if expn_data.call_site.from_expansion() { - outermost_expn_data(expn_data.call_site.ctxt().outer_expn_data()) - } else { - expn_data + pos.kind != FormatArgPositionKind::Number + && (!ignore_mixed || matches!(arg.kind, FormatArgumentKind::Captured(_))) } } -fn check_format_in_format_args( - cx: &LateContext<'_>, - call_site: Span, - name: Symbol, - arg: &Expr<'_>, -) { +fn check_format_in_format_args(cx: &LateContext<'_>, call_site: Span, name: Symbol, arg: &Expr<'_>) { let expn_data = arg.span.ctxt().outer_expn_data(); if expn_data.call_site.from_expansion() { return; @@ -443,9 +455,33 @@ fn check_to_string_in_format_args(cx: &LateContext<'_>, name: Symbol, value: &Ex } } -/// Returns true if `hir_id` is referred to by multiple format params -fn is_aliased(args: &FormatArgsExpn<'_>, hir_id: HirId) -> bool { - args.params().filter(|param| param.value.hir_id == hir_id).at_most_one().is_err() +fn format_arg_positions( + format_args: &rustc_ast::FormatArgs, +) -> impl Iterator { + format_args.template.iter().flat_map(|piece| match piece { + FormatArgsPiece::Placeholder(placeholder) => { + let mut positions = ArrayVec::<_, 3>::new(); + + positions.push((&placeholder.argument, FormatParamUsage::Argument)); + if let Some(FormatCount::Argument(position)) = &placeholder.format_options.width { + positions.push((position, FormatParamUsage::Width)); + } + if let Some(FormatCount::Argument(position)) = &placeholder.format_options.precision { + positions.push((position, FormatParamUsage::Precision)); + } + + positions + }, + FormatArgsPiece::Literal(_) => ArrayVec::new(), + }) +} + +/// Returns true if the format argument at `index` is referred to by multiple format params +fn is_aliased(format_args: &rustc_ast::FormatArgs, index: usize) -> bool { + format_arg_positions(format_args) + .filter(|(position, _)| position.index == Ok(index)) + .at_most_one() + .is_err() } fn count_needed_derefs<'tcx, I>(mut ty: Ty<'tcx>, mut iter: I) -> (usize, Ty<'tcx>) @@ -455,7 +491,11 @@ where let mut n_total = 0; let mut n_needed = 0; loop { - if let Some(Adjustment { kind: Adjust::Deref(overloaded_deref), target }) = iter.next() { + if let Some(Adjustment { + kind: Adjust::Deref(overloaded_deref), + target, + }) = iter.next() + { n_total += 1; if overloaded_deref.is_some() { n_needed = n_total; diff --git a/clippy_lints/src/format_impl.rs b/clippy_lints/src/format_impl.rs index ed1342a546543..e3ddbfb5981f8 100644 --- a/clippy_lints/src/format_impl.rs +++ b/clippy_lints/src/format_impl.rs @@ -1,11 +1,13 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; -use clippy_utils::macros::{is_format_macro, root_macro_call_first_node, FormatArg, FormatArgsExpn}; +use clippy_utils::macros::{find_format_arg_expr, find_format_args, is_format_macro, root_macro_call_first_node}; use clippy_utils::{get_parent_as_impl, is_diag_trait_item, path_to_local, peel_ref_operators}; use if_chain::if_chain; +use rustc_ast::{FormatArgsPiece, FormatTrait}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, Impl, ImplItem, ImplItemKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_span::Span; use rustc_span::{sym, symbol::kw, Symbol}; declare_clippy_lint! { @@ -89,7 +91,7 @@ declare_clippy_lint! { } #[derive(Clone, Copy)] -struct FormatTrait { +struct FormatTraitNames { /// e.g. `sym::Display` name: Symbol, /// `f` in `fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {}` @@ -99,7 +101,7 @@ struct FormatTrait { #[derive(Default)] pub struct FormatImpl { // Whether we are inside Display or Debug trait impl - None for neither - format_trait_impl: Option, + format_trait_impl: Option, } impl FormatImpl { @@ -161,43 +163,57 @@ fn check_to_string_in_display(cx: &LateContext<'_>, expr: &Expr<'_>) { } } -fn check_self_in_format_args<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, impl_trait: FormatTrait) { +fn check_self_in_format_args<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, impl_trait: FormatTraitNames) { // Check each arg in format calls - do we ever use Display on self (directly or via deref)? - if_chain! { - if let Some(outer_macro) = root_macro_call_first_node(cx, expr); - if let macro_def_id = outer_macro.def_id; - if let Some(format_args) = FormatArgsExpn::find_nested(cx, expr, outer_macro.expn); - if is_format_macro(cx, macro_def_id); - then { - for arg in format_args.args { - if arg.format.r#trait != impl_trait.name { - continue; + if let Some(outer_macro) = root_macro_call_first_node(cx, expr) + && let macro_def_id = outer_macro.def_id + && is_format_macro(cx, macro_def_id) + { + find_format_args(cx, expr, outer_macro.expn, |format_args| { + for piece in &format_args.template { + if let FormatArgsPiece::Placeholder(placeholder) = piece + && let trait_name = match placeholder.format_trait { + FormatTrait::Display => sym::Display, + FormatTrait::Debug => sym::Debug, + FormatTrait::LowerExp => sym!(LowerExp), + FormatTrait::UpperExp => sym!(UpperExp), + FormatTrait::Octal => sym!(Octal), + FormatTrait::Pointer => sym::Pointer, + FormatTrait::Binary => sym!(Binary), + FormatTrait::LowerHex => sym!(LowerHex), + FormatTrait::UpperHex => sym!(UpperHex), + } + && trait_name == impl_trait.name + && let Ok(index) = placeholder.argument.index + && let Some(arg) = format_args.arguments.all_args().get(index) + && let Ok(arg_expr) = find_format_arg_expr(expr, arg) + { + check_format_arg_self(cx, expr.span, arg_expr, impl_trait); } - check_format_arg_self(cx, expr, &arg, impl_trait); } - } + }); } } -fn check_format_arg_self(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &FormatArg<'_>, impl_trait: FormatTrait) { +fn check_format_arg_self(cx: &LateContext<'_>, span: Span, arg: &Expr<'_>, impl_trait: FormatTraitNames) { // Handle multiple dereferencing of references e.g. &&self // Handle dereference of &self -> self that is equivalent (i.e. via *self in fmt() impl) // Since the argument to fmt is itself a reference: &self - let reference = peel_ref_operators(cx, arg.param.value); + let reference = peel_ref_operators(cx, arg); let map = cx.tcx.hir(); // Is the reference self? if path_to_local(reference).map(|x| map.name(x)) == Some(kw::SelfLower) { - let FormatTrait { name, .. } = impl_trait; + let FormatTraitNames { name, .. } = impl_trait; span_lint( cx, RECURSIVE_FORMAT_IMPL, - expr.span, + span, &format!("using `self` as `{name}` in `impl {name}` will cause infinite recursion"), ); } } -fn check_print_in_format_impl(cx: &LateContext<'_>, expr: &Expr<'_>, impl_trait: FormatTrait) { +fn check_print_in_format_impl(cx: &LateContext<'_>, expr: &Expr<'_>, impl_trait: FormatTraitNames) { if_chain! { if let Some(macro_call) = root_macro_call_first_node(cx, expr); if let Some(name) = cx.tcx.get_diagnostic_name(macro_call.def_id); @@ -227,7 +243,7 @@ fn check_print_in_format_impl(cx: &LateContext<'_>, expr: &Expr<'_>, impl_trait: } } -fn is_format_trait_impl(cx: &LateContext<'_>, impl_item: &ImplItem<'_>) -> Option { +fn is_format_trait_impl(cx: &LateContext<'_>, impl_item: &ImplItem<'_>) -> Option { if_chain! { if impl_item.ident.name == sym::fmt; if let ImplItemKind::Fn(_, body_id) = impl_item.kind; @@ -241,7 +257,7 @@ fn is_format_trait_impl(cx: &LateContext<'_>, impl_item: &ImplItem<'_>) -> Optio .and_then(|param| param.pat.simple_ident()) .map(|ident| ident.name); - Some(FormatTrait { + Some(FormatTraitNames { name, formatter_name, }) diff --git a/clippy_lints/src/functions/must_use.rs b/clippy_lints/src/functions/must_use.rs index 1e9e826631c37..d0ad26282642c 100644 --- a/clippy_lints/src/functions/must_use.rs +++ b/clippy_lints/src/functions/must_use.rs @@ -1,7 +1,9 @@ +use hir::FnSig; use rustc_ast::ast::Attribute; use rustc_errors::Applicability; use rustc_hir::def_id::DefIdSet; use rustc_hir::{self as hir, def::Res, QPath}; +use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, LintContext}; use rustc_middle::{ lint::in_external_macro, @@ -27,7 +29,7 @@ pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_> let is_public = cx.effective_visibilities.is_exported(item.owner_id.def_id); let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); if let Some(attr) = attr { - check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr); + check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr, sig); } else if is_public && !is_proc_macro(attrs) && !attrs.iter().any(|a| a.has_name(sym::no_mangle)) { check_must_use_candidate( cx, @@ -49,7 +51,7 @@ pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Imp let attrs = cx.tcx.hir().attrs(item.hir_id()); 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); + check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr, sig); } 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, @@ -72,7 +74,7 @@ pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Tr let attrs = cx.tcx.hir().attrs(item.hir_id()); 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); + check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr, sig); } else if let hir::TraitFn::Provided(eid) = *eid { let body = cx.tcx.hir().body(eid); if attr.is_none() && is_public && !is_proc_macro(attrs) { @@ -97,6 +99,7 @@ fn check_needless_must_use( item_span: Span, fn_header_span: Span, attr: &Attribute, + sig: &FnSig<'_>, ) { if in_external_macro(cx.sess(), item_span) { return; @@ -112,6 +115,15 @@ fn check_needless_must_use( }, ); } else if attr.value_str().is_none() && is_must_use_ty(cx, return_ty(cx, item_id)) { + // Ignore async functions unless Future::Output type is a must_use type + if sig.header.is_async() { + let infcx = cx.tcx.infer_ctxt().build(); + if let Some(future_ty) = infcx.get_impl_future_output_ty(return_ty(cx, item_id)) + && !is_must_use_ty(cx, future_ty) { + return; + } + } + span_lint_and_help( cx, DOUBLE_MUST_USE, diff --git a/clippy_lints/src/items_after_statements.rs b/clippy_lints/src/items_after_statements.rs index 46d439b4497e1..a7ec57e28505b 100644 --- a/clippy_lints/src/items_after_statements.rs +++ b/clippy_lints/src/items_after_statements.rs @@ -1,8 +1,8 @@ //! lint when items are used after statements -use clippy_utils::diagnostics::span_lint; -use rustc_ast::ast::{Block, ItemKind, StmtKind}; -use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; +use clippy_utils::diagnostics::span_lint_hir; +use rustc_hir::{Block, ItemKind, StmtKind}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -52,33 +52,34 @@ declare_clippy_lint! { declare_lint_pass!(ItemsAfterStatements => [ITEMS_AFTER_STATEMENTS]); -impl EarlyLintPass for ItemsAfterStatements { - fn check_block(&mut self, cx: &EarlyContext<'_>, item: &Block) { - if in_external_macro(cx.sess(), item.span) { +impl LateLintPass<'_> for ItemsAfterStatements { + fn check_block(&mut self, cx: &LateContext<'_>, block: &Block<'_>) { + if in_external_macro(cx.sess(), block.span) { return; } - // skip initial items and trailing semicolons - let stmts = item + // skip initial items + let stmts = block .stmts .iter() - .map(|stmt| &stmt.kind) - .skip_while(|s| matches!(**s, StmtKind::Item(..) | StmtKind::Empty)); + .skip_while(|stmt| matches!(stmt.kind, StmtKind::Item(..))); // lint on all further items for stmt in stmts { - if let StmtKind::Item(ref it) = *stmt { - if in_external_macro(cx.sess(), it.span) { + if let StmtKind::Item(item_id) = stmt.kind { + let item = cx.tcx.hir().item(item_id); + if in_external_macro(cx.sess(), item.span) || !item.span.eq_ctxt(block.span) { return; } - if let ItemKind::MacroDef(..) = it.kind { + if let ItemKind::Macro(..) = item.kind { // do not lint `macro_rules`, but continue processing further statements continue; } - span_lint( + span_lint_hir( cx, ITEMS_AFTER_STATEMENTS, - it.span, + item.hir_id(), + item.span, "adding items after statements is confusing, since items exist from the \ start of the scope", ); diff --git a/clippy_lints/src/large_futures.rs b/clippy_lints/src/large_futures.rs new file mode 100644 index 0000000000000..1b0544813718a --- /dev/null +++ b/clippy_lints/src/large_futures.rs @@ -0,0 +1,87 @@ +use clippy_utils::source::snippet; +use clippy_utils::{diagnostics::span_lint_and_sugg, ty::implements_trait}; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind, LangItem, MatchSource, QPath}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_target::abi::Size; + +declare_clippy_lint! { + /// ### What it does + /// It checks for the size of a `Future` created by `async fn` or `async {}`. + /// + /// ### Why is this bad? + /// Due to the current [unideal implemention](https://github.com/rust-lang/rust/issues/69826) of `Generator`, + /// large size of a `Future` may cause stack overflows. + /// + /// ### Example + /// ```rust + /// async fn wait(f: impl std::future::Future) {} + /// + /// async fn big_fut(arg: [u8; 1024]) {} + /// + /// pub async fn test() { + /// let fut = big_fut([0u8; 1024]); + /// wait(fut).await; + /// } + /// ``` + /// + /// `Box::pin` the big future instead. + /// + /// ```rust + /// async fn wait(f: impl std::future::Future) {} + /// + /// async fn big_fut(arg: [u8; 1024]) {} + /// + /// pub async fn test() { + /// let fut = Box::pin(big_fut([0u8; 1024])); + /// wait(fut).await; + /// } + /// ``` + #[clippy::version = "1.68.0"] + pub LARGE_FUTURES, + pedantic, + "large future may lead to unexpected stack overflows" +} + +#[derive(Copy, Clone)] +pub struct LargeFuture { + future_size_threshold: u64, +} + +impl LargeFuture { + pub fn new(future_size_threshold: u64) -> Self { + Self { future_size_threshold } + } +} + +impl_lint_pass!(LargeFuture => [LARGE_FUTURES]); + +impl<'tcx> LateLintPass<'tcx> for LargeFuture { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { + if matches!(expr.span.ctxt().outer_expn_data().kind, rustc_span::ExpnKind::Macro(..)) { + return; + } + if let ExprKind::Match(expr, _, MatchSource::AwaitDesugar) = expr.kind { + if let ExprKind::Call(func, [expr, ..]) = expr.kind + && let ExprKind::Path(QPath::LangItem(LangItem::IntoFutureIntoFuture, ..)) = func.kind + && let ty = cx.typeck_results().expr_ty(expr) + && let Some(future_trait_def_id) = cx.tcx.lang_items().future_trait() + && implements_trait(cx, ty, future_trait_def_id, &[]) + && let Ok(layout) = cx.tcx.layout_of(cx.param_env.and(ty)) + && let size = layout.layout.size() + && size >= Size::from_bytes(self.future_size_threshold) + { + span_lint_and_sugg( + cx, + LARGE_FUTURES, + expr.span, + &format!("large future with a size of {} bytes", size.bytes()), + "consider `Box::pin` on it", + format!("Box::pin({})", snippet(cx, expr.span, "..")), + Applicability::Unspecified, + ); + } + } + } +} diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 3da7f95c1b9fe..b0ec14855e71b 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -1,7 +1,6 @@ #![feature(array_windows)] #![feature(binary_heap_into_iter_sorted)] #![feature(box_patterns)] -#![feature(drain_filter)] #![feature(if_let_guard)] #![feature(iter_intersperse)] #![feature(let_chains)] @@ -162,6 +161,7 @@ mod items_after_statements; mod iter_not_returning_iterator; mod large_const_arrays; mod large_enum_variant; +mod large_futures; mod large_include_file; mod large_stack_arrays; mod len_zero; @@ -169,6 +169,7 @@ mod let_if_seq; mod let_underscore; mod let_with_type_underscore; mod lifetimes; +mod lines_filter_map_ok; mod literal_representation; mod loops; mod macro_use; @@ -183,6 +184,7 @@ mod manual_main_separator_str; mod manual_non_exhaustive; mod manual_rem_euclid; mod manual_retain; +mod manual_slice_size_calculation; mod manual_string_new; mod manual_strip; mod map_unit_fn; @@ -281,6 +283,7 @@ mod slow_vector_initialization; mod std_instead_of_core; mod strings; mod strlen_on_c_strings; +mod suspicious_doc_comments; mod suspicious_operation_groupings; mod suspicious_trait_impl; mod suspicious_xor_used_as_pow; @@ -288,6 +291,7 @@ mod swap; mod swap_ptr_to_ref; mod tabs_in_doc_comments; mod temporary_assignment; +mod tests_outside_test_module; mod to_digit_is_some; mod trailing_empty_array; mod trait_bounds; @@ -299,6 +303,7 @@ mod uninit_vec; mod unit_return_expecting_ord; mod unit_types; mod unnamed_address; +mod unnecessary_box_returns; mod unnecessary_owned_empty_strings; mod unnecessary_self_imports; mod unnecessary_struct_initialization; @@ -344,13 +349,17 @@ pub fn register_pre_expansion_lints(store: &mut rustc_lint::LintStore, sess: &Se } #[doc(hidden)] -pub fn read_conf(sess: &Session, path: &io::Result>) -> Conf { +pub fn read_conf(sess: &Session, path: &io::Result<(Option, Vec)>) -> Conf { + if let Ok((_, warnings)) = path { + for warning in warnings { + sess.warn(warning); + } + } let file_name = match path { - Ok(Some(path)) => path, - Ok(None) => return Conf::default(), + Ok((Some(path), _)) => path, + Ok((None, _)) => return Conf::default(), Err(error) => { - sess.struct_err(format!("error finding Clippy's configuration file: {error}")) - .emit(); + sess.err(format!("error finding Clippy's configuration file: {error}")); return Conf::default(); }, }; @@ -746,7 +755,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_early_pass(|| Box::new(unused_unit::UnusedUnit)); store.register_late_pass(|_| Box::new(returns::Return)); store.register_early_pass(|| Box::new(collapsible_if::CollapsibleIf)); - store.register_early_pass(|| Box::new(items_after_statements::ItemsAfterStatements)); + store.register_late_pass(|_| Box::new(items_after_statements::ItemsAfterStatements)); store.register_early_pass(|| Box::new(precedence::Precedence)); store.register_late_pass(|_| Box::new(needless_parens_on_range_literals::NeedlessParensOnRangeLiterals)); store.register_early_pass(|| Box::new(needless_continue::NeedlessContinue)); @@ -808,6 +817,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(move |_| Box::new(dereference::Dereferencing::new(msrv()))); store.register_late_pass(|_| Box::new(option_if_let_else::OptionIfLetElse)); store.register_late_pass(|_| Box::new(future_not_send::FutureNotSend)); + let future_size_threshold = conf.future_size_threshold; + store.register_late_pass(move |_| Box::new(large_futures::LargeFuture::new(future_size_threshold))); store.register_late_pass(|_| Box::new(if_let_mutex::IfLetMutex)); store.register_late_pass(|_| Box::new(if_not_else::IfNotElse)); store.register_late_pass(|_| Box::new(equatable_if_let::PatternEquality)); @@ -934,11 +945,20 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|_| Box::new(no_mangle_with_rust_abi::NoMangleWithRustAbi)); store.register_late_pass(|_| Box::new(collection_is_never_read::CollectionIsNeverRead)); 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(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)); + store.register_late_pass(move |_| { + Box::new(unnecessary_box_returns::UnnecessaryBoxReturns::new( + avoid_breaking_exported_api, + )) + }); + store.register_late_pass(|_| Box::new(lines_filter_map_ok::LinesFilterMapOk)); + store.register_late_pass(|_| Box::new(tests_outside_test_module::TestsOutsideTestModule)); + store.register_late_pass(|_| Box::new(manual_slice_size_calculation::ManualSliceSizeCalculation)); + store.register_early_pass(|| Box::new(suspicious_doc_comments::SuspiciousDocComments)); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/clippy_lints/src/lines_filter_map_ok.rs b/clippy_lints/src/lines_filter_map_ok.rs new file mode 100644 index 0000000000000..b0f9276475d3e --- /dev/null +++ b/clippy_lints/src/lines_filter_map_ok.rs @@ -0,0 +1,100 @@ +use clippy_utils::{ + diagnostics::span_lint_and_then, is_diag_item_method, is_trait_method, match_def_path, path_to_local_id, paths, + ty::match_type, +}; +use rustc_errors::Applicability; +use rustc_hir::{Body, Closure, Expr, ExprKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::sym; + +declare_clippy_lint! { + /// ### What it does + /// Detect uses of `lines.filter_map(Result::ok)` or `lines.flat_map(Result::ok)` + /// when `lines` has type `std::io::Lines`. + /// + /// ### Why is this bad? + /// `Lines` instances might produce a never-ending stream of `Err`, in which case + /// `filter_map(Result::ok)` will enter an infinite loop while waiting for an + /// `Ok` variant. Calling `next()` once is sufficient to enter the infinite loop, + /// even in the absence of explicit loops in the user code. + /// + /// This situation can arise when working with user-provided paths. On some platforms, + /// `std::fs::File::open(path)` might return `Ok(fs)` even when `path` is a directory, + /// but any later attempt to read from `fs` will return an error. + /// + /// ### Known problems + /// This lint suggests replacing `filter_map()` or `flat_map()` applied to a `Lines` + /// instance in all cases. There two cases where the suggestion might not be + /// appropriate or necessary: + /// + /// - If the `Lines` instance can never produce any error, or if an error is produced + /// only once just before terminating the iterator, using `map_while()` is not + /// necessary but will not do any harm. + /// - If the `Lines` instance can produce intermittent errors then recover and produce + /// successful results, using `map_while()` would stop at the first error. + /// + /// ### Example + /// ```rust + /// # use std::{fs::File, io::{self, BufRead, BufReader}}; + /// # let _ = || -> io::Result<()> { + /// let mut lines = BufReader::new(File::open("some-path")?).lines().filter_map(Result::ok); + /// // If "some-path" points to a directory, the next statement never terminates: + /// let first_line: Option = lines.next(); + /// # Ok(()) }; + /// ``` + /// Use instead: + /// ```rust + /// # use std::{fs::File, io::{self, BufRead, BufReader}}; + /// # let _ = || -> io::Result<()> { + /// let mut lines = BufReader::new(File::open("some-path")?).lines().map_while(Result::ok); + /// let first_line: Option = lines.next(); + /// # Ok(()) }; + /// ``` + #[clippy::version = "1.70.0"] + pub LINES_FILTER_MAP_OK, + suspicious, + "filtering `std::io::Lines` with `filter_map()` or `flat_map()` might cause an infinite loop" +} +declare_lint_pass!(LinesFilterMapOk => [LINES_FILTER_MAP_OK]); + +impl LateLintPass<'_> for LinesFilterMapOk { + fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { + if let ExprKind::MethodCall(fm_method, fm_receiver, [fm_arg], fm_span) = expr.kind && + is_trait_method(cx, expr, sym::Iterator) && + (fm_method.ident.as_str() == "filter_map" || fm_method.ident.as_str() == "flat_map") && + match_type(cx, cx.typeck_results().expr_ty_adjusted(fm_receiver), &paths::STD_IO_LINES) + { + let lint = match &fm_arg.kind { + // Detect `Result::ok` + ExprKind::Path(qpath) => + cx.qpath_res(qpath, fm_arg.hir_id).opt_def_id().map(|did| + match_def_path(cx, did, &paths::CORE_RESULT_OK_METHOD)).unwrap_or_default(), + // Detect `|x| x.ok()` + ExprKind::Closure(Closure { body, .. }) => + if let Body { params: [param], value, .. } = cx.tcx.hir().body(*body) && + let ExprKind::MethodCall(method, receiver, [], _) = value.kind && + path_to_local_id(receiver, param.pat.hir_id) && + let Some(method_did) = cx.typeck_results().type_dependent_def_id(value.hir_id) + { + is_diag_item_method(cx, method_did, sym::Result) && method.ident.as_str() == "ok" + } else { + false + } + _ => false, + }; + if lint { + span_lint_and_then(cx, + LINES_FILTER_MAP_OK, + fm_span, + &format!("`{}()` will run forever if the iterator repeatedly produces an `Err`", fm_method.ident), + |diag| { + diag.span_note( + fm_receiver.span, + "this expression returning a `std::io::Lines` may produce an infinite number of `Err` in case of a read error"); + diag.span_suggestion(fm_span, "replace with", "map_while(Result::ok)", Applicability::MaybeIncorrect); + }); + } + } + } +} diff --git a/clippy_lints/src/manual_slice_size_calculation.rs b/clippy_lints/src/manual_slice_size_calculation.rs new file mode 100644 index 0000000000000..92ee79453a3b8 --- /dev/null +++ b/clippy_lints/src/manual_slice_size_calculation.rs @@ -0,0 +1,93 @@ +use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::{expr_or_init, in_constant}; +use rustc_hir::{BinOpKind, Expr, ExprKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::symbol::sym; + +declare_clippy_lint! { + /// ### What it does + /// When `a` is `&[T]`, detect `a.len() * size_of::()` and suggest `size_of_val(a)` + /// instead. + /// + /// ### Why is this better? + /// * Shorter to write + /// * Removes the need for the human and the compiler to worry about overflow in the + /// multiplication + /// * Potentially faster at runtime as rust emits special no-wrapping flags when it + /// calculates the byte length + /// * Less turbofishing + /// + /// ### Example + /// ```rust + /// # let data : &[i32] = &[1, 2, 3]; + /// let newlen = data.len() * std::mem::size_of::(); + /// ``` + /// Use instead: + /// ```rust + /// # let data : &[i32] = &[1, 2, 3]; + /// let newlen = std::mem::size_of_val(data); + /// ``` + #[clippy::version = "1.70.0"] + pub MANUAL_SLICE_SIZE_CALCULATION, + complexity, + "manual slice size calculation" +} +declare_lint_pass!(ManualSliceSizeCalculation => [MANUAL_SLICE_SIZE_CALCULATION]); + +impl<'tcx> LateLintPass<'tcx> for ManualSliceSizeCalculation { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { + // Does not apply inside const because size_of_value is not cost in stable. + if !in_constant(cx, expr.hir_id) + && let ExprKind::Binary(ref op, left, right) = expr.kind + && BinOpKind::Mul == op.node + && let Some(_receiver) = simplify(cx, left, right) + { + span_lint_and_help( + cx, + MANUAL_SLICE_SIZE_CALCULATION, + expr.span, + "manual slice size calculation", + None, + "consider using std::mem::size_of_value instead"); + } + } +} + +fn simplify<'tcx>( + cx: &LateContext<'tcx>, + expr1: &'tcx Expr<'tcx>, + expr2: &'tcx Expr<'tcx>, +) -> Option<&'tcx Expr<'tcx>> { + let expr1 = expr_or_init(cx, expr1); + let expr2 = expr_or_init(cx, expr2); + + simplify_half(cx, expr1, expr2).or_else(|| simplify_half(cx, expr2, expr1)) +} + +fn simplify_half<'tcx>( + cx: &LateContext<'tcx>, + expr1: &'tcx Expr<'tcx>, + expr2: &'tcx Expr<'tcx>, +) -> Option<&'tcx Expr<'tcx>> { + if + // expr1 is `[T1].len()`? + let ExprKind::MethodCall(method_path, receiver, _, _) = expr1.kind + && method_path.ident.name == sym::len + && let receiver_ty = cx.typeck_results().expr_ty(receiver) + && let ty::Slice(ty1) = receiver_ty.peel_refs().kind() + // expr2 is `size_of::()`? + && let ExprKind::Call(func, _) = expr2.kind + && let ExprKind::Path(ref func_qpath) = func.kind + && let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id() + && cx.tcx.is_diagnostic_item(sym::mem_size_of, def_id) + && let Some(ty2) = cx.typeck_results().node_substs(func.hir_id).types().next() + // T1 == T2? + && *ty1 == ty2 + { + Some(receiver) + } else { + None + } +} diff --git a/clippy_lints/src/mem_replace.rs b/clippy_lints/src/mem_replace.rs index 35024ec1224f0..8a921d4af1655 100644 --- a/clippy_lints/src/mem_replace.rs +++ b/clippy_lints/src/mem_replace.rs @@ -1,12 +1,13 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg, span_lint_and_then}; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::{snippet, snippet_with_applicability}; +use clippy_utils::sugg::Sugg; use clippy_utils::ty::is_non_aggregate_primitive_type; -use clippy_utils::{is_default_equivalent, is_res_lang_ctor, path_res}; +use clippy_utils::{is_default_equivalent, is_res_lang_ctor, path_res, peel_ref_operators}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::LangItem::OptionNone; -use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, QPath}; +use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_tool_lint, impl_lint_pass}; @@ -101,40 +102,26 @@ declare_clippy_lint! { impl_lint_pass!(MemReplace => [MEM_REPLACE_OPTION_WITH_NONE, MEM_REPLACE_WITH_UNINIT, MEM_REPLACE_WITH_DEFAULT]); -fn check_replace_option_with_none(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr<'_>, expr_span: Span) { - // Check that second argument is `Option::None` - if is_res_lang_ctor(cx, path_res(cx, src), OptionNone) { - // Since this is a late pass (already type-checked), - // and we already know that the second argument is an - // `Option`, we do not need to check the first - // argument's type. All that's left is to get - // replacee's path. - let replaced_path = match dest.kind { - ExprKind::AddrOf(BorrowKind::Ref, Mutability::Mut, replaced) => { - if let ExprKind::Path(QPath::Resolved(None, replaced_path)) = replaced.kind { - replaced_path - } else { - return; - } - }, - ExprKind::Path(QPath::Resolved(None, replaced_path)) => replaced_path, - _ => return, - }; - - let mut applicability = Applicability::MachineApplicable; - span_lint_and_sugg( - cx, - MEM_REPLACE_OPTION_WITH_NONE, - expr_span, - "replacing an `Option` with `None`", - "consider `Option::take()` instead", - format!( - "{}.take()", - snippet_with_applicability(cx, replaced_path.span, "", &mut applicability) - ), - applicability, - ); - } +fn check_replace_option_with_none(cx: &LateContext<'_>, dest: &Expr<'_>, expr_span: Span) { + // Since this is a late pass (already type-checked), + // and we already know that the second argument is an + // `Option`, we do not need to check the first + // argument's type. All that's left is to get + // the replacee's expr after peeling off the `&mut` + let sugg_expr = peel_ref_operators(cx, dest); + let mut applicability = Applicability::MachineApplicable; + span_lint_and_sugg( + cx, + MEM_REPLACE_OPTION_WITH_NONE, + expr_span, + "replacing an `Option` with `None`", + "consider `Option::take()` instead", + format!( + "{}.take()", + Sugg::hir_with_context(cx, sugg_expr, expr_span.ctxt(), "", &mut applicability).maybe_par() + ), + applicability, + ); } fn check_replace_with_uninit(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr<'_>, expr_span: Span) { @@ -200,10 +187,6 @@ fn check_replace_with_default(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr< if is_non_aggregate_primitive_type(expr_type) { return; } - // disable lint for Option since it is covered in another lint - if is_res_lang_ctor(cx, path_res(cx, src), OptionNone) { - return; - } if is_default_equivalent(cx, src) && !in_external_macro(cx.tcx.sess, expr_span) { span_lint_and_then( cx, @@ -246,11 +229,13 @@ impl<'tcx> LateLintPass<'tcx> for MemReplace { if let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id(); if cx.tcx.is_diagnostic_item(sym::mem_replace, def_id); then { - check_replace_option_with_none(cx, src, dest, expr.span); - check_replace_with_uninit(cx, src, dest, expr.span); - if self.msrv.meets(msrvs::MEM_TAKE) { + // Check that second argument is `Option::None` + if is_res_lang_ctor(cx, path_res(cx, src), OptionNone) { + check_replace_option_with_none(cx, dest, expr.span); + } else if self.msrv.meets(msrvs::MEM_TAKE) { check_replace_with_default(cx, src, dest, expr.span); } + check_replace_with_uninit(cx, src, dest, expr.span); } } } diff --git a/clippy_lints/src/methods/clear_with_drain.rs b/clippy_lints/src/methods/clear_with_drain.rs new file mode 100644 index 0000000000000..67ad58d5a8c64 --- /dev/null +++ b/clippy_lints/src/methods/clear_with_drain.rs @@ -0,0 +1,53 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::is_range_full; +use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item}; +use rustc_errors::Applicability; +use rustc_hir as hir; +use rustc_hir::{Expr, ExprKind, LangItem, QPath}; +use rustc_lint::LateContext; +use rustc_span::symbol::sym; +use rustc_span::Span; + +use super::CLEAR_WITH_DRAIN; + +// Add `String` here when it is added to diagnostic items +const ACCEPTABLE_TYPES_WITH_ARG: [rustc_span::Symbol; 2] = [sym::Vec, sym::VecDeque]; + +const ACCEPTABLE_TYPES_WITHOUT_ARG: [rustc_span::Symbol; 3] = [sym::BinaryHeap, sym::HashMap, sym::HashSet]; + +pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span: Span, arg: Option<&Expr<'_>>) { + if let Some(arg) = arg { + if match_acceptable_type(cx, recv, &ACCEPTABLE_TYPES_WITH_ARG) + && let ExprKind::Path(QPath::Resolved(None, container_path)) = recv.kind + && is_range_full(cx, arg, Some(container_path)) + { + suggest(cx, expr, recv, span); + } + } else if match_acceptable_type(cx, recv, &ACCEPTABLE_TYPES_WITHOUT_ARG) { + suggest(cx, expr, recv, span); + } +} + +fn match_acceptable_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>, types: &[rustc_span::Symbol]) -> bool { + let expr_ty = cx.typeck_results().expr_ty(expr).peel_refs(); + types.iter().any(|&ty| is_type_diagnostic_item(cx, expr_ty, ty)) + // String type is a lang item but not a diagnostic item for now so we need a separate check + || is_type_lang_item(cx, expr_ty, LangItem::String) +} + +fn suggest(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span: Span) { + if let Some(adt) = cx.typeck_results().expr_ty(recv).ty_adt_def() + // Use `opt_item_name` while `String` is not a diagnostic item + && let Some(ty_name) = cx.tcx.opt_item_name(adt.did()) + { + span_lint_and_sugg( + cx, + CLEAR_WITH_DRAIN, + span.with_hi(expr.span.hi()), + &format!("`drain` used to clear a `{ty_name}`"), + "try", + "clear()".to_string(), + Applicability::MachineApplicable, + ); + } +} diff --git a/clippy_lints/src/methods/expect_fun_call.rs b/clippy_lints/src/methods/expect_fun_call.rs index a22285058d48e..92d21bb893262 100644 --- a/clippy_lints/src/methods/expect_fun_call.rs +++ b/clippy_lints/src/methods/expect_fun_call.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::macros::{root_macro_call_first_node, FormatArgsExpn}; +use clippy_utils::macros::{find_format_args, format_args_inputs_span, root_macro_call_first_node}; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item}; use rustc_errors::Applicability; @@ -136,18 +136,19 @@ pub(super) fn check<'tcx>( if !cx.tcx.is_diagnostic_item(sym::format_macro, macro_call.def_id) { return; } - let Some(format_args) = FormatArgsExpn::find_nested(cx, arg_root, macro_call.expn) else { return }; - let span = format_args.inputs_span(); - let sugg = snippet_with_applicability(cx, span, "..", &mut applicability); - span_lint_and_sugg( - cx, - EXPECT_FUN_CALL, - span_replace_word, - &format!("use of `{name}` followed by a function call"), - "try this", - format!("unwrap_or_else({closure_args} panic!({sugg}))"), - applicability, - ); + find_format_args(cx, arg_root, macro_call.expn, |format_args| { + let span = format_args_inputs_span(format_args); + let sugg = snippet_with_applicability(cx, span, "..", &mut applicability); + span_lint_and_sugg( + cx, + EXPECT_FUN_CALL, + span_replace_word, + &format!("use of `{name}` followed by a function call"), + "try this", + format!("unwrap_or_else({closure_args} panic!({sugg}))"), + applicability, + ); + }); return; } diff --git a/clippy_lints/src/methods/iter_with_drain.rs b/clippy_lints/src/methods/iter_with_drain.rs index 3da230e12d7fe..f6772c5c6b369 100644 --- a/clippy_lints/src/methods/iter_with_drain.rs +++ b/clippy_lints/src/methods/iter_with_drain.rs @@ -1,7 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::higher::Range; -use clippy_utils::is_integer_const; -use rustc_ast::ast::RangeLimits; +use clippy_utils::is_range_full; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, QPath}; use rustc_lint::LateContext; @@ -15,8 +13,8 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span && let Some(adt) = cx.typeck_results().expr_ty(recv).ty_adt_def() && let Some(ty_name) = cx.tcx.get_diagnostic_name(adt.did()) && matches!(ty_name, sym::Vec | sym::VecDeque) - && let Some(range) = Range::hir(arg) - && is_full_range(cx, recv, range) + && let ExprKind::Path(QPath::Resolved(None, container_path)) = recv.kind + && is_range_full(cx, arg, Some(container_path)) { span_lint_and_sugg( cx, @@ -29,19 +27,3 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span ); }; } - -fn is_full_range(cx: &LateContext<'_>, container: &Expr<'_>, range: Range<'_>) -> bool { - range.start.map_or(true, |e| is_integer_const(cx, e, 0)) - && range.end.map_or(true, |e| { - if range.limits == RangeLimits::HalfOpen - && let ExprKind::Path(QPath::Resolved(None, container_path)) = container.kind - && let ExprKind::MethodCall(name, self_arg, [], _) = e.kind - && name.ident.name == sym::len - && let ExprKind::Path(QPath::Resolved(None, path)) = self_arg.kind - { - container_path.res == path.res - } else { - false - } - }) -} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 56e3988bf097b..64bf55ba24c98 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -9,6 +9,7 @@ mod chars_last_cmp; mod chars_last_cmp_with_unwrap; mod chars_next_cmp; mod chars_next_cmp_with_unwrap; +mod clear_with_drain; mod clone_on_copy; mod clone_on_ref_ptr; mod cloned_instead_of_copied; @@ -110,7 +111,7 @@ use clippy_utils::ty::{contains_ty_adt_constructor_opaque, implements_trait, is_ use clippy_utils::{contains_return, is_bool, is_trait_method, iter_input_pats, return_ty}; use if_chain::if_chain; use rustc_hir as hir; -use rustc_hir::{Expr, ExprKind, TraitItem, TraitItemKind}; +use rustc_hir::{Expr, ExprKind, Node, Stmt, StmtKind, TraitItem, TraitItemKind}; use rustc_hir_analysis::hir_ty_to_ty; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; @@ -3190,6 +3191,31 @@ declare_clippy_lint! { "single command line argument that looks like it should be multiple arguments" } +declare_clippy_lint! { + /// ### What it does + /// Checks for usage of `.drain(..)` for the sole purpose of clearing a container. + /// + /// ### Why is this bad? + /// This creates an unnecessary iterator that is dropped immediately. + /// + /// Calling `.clear()` also makes the intent clearer. + /// + /// ### Example + /// ```rust + /// let mut v = vec![1, 2, 3]; + /// v.drain(..); + /// ``` + /// Use instead: + /// ```rust + /// let mut v = vec![1, 2, 3]; + /// v.clear(); + /// ``` + #[clippy::version = "1.69.0"] + pub CLEAR_WITH_DRAIN, + nursery, + "calling `drain` in order to `clear` a container" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Msrv, @@ -3318,6 +3344,7 @@ impl_lint_pass!(Methods => [ SEEK_TO_START_INSTEAD_OF_REWIND, NEEDLESS_COLLECT, SUSPICIOUS_COMMAND_ARG_SPACE, + CLEAR_WITH_DRAIN, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -3562,8 +3589,15 @@ impl Methods { Some(("bytes", recv2, [], _, _)) => bytes_count_to_len::check(cx, expr, recv, recv2), _ => {}, }, - ("drain", [arg]) => { - iter_with_drain::check(cx, expr, recv, span, arg); + ("drain", ..) => { + if let Node::Stmt(Stmt { hir_id: _, kind, .. }) = cx.tcx.hir().get_parent(expr.hir_id) + && matches!(kind, StmtKind::Semi(_)) + && args.len() <= 1 + { + clear_with_drain::check(cx, expr, recv, span, args.first()); + } else if let [arg] = args { + iter_with_drain::check(cx, expr, recv, span, arg); + } }, ("ends_with", [arg]) => { if let ExprKind::MethodCall(.., span) = expr.kind { diff --git a/clippy_lints/src/missing_const_for_fn.rs b/clippy_lints/src/missing_const_for_fn.rs index 87bd007a26a24..f1831a30461af 100644 --- a/clippy_lints/src/missing_const_for_fn.rs +++ b/clippy_lints/src/missing_const_for_fn.rs @@ -41,6 +41,7 @@ declare_clippy_lint! { /// can't be const as it calls a non-const function. Making `a` const and running Clippy again, /// will suggest to make `b` const, too. /// + /// If you are marking a public function with `const`, removing it again will break API compatibility. /// ### Example /// ```rust /// # struct Foo { diff --git a/clippy_lints/src/operators/arithmetic_side_effects.rs b/clippy_lints/src/operators/arithmetic_side_effects.rs index 25e8de9486370..e5713735672da 100644 --- a/clippy_lints/src/operators/arithmetic_side_effects.rs +++ b/clippy_lints/src/operators/arithmetic_side_effects.rs @@ -154,10 +154,18 @@ impl ArithmeticSideEffects { Self::literal_integer(cx, actual_rhs), ) { (None, None) => false, - (None, Some(n)) | (Some(n), None) => match (&op.node, n) { + (None, Some(n)) => match (&op.node, n) { // Division and module are always valid if applied to non-zero integers (hir::BinOpKind::Div | hir::BinOpKind::Rem, local_n) if local_n != 0 => true, - // Addition or subtracting zeros is always a no-op + // Adding or subtracting zeros is always a no-op + (hir::BinOpKind::Add | hir::BinOpKind::Sub, 0) + // Multiplication by 1 or 0 will never overflow + | (hir::BinOpKind::Mul, 0 | 1) + => true, + _ => false, + }, + (Some(n), None) => match (&op.node, n) { + // Adding or subtracting zeros is always a no-op (hir::BinOpKind::Add | hir::BinOpKind::Sub, 0) // Multiplication by 1 or 0 will never overflow | (hir::BinOpKind::Mul, 0 | 1) diff --git a/clippy_lints/src/redundant_async_block.rs b/clippy_lints/src/redundant_async_block.rs index 5ac203665d0c0..a0f831764d071 100644 --- a/clippy_lints/src/redundant_async_block.rs +++ b/clippy_lints/src/redundant_async_block.rs @@ -1,8 +1,15 @@ -use clippy_utils::{diagnostics::span_lint_and_sugg, source::snippet}; -use rustc_ast::ast::{Expr, ExprKind, Stmt, StmtKind}; -use rustc_ast::visit::Visitor as AstVisitor; +use std::ops::ControlFlow; + +use clippy_utils::{ + diagnostics::span_lint_and_sugg, + peel_blocks, + source::{snippet, walk_span_to_context}, + visitors::for_each_expr, +}; use rustc_errors::Applicability; -use rustc_lint::{EarlyContext, EarlyLintPass}; +use rustc_hir::{AsyncGeneratorKind, Closure, Expr, ExprKind, GeneratorKind, MatchSource}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::{lint::in_external_macro, ty::UpvarCapture}; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { @@ -14,106 +21,88 @@ declare_clippy_lint! { /// /// ### Example /// ```rust - /// async fn f() -> i32 { - /// 1 + 2 - /// } - /// + /// let f = async { + /// 1 + 2 + /// }; /// let fut = async { - /// f().await + /// f.await /// }; /// ``` /// Use instead: /// ```rust - /// async fn f() -> i32 { - /// 1 + 2 - /// } - /// - /// let fut = f(); + /// let f = async { + /// 1 + 2 + /// }; + /// let fut = f; /// ``` #[clippy::version = "1.69.0"] pub REDUNDANT_ASYNC_BLOCK, - nursery, + complexity, "`async { future.await }` can be replaced by `future`" } declare_lint_pass!(RedundantAsyncBlock => [REDUNDANT_ASYNC_BLOCK]); -impl EarlyLintPass for RedundantAsyncBlock { - fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { - if expr.span.from_expansion() { - return; - } - if let ExprKind::Async(_, block) = &expr.kind && block.stmts.len() == 1 && - let Some(Stmt { kind: StmtKind::Expr(last), .. }) = block.stmts.last() && - let ExprKind::Await(future) = &last.kind && - !future.span.from_expansion() && - !await_in_expr(future) +impl<'tcx> LateLintPass<'tcx> for RedundantAsyncBlock { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { + let span = expr.span; + if !in_external_macro(cx.tcx.sess, span) && + let Some(body_expr) = desugar_async_block(cx, expr) && + let Some(expr) = desugar_await(peel_blocks(body_expr)) && + // The await prefix must not come from a macro as its content could change in the future. + expr.span.ctxt() == body_expr.span.ctxt() && + // An async block does not have immediate side-effects from a `.await` point-of-view. + (!expr.can_have_side_effects() || desugar_async_block(cx, expr).is_some()) && + let Some(shortened_span) = walk_span_to_context(expr.span, span.ctxt()) { - if captures_value(last) { - // If the async block captures variables then there is no equivalence. - return; - } - span_lint_and_sugg( cx, REDUNDANT_ASYNC_BLOCK, - expr.span, + span, "this async expression only awaits a single future", "you can reduce it to", - snippet(cx, future.span, "..").into_owned(), + snippet(cx, shortened_span, "..").into_owned(), Applicability::MachineApplicable, ); } } } -/// Check whether an expression contains `.await` -fn await_in_expr(expr: &Expr) -> bool { - let mut detector = AwaitDetector::default(); - detector.visit_expr(expr); - detector.await_found -} - -#[derive(Default)] -struct AwaitDetector { - await_found: bool, -} - -impl<'ast> AstVisitor<'ast> for AwaitDetector { - fn visit_expr(&mut self, ex: &'ast Expr) { - match (&ex.kind, self.await_found) { - (ExprKind::Await(_), _) => self.await_found = true, - (_, false) => rustc_ast::visit::walk_expr(self, ex), - _ => (), - } +/// If `expr` is a desugared `async` block, return the original expression if it does not capture +/// any variable by ref. +fn desugar_async_block<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> { + if let ExprKind::Closure(Closure { body, def_id, .. }) = expr.kind && + let body = cx.tcx.hir().body(*body) && + matches!(body.generator_kind, Some(GeneratorKind::Async(AsyncGeneratorKind::Block))) + { + cx + .typeck_results() + .closure_min_captures + .get(def_id) + .map_or(true, |m| { + m.values().all(|places| { + places + .iter() + .all(|place| matches!(place.info.capture_kind, UpvarCapture::ByValue)) + }) + }) + .then_some(body.value) + } else { + None } } -/// 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), - _ => (), - } +/// If `expr` is a desugared `.await`, return the original expression if it does not come from a +/// macro expansion. +fn desugar_await<'tcx>(expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> { + if let ExprKind::Match(match_value, _, MatchSource::AwaitDesugar) = expr.kind && + let ExprKind::Call(_, [into_future_arg]) = match_value.kind && + let ctxt = expr.span.ctxt() && + for_each_expr(into_future_arg, |e| + walk_span_to_context(e.span, ctxt) + .map_or(ControlFlow::Break(()), |_| ControlFlow::Continue(()))).is_none() + { + Some(into_future_arg) + } else { + None } } diff --git a/clippy_lints/src/redundant_static_lifetimes.rs b/clippy_lints/src/redundant_static_lifetimes.rs index 11b908e7e53d1..038dfe8e4803c 100644 --- a/clippy_lints/src/redundant_static_lifetimes.rs +++ b/clippy_lints/src/redundant_static_lifetimes.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet; -use rustc_ast::ast::{Item, ItemKind, Ty, TyKind, StaticItem, ConstItem}; +use rustc_ast::ast::{ConstItem, Item, ItemKind, StaticItem, Ty, TyKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; @@ -106,7 +106,7 @@ impl EarlyLintPass for RedundantStaticLifetimes { // #2438) } - if let ItemKind::Static(box StaticItem { ty: ref var_type,.. }) = item.kind { + if let ItemKind::Static(box StaticItem { ty: ref var_type, .. }) = item.kind { Self::visit_type(var_type, cx, "statics have by default a `'static` lifetime"); } } diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs index f0d7dd23a6786..df126d7617ebe 100644 --- a/clippy_lints/src/returns.rs +++ b/clippy_lints/src/returns.rs @@ -9,7 +9,7 @@ use rustc_hir::intravisit::FnKind; use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, LangItem, MatchSource, PatKind, QPath, StmtKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_middle::ty::subst::GenericArgKind; +use rustc_middle::ty::{self, subst::GenericArgKind, Ty}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::def_id::LocalDefId; use rustc_span::source_map::Span; @@ -175,7 +175,7 @@ impl<'tcx> LateLintPass<'tcx> for Return { } else { RetReplacement::Empty }; - check_final_expr(cx, body.value, vec![], replacement); + check_final_expr(cx, body.value, vec![], replacement, None); }, FnKind::ItemFn(..) | FnKind::Method(..) => { check_block_return(cx, &body.value.kind, sp, vec![]); @@ -188,11 +188,11 @@ impl<'tcx> LateLintPass<'tcx> for Return { fn check_block_return<'tcx>(cx: &LateContext<'tcx>, expr_kind: &ExprKind<'tcx>, sp: Span, mut semi_spans: Vec) { if let ExprKind::Block(block, _) = expr_kind { if let Some(block_expr) = block.expr { - check_final_expr(cx, block_expr, semi_spans, RetReplacement::Empty); + check_final_expr(cx, block_expr, semi_spans, RetReplacement::Empty, None); } else if let Some(stmt) = block.stmts.iter().last() { match stmt.kind { StmtKind::Expr(expr) => { - check_final_expr(cx, expr, semi_spans, RetReplacement::Empty); + check_final_expr(cx, expr, semi_spans, RetReplacement::Empty, None); }, StmtKind::Semi(semi_expr) => { // Remove ending semicolons and any whitespace ' ' in between. @@ -202,7 +202,7 @@ fn check_block_return<'tcx>(cx: &LateContext<'tcx>, expr_kind: &ExprKind<'tcx>, span_find_starting_semi(cx.sess().source_map(), semi_span.with_hi(sp.hi())); semi_spans.push(semi_span_to_remove); } - check_final_expr(cx, semi_expr, semi_spans, RetReplacement::Empty); + check_final_expr(cx, semi_expr, semi_spans, RetReplacement::Empty, None); }, _ => (), } @@ -216,6 +216,7 @@ fn check_final_expr<'tcx>( semi_spans: Vec, /* containing all the places where we would need to remove semicolons if finding an * needless return */ replacement: RetReplacement<'tcx>, + match_ty_opt: Option>, ) { let peeled_drop_expr = expr.peel_drop_temps(); match &peeled_drop_expr.kind { @@ -244,7 +245,22 @@ fn check_final_expr<'tcx>( RetReplacement::Expr(snippet, applicability) } } else { - replacement + match match_ty_opt { + Some(match_ty) => { + match match_ty.kind() { + // If the code got till here with + // tuple not getting detected before it, + // then we are sure it's going to be Unit + // type + ty::Tuple(_) => RetReplacement::Unit, + // We don't want to anything in this case + // cause we can't predict what the user would + // want here + _ => return, + } + }, + None => replacement, + } }; if !cx.tcx.hir().attrs(expr.hir_id).is_empty() { @@ -268,8 +284,9 @@ fn check_final_expr<'tcx>( // note, if without else is going to be a type checking error anyways // (except for unit type functions) so we don't match it ExprKind::Match(_, arms, MatchSource::Normal) => { + let match_ty = cx.typeck_results().expr_ty(peeled_drop_expr); for arm in arms.iter() { - check_final_expr(cx, arm.body, semi_spans.clone(), RetReplacement::Unit); + check_final_expr(cx, arm.body, semi_spans.clone(), RetReplacement::Unit, Some(match_ty)); } }, // if it's a whole block, check it @@ -293,6 +310,7 @@ fn emit_return_lint(cx: &LateContext<'_>, ret_span: Span, semi_spans: Vec, if ret_span.from_expansion() { return; } + let applicability = replacement.applicability().unwrap_or(Applicability::MachineApplicable); let return_replacement = replacement.to_string(); let sugg_help = replacement.sugg_help(); diff --git a/clippy_lints/src/single_component_path_imports.rs b/clippy_lints/src/single_component_path_imports.rs index d46f6a6352c63..5743dd21c2835 100644 --- a/clippy_lints/src/single_component_path_imports.rs +++ b/clippy_lints/src/single_component_path_imports.rs @@ -1,6 +1,7 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg}; use rustc_ast::node_id::{NodeId, NodeMap}; -use rustc_ast::{ptr::P, Crate, Item, ItemKind, MacroDef, ModKind, UseTreeKind}; +use rustc_ast::visit::{walk_expr, Visitor}; +use rustc_ast::{ptr::P, Crate, Expr, ExprKind, Item, ItemKind, MacroDef, ModKind, Ty, TyKind, UseTreeKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_session::{declare_tool_lint, impl_lint_pass}; @@ -55,7 +56,7 @@ impl EarlyLintPass for SingleComponentPathImports { return; } - self.check_mod(cx, &krate.items); + self.check_mod(&krate.items); } fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) { @@ -84,8 +85,43 @@ impl EarlyLintPass for SingleComponentPathImports { } } +#[derive(Default)] +struct ImportUsageVisitor { + // keep track of imports reused with `self` keyword, such as `self::std` in the example below. + // Removing the `use std;` would make this a compile error (#10549) + // ``` + // use std; + // + // fn main() { + // let _ = self::std::io::stdout(); + // } + // ``` + imports_referenced_with_self: Vec, +} + +impl<'tcx> Visitor<'tcx> for ImportUsageVisitor { + fn visit_expr(&mut self, expr: &Expr) { + if let ExprKind::Path(_, path) = &expr.kind + && path.segments.len() > 1 + && path.segments[0].ident.name == kw::SelfLower + { + self.imports_referenced_with_self.push(path.segments[1].ident.name); + } + walk_expr(self, expr); + } + + fn visit_ty(&mut self, ty: &Ty) { + if let TyKind::Path(_, path) = &ty.kind + && path.segments.len() > 1 + && path.segments[0].ident.name == kw::SelfLower + { + self.imports_referenced_with_self.push(path.segments[1].ident.name); + } + } +} + impl SingleComponentPathImports { - fn check_mod(&mut self, cx: &EarlyContext<'_>, items: &[P]) { + fn check_mod(&mut self, items: &[P]) { // keep track of imports reused with `self` keyword, such as `self::crypto_hash` in the example // below. Removing the `use crypto_hash;` would make this a compile error // ``` @@ -108,18 +144,16 @@ impl SingleComponentPathImports { // ``` let mut macros = Vec::new(); + let mut import_usage_visitor = ImportUsageVisitor::default(); for item in items { - self.track_uses( - cx, - item, - &mut imports_reused_with_self, - &mut single_use_usages, - &mut macros, - ); + self.track_uses(item, &mut imports_reused_with_self, &mut single_use_usages, &mut macros); + import_usage_visitor.visit_item(item); } for usage in single_use_usages { - if !imports_reused_with_self.contains(&usage.name) { + if !imports_reused_with_self.contains(&usage.name) + && !import_usage_visitor.imports_referenced_with_self.contains(&usage.name) + { self.found.entry(usage.item_id).or_default().push(usage); } } @@ -127,7 +161,6 @@ impl SingleComponentPathImports { fn track_uses( &mut self, - cx: &EarlyContext<'_>, item: &Item, imports_reused_with_self: &mut Vec, single_use_usages: &mut Vec, @@ -139,7 +172,7 @@ impl SingleComponentPathImports { match &item.kind { ItemKind::Mod(_, ModKind::Loaded(ref items, ..)) => { - self.check_mod(cx, items); + self.check_mod(items); }, ItemKind::MacroDef(MacroDef { macro_rules: true, .. }) => { macros.push(item.ident.name); diff --git a/clippy_lints/src/suspicious_doc_comments.rs b/clippy_lints/src/suspicious_doc_comments.rs new file mode 100644 index 0000000000000..e5746ca99cac1 --- /dev/null +++ b/clippy_lints/src/suspicious_doc_comments.rs @@ -0,0 +1,94 @@ +use clippy_utils::diagnostics::{multispan_sugg_with_applicability, span_lint_and_then}; +use if_chain::if_chain; +use rustc_ast::{token::CommentKind, AttrKind, AttrStyle, Attribute, Item}; +use rustc_errors::Applicability; +use rustc_lint::{EarlyContext, EarlyLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::Span; + +declare_clippy_lint! { + /// ### What it does + /// Detects the use of outer doc comments (`///`, `/**`) followed by a bang (`!`): `///!` + /// + /// ### Why is this bad? + /// Triple-slash comments (known as "outer doc comments") apply to items that follow it. + /// An outer doc comment followed by a bang (i.e. `///!`) has no specific meaning. + /// + /// The user most likely meant to write an inner doc comment (`//!`, `/*!`), which + /// applies to the parent item (i.e. the item that the comment is contained in, + /// usually a module or crate). + /// + /// ### Known problems + /// Inner doc comments can only appear before items, so there are certain cases where the suggestion + /// made by this lint is not valid code. For example: + /// ```rs + /// fn foo() {} + /// ///! + /// fn bar() {} + /// ``` + /// This lint detects the doc comment and suggests changing it to `//!`, but an inner doc comment + /// is not valid at that position. + /// + /// ### Example + /// In this example, the doc comment is attached to the *function*, rather than the *module*. + /// ```rust + /// pub mod util { + /// ///! This module contains utility functions. + /// + /// pub fn dummy() {} + /// } + /// ``` + /// + /// Use instead: + /// ```rust + /// pub mod util { + /// //! This module contains utility functions. + /// + /// pub fn dummy() {} + /// } + /// ``` + #[clippy::version = "1.70.0"] + pub SUSPICIOUS_DOC_COMMENTS, + suspicious, + "suspicious usage of (outer) doc comments" +} +declare_lint_pass!(SuspiciousDocComments => [SUSPICIOUS_DOC_COMMENTS]); + +const WARNING: &str = "this is an outer doc comment and does not apply to the parent module or crate"; +const HELP: &str = "use an inner doc comment to document the parent module or crate"; + +impl EarlyLintPass for SuspiciousDocComments { + fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) { + let replacements = collect_doc_comment_replacements(&item.attrs); + + if let Some(((lo_span, _), (hi_span, _))) = replacements.first().zip(replacements.last()) { + let span = lo_span.to(*hi_span); + + span_lint_and_then(cx, SUSPICIOUS_DOC_COMMENTS, span, WARNING, |diag| { + multispan_sugg_with_applicability(diag, HELP, Applicability::MaybeIncorrect, replacements); + }); + } + } +} + +fn collect_doc_comment_replacements(attrs: &[Attribute]) -> Vec<(Span, String)> { + attrs + .iter() + .filter_map(|attr| { + if_chain! { + if let AttrKind::DocComment(com_kind, sym) = attr.kind; + if let AttrStyle::Outer = attr.style; + if let Some(com) = sym.as_str().strip_prefix('!'); + then { + let sugg = match com_kind { + CommentKind::Line => format!("//!{com}"), + CommentKind::Block => format!("/*!{com}*/") + }; + Some((attr.span, sugg)) + } else { + None + } + } + }) + .collect() +} diff --git a/clippy_lints/src/tests_outside_test_module.rs b/clippy_lints/src/tests_outside_test_module.rs new file mode 100644 index 0000000000000..0a0a77082e02f --- /dev/null +++ b/clippy_lints/src/tests_outside_test_module.rs @@ -0,0 +1,71 @@ +use clippy_utils::{diagnostics::span_lint_and_note, is_in_cfg_test, is_in_test_function}; +use rustc_hir::{intravisit::FnKind, Body, FnDecl}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::{def_id::LocalDefId, Span}; + +declare_clippy_lint! { + /// ### What it does + /// Triggers when a testing function (marked with the `#[test]` attribute) isn't inside a testing module + /// (marked with `#[cfg(test)]`). + /// ### Why is this bad? + /// The idiomatic (and more performant) way of writing tests is inside a testing module (flagged with `#[cfg(test)]`), + /// having test functions outside of this module is confusing and may lead to them being "hidden". + /// ### Example + /// ```rust + /// #[test] + /// fn my_cool_test() { + /// // [...] + /// } + /// + /// #[cfg(test)] + /// mod tests { + /// // [...] + /// } + /// + /// ``` + /// Use instead: + /// ```rust + /// #[cfg(test)] + /// mod tests { + /// #[test] + /// fn my_cool_test() { + /// // [...] + /// } + /// } + /// ``` + #[clippy::version = "1.70.0"] + pub TESTS_OUTSIDE_TEST_MODULE, + restriction, + "A test function is outside the testing module." +} + +declare_lint_pass!(TestsOutsideTestModule => [TESTS_OUTSIDE_TEST_MODULE]); + +impl LateLintPass<'_> for TestsOutsideTestModule { + fn check_fn( + &mut self, + cx: &LateContext<'_>, + kind: FnKind<'_>, + _: &FnDecl<'_>, + body: &Body<'_>, + sp: Span, + _: LocalDefId, + ) { + if_chain! { + if !matches!(kind, FnKind::Closure); + if is_in_test_function(cx.tcx, body.id().hir_id); + if !is_in_cfg_test(cx.tcx, body.id().hir_id); + then { + span_lint_and_note( + cx, + TESTS_OUTSIDE_TEST_MODULE, + sp, + "this function marked with #[test] is outside a #[cfg(test)] module", + None, + "move it to a testing module marked with #[cfg(test)]", + ); + } + } + } +} diff --git a/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs b/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs index 8530b43243fa3..85cd74f23ef7e 100644 --- a/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs +++ b/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs @@ -2,8 +2,9 @@ use super::utils::check_cast; use super::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::sugg::Sugg; +use rustc_ast::ExprPrecedence; use rustc_errors::Applicability; -use rustc_hir::Expr; +use rustc_hir::{Expr, Node}; use rustc_lint::LateContext; use rustc_middle::ty::{cast::CastKind, Ty}; @@ -19,7 +20,7 @@ pub(super) fn check<'tcx>( ) -> bool { use CastKind::{AddrPtrCast, ArrayPtrCast, FnPtrAddrCast, FnPtrPtrCast, PtrAddrCast, PtrPtrCast}; let mut app = Applicability::MachineApplicable; - let sugg = match check_cast(cx, e, from_ty, to_ty) { + let mut sugg = match check_cast(cx, e, from_ty, to_ty) { Some(PtrPtrCast | AddrPtrCast | ArrayPtrCast | FnPtrPtrCast | FnPtrAddrCast) => { Sugg::hir_with_context(cx, arg, e.span.ctxt(), "..", &mut app) .as_ty(to_ty.to_string()) @@ -39,6 +40,12 @@ pub(super) fn check<'tcx>( _ => return false, }; + if let Node::Expr(parent) = cx.tcx.hir().get_parent(e.hir_id) + && parent.precedence().order() > ExprPrecedence::Cast.order() + { + sugg = format!("({sugg})"); + } + span_lint_and_sugg( cx, TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS, diff --git a/clippy_lints/src/unnecessary_box_returns.rs b/clippy_lints/src/unnecessary_box_returns.rs new file mode 100644 index 0000000000000..912bcda630b83 --- /dev/null +++ b/clippy_lints/src/unnecessary_box_returns.rs @@ -0,0 +1,120 @@ +use clippy_utils::diagnostics::span_lint_and_then; +use rustc_errors::Applicability; +use rustc_hir::{def_id::LocalDefId, FnDecl, FnRetTy, ImplItemKind, Item, ItemKind, Node, TraitItem, TraitItemKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_span::Symbol; + +declare_clippy_lint! { + /// ### What it does + /// + /// Checks for a return type containing a `Box` where `T` implements `Sized` + /// + /// ### Why is this bad? + /// + /// It's better to just return `T` in these cases. The caller may not need + /// the value to be boxed, and it's expensive to free the memory once the + /// `Box` been dropped. + /// + /// ### Example + /// ```rust + /// fn foo() -> Box { + /// Box::new(String::from("Hello, world!")) + /// } + /// ``` + /// Use instead: + /// ```rust + /// fn foo() -> String { + /// String::from("Hello, world!") + /// } + /// ``` + #[clippy::version = "1.70.0"] + pub UNNECESSARY_BOX_RETURNS, + pedantic, + "Needlessly returning a Box" +} + +pub struct UnnecessaryBoxReturns { + avoid_breaking_exported_api: bool, +} + +impl_lint_pass!(UnnecessaryBoxReturns => [UNNECESSARY_BOX_RETURNS]); + +impl UnnecessaryBoxReturns { + pub fn new(avoid_breaking_exported_api: bool) -> Self { + Self { + avoid_breaking_exported_api, + } + } + + fn check_fn_item(&mut self, cx: &LateContext<'_>, decl: &FnDecl<'_>, def_id: LocalDefId, name: Symbol) { + // we don't want to tell someone to break an exported function if they ask us not to + if self.avoid_breaking_exported_api && cx.effective_visibilities.is_exported(def_id) { + return; + } + + // functions which contain the word "box" are exempt from this lint + if name.as_str().contains("box") { + return; + } + + let FnRetTy::Return(return_ty_hir) = &decl.output else { return }; + + let return_ty = cx + .tcx + .erase_late_bound_regions(cx.tcx.fn_sig(def_id).skip_binder()) + .output(); + + if !return_ty.is_box() { + return; + } + + let boxed_ty = return_ty.boxed_ty(); + + // it's sometimes useful to return Box if T is unsized, so don't lint those + if boxed_ty.is_sized(cx.tcx, cx.param_env) { + span_lint_and_then( + cx, + UNNECESSARY_BOX_RETURNS, + return_ty_hir.span, + format!("boxed return of the sized type `{boxed_ty}`").as_str(), + |diagnostic| { + diagnostic.span_suggestion( + return_ty_hir.span, + "try", + boxed_ty.to_string(), + // the return value and function callers also needs to + // be changed, so this can't be MachineApplicable + Applicability::Unspecified, + ); + diagnostic.help("changing this also requires a change to the return expressions in this function"); + }, + ); + } + } +} + +impl LateLintPass<'_> for UnnecessaryBoxReturns { + fn check_trait_item(&mut self, cx: &LateContext<'_>, item: &TraitItem<'_>) { + let TraitItemKind::Fn(signature, _) = &item.kind else { return }; + self.check_fn_item(cx, signature.decl, item.owner_id.def_id, item.ident.name); + } + + fn check_impl_item(&mut self, cx: &LateContext<'_>, item: &rustc_hir::ImplItem<'_>) { + // Ignore implementations of traits, because the lint should be on the + // trait, not on the implmentation of it. + let Node::Item(parent) = cx.tcx.hir().get_parent(item.hir_id()) else { return }; + let ItemKind::Impl(parent) = parent.kind else { return }; + if parent.of_trait.is_some() { + return; + } + + let ImplItemKind::Fn(signature, ..) = &item.kind else { return }; + self.check_fn_item(cx, signature.decl, item.owner_id.def_id, item.ident.name); + } + + fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) { + let ItemKind::Fn(signature, ..) = &item.kind else { return }; + self.check_fn_item(cx, signature.decl, item.owner_id.def_id, item.ident.name); + } +} diff --git a/clippy_lints/src/unnecessary_struct_initialization.rs b/clippy_lints/src/unnecessary_struct_initialization.rs index af0b4b1592f4c..084b031982d8c 100644 --- a/clippy_lints/src/unnecessary_struct_initialization.rs +++ b/clippy_lints/src/unnecessary_struct_initialization.rs @@ -9,7 +9,7 @@ declare_clippy_lint! { /// any field. /// /// ### Why is this bad? - /// Readibility suffers from unnecessary struct building. + /// Readability suffers from unnecessary struct building. /// /// ### Example /// ```rust @@ -25,9 +25,13 @@ declare_clippy_lint! { /// let a = S { s: String::from("Hello, world!") }; /// let b = a; /// ``` + /// + /// ### Known Problems + /// Has false positives when the base is a place expression that cannot be + /// moved out of, see [#10547](https://github.com/rust-lang/rust-clippy/issues/10547). #[clippy::version = "1.70.0"] pub UNNECESSARY_STRUCT_INITIALIZATION, - complexity, + nursery, "struct built from a base that can be written mode concisely" } declare_lint_pass!(UnnecessaryStruct => [UNNECESSARY_STRUCT_INITIALIZATION]); diff --git a/clippy_lints/src/use_self.rs b/clippy_lints/src/use_self.rs index 7dfb0956077e4..5a02987453c41 100644 --- a/clippy_lints/src/use_self.rs +++ b/clippy_lints/src/use_self.rs @@ -10,8 +10,8 @@ use rustc_hir::{ def::{CtorOf, DefKind, Res}, def_id::LocalDefId, intravisit::{walk_inf, walk_ty, Visitor}, - Expr, ExprKind, FnRetTy, FnSig, GenericArg, GenericArgsParentheses, GenericParam, GenericParamKind, HirId, Impl, ImplItemKind, Item, - ItemKind, Pat, PatKind, Path, QPath, Ty, TyKind, + 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; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index 8ba252425a3d0..896a01af37d99 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -249,7 +249,7 @@ define_Conf! { /// arithmetic-side-effects-allowed-unary = ["SomeType", "AnotherType"] /// ``` (arithmetic_side_effects_allowed_unary: rustc_data_structures::fx::FxHashSet = <_>::default()), - /// Lint: ENUM_VARIANT_NAMES, LARGE_TYPES_PASSED_BY_VALUE, TRIVIALLY_COPY_PASS_BY_REF, UNNECESSARY_WRAPS, UNUSED_SELF, UPPER_CASE_ACRONYMS, WRONG_SELF_CONVENTION, BOX_COLLECTION, REDUNDANT_ALLOCATION, RC_BUFFER, VEC_BOX, OPTION_OPTION, LINKEDLIST, RC_MUTEX. + /// Lint: ENUM_VARIANT_NAMES, LARGE_TYPES_PASSED_BY_VALUE, TRIVIALLY_COPY_PASS_BY_REF, UNNECESSARY_WRAPS, UNUSED_SELF, UPPER_CASE_ACRONYMS, WRONG_SELF_CONVENTION, BOX_COLLECTION, REDUNDANT_ALLOCATION, RC_BUFFER, VEC_BOX, OPTION_OPTION, LINKEDLIST, RC_MUTEX, UNNECESSARY_BOX_RETURNS. /// /// Suppress lints whenever the suggested change would cause breakage for other crates. (avoid_breaking_exported_api: bool = true), @@ -275,13 +275,13 @@ define_Conf! { /// /// The list of disallowed names to lint about. NB: `bar` is not here since it has legitimate uses. The value /// `".."` can be used as part of the list to indicate, that the configured values should be appended to the - /// default configuration of Clippy. By default any configuration will replace the default value. + /// default configuration of Clippy. By default, any configuration will replace the default value. (disallowed_names: Vec = super::DEFAULT_DISALLOWED_NAMES.iter().map(ToString::to_string).collect()), /// Lint: DOC_MARKDOWN. /// /// The list of words this lint should not consider as identifiers needing ticks. The value /// `".."` can be used as part of the list to indicate, that the configured values should be appended to the - /// default configuration of Clippy. By default any configuraction will replace the default value. For example: + /// default configuration of Clippy. By default, any configuration will replace the default value. For example: /// * `doc-valid-idents = ["ClipPy"]` would replace the default list with `["ClipPy"]`. /// * `doc-valid-idents = ["ClipPy", ".."]` would append `ClipPy` to the default list. /// @@ -390,7 +390,7 @@ define_Conf! { /// Enforce the named macros always use the braces specified. /// /// A `MacroMatcher` can be added like so `{ name = "macro_name", brace = "(" }`. If the macro - /// is could be used with a full path two `MacroMatcher`s have to be added one with the full path + /// could be used with a full path two `MacroMatcher`s have to be added one with the full path /// `crate_name::macro_name` and one with just the macro name. (standard_macro_braces: Vec = Vec::new()), /// Lint: MISSING_ENFORCED_IMPORT_RENAMES. @@ -408,7 +408,7 @@ define_Conf! { /// Lint: INDEX_REFUTABLE_SLICE. /// /// When Clippy suggests using a slice pattern, this is the maximum number of elements allowed in - /// the slice pattern that is suggested. If more elements would be necessary, the lint is suppressed. + /// the slice pattern that is suggested. If more elements are necessary, the lint is suppressed. /// For example, `[_, _, _, e, ..]` is a slice pattern with 4 elements. (max_suggested_slice_pattern_length: u64 = 3), /// Lint: AWAIT_HOLDING_INVALID_TYPE. @@ -459,6 +459,10 @@ define_Conf! { /// Whether to **only** check for missing documentation in items visible within the current /// crate. For example, `pub(crate)` items. (missing_docs_in_crate_items: bool = false), + /// Lint: LARGE_FUTURES. + /// + /// The maximum byte size a `Future` can have, before it triggers the `clippy::large_futures` lint + (future_size_threshold: u64 = 16 * 1024), } /// Search for the configuration file. @@ -466,7 +470,7 @@ define_Conf! { /// # Errors /// /// Returns any unexpected filesystem error encountered when searching for the config file -pub fn lookup_conf_file() -> io::Result> { +pub fn lookup_conf_file() -> io::Result<(Option, Vec)> { /// Possible filename to search for. const CONFIG_FILE_NAMES: [&str; 2] = [".clippy.toml", "clippy.toml"]; @@ -474,9 +478,11 @@ pub fn lookup_conf_file() -> io::Result> { // If neither of those exist, use ".". let mut current = env::var_os("CLIPPY_CONF_DIR") .or_else(|| env::var_os("CARGO_MANIFEST_DIR")) - .map_or_else(|| PathBuf::from("."), PathBuf::from); + .map_or_else(|| PathBuf::from("."), PathBuf::from) + .canonicalize()?; let mut found_config: Option = None; + let mut warnings = vec![]; loop { for config_file_name in &CONFIG_FILE_NAMES { @@ -487,12 +493,12 @@ pub fn lookup_conf_file() -> io::Result> { Ok(md) if md.is_dir() => {}, Ok(_) => { // warn if we happen to find two config files #8323 - if let Some(ref found_config_) = found_config { - eprintln!( - "Using config file `{}`\nWarning: `{}` will be ignored.", - found_config_.display(), - config_file.display(), - ); + if let Some(ref found_config) = found_config { + warnings.push(format!( + "using config file `{}`, `{}` will be ignored", + found_config.display(), + config_file.display() + )); } else { found_config = Some(config_file); } @@ -502,12 +508,12 @@ pub fn lookup_conf_file() -> io::Result> { } if found_config.is_some() { - return Ok(found_config); + return Ok((found_config, warnings)); } // If the current directory has no parent, we're done searching. if !current.pop() { - return Ok(None); + return Ok((None, warnings)); } } } diff --git a/clippy_lints/src/utils/format_args_collector.rs b/clippy_lints/src/utils/format_args_collector.rs index be56b842b98c6..09fcb82c37c88 100644 --- a/clippy_lints/src/utils/format_args_collector.rs +++ b/clippy_lints/src/utils/format_args_collector.rs @@ -1,7 +1,12 @@ use clippy_utils::macros::collect_ast_format_args; -use rustc_ast::{Expr, ExprKind}; +use clippy_utils::source::snippet_opt; +use itertools::Itertools; +use rustc_ast::{Expr, ExprKind, FormatArgs}; +use rustc_lexer::{tokenize, TokenKind}; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::hygiene; +use std::iter::once; declare_clippy_lint! { /// ### What it does @@ -15,9 +20,79 @@ declare_clippy_lint! { declare_lint_pass!(FormatArgsCollector => [FORMAT_ARGS_COLLECTOR]); impl EarlyLintPass for FormatArgsCollector { - fn check_expr(&mut self, _: &EarlyContext<'_>, expr: &Expr) { + fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { if let ExprKind::FormatArgs(args) = &expr.kind { + if has_span_from_proc_macro(cx, args) { + return; + } + collect_ast_format_args(expr.span, args); } } } + +/// Detects if the format string or an argument has its span set by a proc macro to something inside +/// a macro callsite, e.g. +/// +/// ```ignore +/// println!(some_proc_macro!("input {}"), a); +/// ``` +/// +/// Where `some_proc_macro` expands to +/// +/// ```ignore +/// println!("output {}", a); +/// ``` +/// +/// But with the span of `"output {}"` set to the macro input +/// +/// ```ignore +/// println!(some_proc_macro!("input {}"), a); +/// // ^^^^^^^^^^ +/// ``` +fn has_span_from_proc_macro(cx: &EarlyContext<'_>, args: &FormatArgs) -> bool { + let ctxt = args.span.ctxt(); + + // `format!("{} {} {c}", "one", "two", c = "three")` + // ^^^^^ ^^^^^ ^^^^^^^ + let argument_span = args + .arguments + .explicit_args() + .iter() + .map(|argument| hygiene::walk_chain(argument.expr.span, ctxt)); + + // `format!("{} {} {c}", "one", "two", c = "three")` + // ^^ ^^ ^^^^^^ + let between_spans = once(args.span) + .chain(argument_span) + .tuple_windows() + .map(|(start, end)| start.between(end)); + + for between_span in between_spans { + let mut seen_comma = false; + + let Some(snippet) = snippet_opt(cx, between_span) else { return true }; + for token in tokenize(&snippet) { + match token.kind { + TokenKind::LineComment { .. } | TokenKind::BlockComment { .. } | TokenKind::Whitespace => {}, + TokenKind::Comma if !seen_comma => seen_comma = true, + // named arguments, `start_val, name = end_val` + // ^^^^^^^^^ between_span + TokenKind::Ident | TokenKind::Eq if seen_comma => {}, + // An unexpected token usually indicates that we crossed a macro boundary + // + // `println!(some_proc_macro!("input {}"), a)` + // ^^^ between_span + // `println!("{}", val!(x))` + // ^^^^^^^ between_span + _ => return true, + } + } + + if !seen_comma { + return true; + } + } + + false +} diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs index 8114a8463faad..d7c94b909bdc5 100644 --- a/clippy_lints/src/write.rs +++ b/clippy_lints/src/write.rs @@ -463,12 +463,18 @@ fn check_literal(cx: &LateContext<'_>, format_args: &FormatArgs, name: &str) { && let Some(value_string) = snippet_opt(cx, arg.expr.span) { let (replacement, replace_raw) = match lit.kind { - LitKind::Str | LitKind::StrRaw(_) => extract_str_literal(&value_string), + LitKind::Str | LitKind::StrRaw(_) => match extract_str_literal(&value_string) { + Some(extracted) => extracted, + None => return, + }, LitKind::Char => ( match lit.symbol.as_str() { "\"" => "\\\"", "\\'" => "'", - _ => &value_string[1..value_string.len() - 1], + _ => match value_string.strip_prefix('\'').and_then(|s| s.strip_suffix('\'')) { + Some(stripped) => stripped, + None => return, + }, } .to_string(), false, @@ -533,13 +539,13 @@ fn check_literal(cx: &LateContext<'_>, format_args: &FormatArgs, name: &str) { /// `r#"a"#` -> (`a`, true) /// /// `"b"` -> (`b`, false) -fn extract_str_literal(literal: &str) -> (String, bool) { +fn extract_str_literal(literal: &str) -> Option<(String, bool)> { let (literal, raw) = match literal.strip_prefix('r') { Some(stripped) => (stripped.trim_matches('#'), true), None => (literal, false), }; - (literal[1..literal.len() - 1].to_string(), raw) + Some((literal.strip_prefix('"')?.strip_suffix('"')?.to_string(), raw)) } enum UnescapeErr { diff --git a/clippy_utils/src/ast_utils.rs b/clippy_utils/src/ast_utils.rs index c5b58b0c060c0..1f15598db36d9 100644 --- a/clippy_utils/src/ast_utils.rs +++ b/clippy_utils/src/ast_utils.rs @@ -286,8 +286,30 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { match (l, r) { (ExternCrate(l), ExternCrate(r)) => l == r, (Use(l), Use(r)) => eq_use_tree(l, r), - (Static(box ast::StaticItem { ty: lt, mutability: lm, expr: le}), Static(box ast::StaticItem { ty: rt, mutability: rm, expr: re})) => lm == rm && eq_ty(lt, rt) && eq_expr_opt(le, re), - (Const(box ast::ConstItem { defaultness: ld, ty: lt, expr: le}), Const(box ast::ConstItem { defaultness: rd, ty: rt, expr: re} )) => eq_defaultness(*ld, *rd) && eq_ty(lt, rt) && eq_expr_opt(le, re), + ( + Static(box ast::StaticItem { + ty: lt, + mutability: lm, + expr: le, + }), + Static(box ast::StaticItem { + ty: rt, + mutability: rm, + expr: re, + }), + ) => lm == rm && eq_ty(lt, rt) && eq_expr_opt(le, re), + ( + Const(box ast::ConstItem { + defaultness: ld, + ty: lt, + expr: le, + }), + Const(box ast::ConstItem { + defaultness: rd, + ty: rt, + expr: re, + }), + ) => eq_defaultness(*ld, *rd) && eq_ty(lt, rt) && eq_expr_opt(le, re), ( Fn(box ast::Fn { defaultness: ld, @@ -451,7 +473,18 @@ pub fn eq_foreign_item_kind(l: &ForeignItemKind, r: &ForeignItemKind) -> bool { pub fn eq_assoc_item_kind(l: &AssocItemKind, r: &AssocItemKind) -> bool { use AssocItemKind::*; match (l, r) { - (Const(box ast::ConstItem { defaultness: ld, ty: lt, expr: le}), Const(box ast::ConstItem { defaultness: rd, ty: rt, expr: re})) => eq_defaultness(*ld, *rd) && eq_ty(lt, rt) && eq_expr_opt(le, re), + ( + Const(box ast::ConstItem { + defaultness: ld, + ty: lt, + expr: le, + }), + Const(box ast::ConstItem { + defaultness: rd, + ty: rt, + expr: re, + }), + ) => eq_defaultness(*ld, *rd) && eq_ty(lt, rt) && eq_expr_opt(le, re), ( Fn(box ast::Fn { defaultness: ld, diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 9051cf51658df..6b677df464147 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -32,7 +32,6 @@ extern crate rustc_lexer; extern crate rustc_lint; extern crate rustc_middle; extern crate rustc_mir_dataflow; -extern crate rustc_parse_format; extern crate rustc_session; extern crate rustc_span; extern crate rustc_target; @@ -77,7 +76,7 @@ use std::sync::OnceLock; use std::sync::{Mutex, MutexGuard}; use if_chain::if_chain; -use rustc_ast::ast::{self, LitKind}; +use rustc_ast::ast::{self, LitKind, RangeLimits}; use rustc_ast::Attribute; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::unhash::UnhashMap; @@ -95,6 +94,7 @@ use rustc_hir::{ use rustc_lexer::{tokenize, TokenKind}; use rustc_lint::{LateContext, Level, Lint, LintContext}; use rustc_middle::hir::place::PlaceBase; +use rustc_middle::mir::ConstantKind; use rustc_middle::ty as rustc_ty; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow}; use rustc_middle::ty::binding::BindingMode; @@ -113,7 +113,8 @@ use rustc_span::symbol::{kw, Ident, Symbol}; use rustc_span::Span; use rustc_target::abi::Integer; -use crate::consts::{constant, Constant}; +use crate::consts::{constant, miri_to_const, Constant}; +use crate::higher::Range; use crate::ty::{can_partially_move_ty, expr_sig, is_copy, is_recursively_primitive_type, ty_is_fn_once_param}; use crate::visitors::for_each_expr; @@ -1490,6 +1491,68 @@ pub fn is_else_clause(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> bool { } } +/// Checks whether the given `Expr` is a range equivalent to a `RangeFull`. +/// For the lower bound, this means that: +/// - either there is none +/// - or it is the smallest value that can be represented by the range's integer type +/// For the upper bound, this means that: +/// - either there is none +/// - or it is the largest value that can be represented by the range's integer type and is +/// inclusive +/// - or it is a call to some container's `len` method and is exclusive, and the range is passed to +/// a method call on that same container (e.g. `v.drain(..v.len())`) +/// If the given `Expr` is not some kind of range, the function returns `false`. +pub fn is_range_full(cx: &LateContext<'_>, expr: &Expr<'_>, container_path: Option<&Path<'_>>) -> bool { + let ty = cx.typeck_results().expr_ty(expr); + if let Some(Range { start, end, limits }) = Range::hir(expr) { + let start_is_none_or_min = start.map_or(true, |start| { + if let rustc_ty::Adt(_, subst) = ty.kind() + && let bnd_ty = subst.type_at(0) + && let Some(min_val) = bnd_ty.numeric_min_val(cx.tcx) + && let const_val = cx.tcx.valtree_to_const_val((bnd_ty, min_val.to_valtree())) + && let min_const_kind = ConstantKind::from_value(const_val, bnd_ty) + && let Some(min_const) = miri_to_const(cx.tcx, min_const_kind) + && let Some((start_const, _)) = constant(cx, cx.typeck_results(), start) + { + start_const == min_const + } else { + false + } + }); + let end_is_none_or_max = end.map_or(true, |end| { + match limits { + RangeLimits::Closed => { + if let rustc_ty::Adt(_, subst) = ty.kind() + && let bnd_ty = subst.type_at(0) + && let Some(max_val) = bnd_ty.numeric_max_val(cx.tcx) + && let const_val = cx.tcx.valtree_to_const_val((bnd_ty, max_val.to_valtree())) + && let max_const_kind = ConstantKind::from_value(const_val, bnd_ty) + && let Some(max_const) = miri_to_const(cx.tcx, max_const_kind) + && let Some((end_const, _)) = constant(cx, cx.typeck_results(), end) + { + end_const == max_const + } else { + false + } + }, + RangeLimits::HalfOpen => { + if let Some(container_path) = container_path + && let ExprKind::MethodCall(name, self_arg, [], _) = end.kind + && name.ident.name == sym::len + && let ExprKind::Path(QPath::Resolved(None, path)) = self_arg.kind + { + container_path.res == path.res + } else { + false + } + }, + } + }); + return start_is_none_or_min && end_is_none_or_max; + } + false +} + /// Checks whether the given expression is a constant integer of the given value. /// unlike `is_integer_literal`, this version does const folding pub fn is_integer_const(cx: &LateContext<'_>, e: &Expr<'_>, value: u128) -> bool { @@ -2104,8 +2167,7 @@ pub fn fn_has_unsatisfiable_preds(cx: &LateContext<'_>, did: DefId) -> bool { .filter_map(|(p, _)| if p.is_global() { Some(*p) } else { None }); traits::impossible_predicates( cx.tcx, - traits::elaborate(cx.tcx, predicates) - .collect::>(), + traits::elaborate(cx.tcx, predicates).collect::>(), ) } diff --git a/clippy_utils/src/macros.rs b/clippy_utils/src/macros.rs index c0e32068ecacc..62d388a5ece8d 100644 --- a/clippy_utils/src/macros.rs +++ b/clippy_utils/src/macros.rs @@ -1,24 +1,16 @@ #![allow(clippy::similar_names)] // `expr` and `expn` -use crate::source::snippet_opt; use crate::visitors::{for_each_expr, Descend}; use arrayvec::ArrayVec; -use itertools::{izip, Either, Itertools}; -use rustc_ast::ast::LitKind; -use rustc_ast::FormatArgs; +use rustc_ast::{FormatArgs, FormatArgument, FormatPlaceholder}; use rustc_data_structures::fx::FxHashMap; -use rustc_hir::intravisit::{walk_expr, Visitor}; -use rustc_hir::{self as hir, Expr, ExprField, ExprKind, HirId, LangItem, Node, QPath, TyKind}; -use rustc_lexer::unescape::unescape_literal; -use rustc_lexer::{tokenize, unescape, LiteralKind, TokenKind}; +use rustc_hir::{self as hir, Expr, ExprKind, HirId, Node, QPath}; use rustc_lint::LateContext; -use rustc_parse_format::{self as rpf, Alignment}; use rustc_span::def_id::DefId; use rustc_span::hygiene::{self, MacroKind, SyntaxContext}; -use rustc_span::{sym, BytePos, ExpnData, ExpnId, ExpnKind, Pos, Span, SpanData, Symbol}; +use rustc_span::{sym, BytePos, ExpnData, ExpnId, ExpnKind, Span, Symbol}; use std::cell::RefCell; -use std::iter::{once, zip}; use std::ops::ControlFlow; use std::sync::atomic::{AtomicBool, Ordering}; @@ -226,11 +218,11 @@ pub enum PanicExpn<'a> { /// A single argument that implements `Display` - `panic!("{}", object)` Display(&'a Expr<'a>), /// Anything else - `panic!("error {}: {}", a, b)` - Format(FormatArgsExpn<'a>), + Format(&'a Expr<'a>), } impl<'a> PanicExpn<'a> { - pub fn parse(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option { + pub fn parse(expr: &'a Expr<'a>) -> Option { let ExprKind::Call(callee, [arg, rest @ ..]) = &expr.kind else { return None }; let ExprKind::Path(QPath::Resolved(_, path)) = &callee.kind else { return None }; let result = match path.segments.last().unwrap().ident.as_str() { @@ -240,7 +232,7 @@ impl<'a> PanicExpn<'a> { let ExprKind::AddrOf(_, _, e) = &arg.kind else { return None }; Self::Display(e) }, - "panic_fmt" => Self::Format(FormatArgsExpn::parse(cx, arg)?), + "panic_fmt" => Self::Format(arg), // Since Rust 1.52, `assert_{eq,ne}` macros expand to use: // `core::panicking::assert_failed(.., left_val, right_val, None | Some(format_args!(..)));` "assert_failed" => { @@ -252,7 +244,7 @@ impl<'a> PanicExpn<'a> { // `msg_arg` is either `None` (no custom message) or `Some(format_args!(..))` (custom message) let msg_arg = &rest[2]; match msg_arg.kind { - ExprKind::Call(_, [fmt_arg]) => Self::Format(FormatArgsExpn::parse(cx, fmt_arg)?), + ExprKind::Call(_, [fmt_arg]) => Self::Format(fmt_arg), _ => Self::Empty, } }, @@ -304,7 +296,7 @@ fn find_assert_args_inner<'a, const N: usize>( let mut args = ArrayVec::new(); let panic_expn = for_each_expr(expr, |e| { if args.is_full() { - match PanicExpn::parse(cx, e) { + match PanicExpn::parse(e) { Some(expn) => ControlFlow::Break(expn), None => ControlFlow::Continue(Descend::Yes), } @@ -391,30 +383,82 @@ pub fn collect_ast_format_args(span: Span, format_args: &FormatArgs) { }); } -/// Calls `callback` with an AST [`FormatArgs`] node if one is found +/// Calls `callback` with an AST [`FormatArgs`] node if a `format_args` expansion is found as a +/// descendant of `expn_id` pub fn find_format_args(cx: &LateContext<'_>, start: &Expr<'_>, expn_id: ExpnId, callback: impl FnOnce(&FormatArgs)) { let format_args_expr = for_each_expr(start, |expr| { let ctxt = expr.span.ctxt(); - if ctxt == start.span.ctxt() { - ControlFlow::Continue(Descend::Yes) - } else if ctxt.outer_expn().is_descendant_of(expn_id) - && macro_backtrace(expr.span) + if ctxt.outer_expn().is_descendant_of(expn_id) { + if macro_backtrace(expr.span) .map(|macro_call| cx.tcx.item_name(macro_call.def_id)) .any(|name| matches!(name, sym::const_format_args | sym::format_args | sym::format_args_nl)) - { - ControlFlow::Break(expr) + { + ControlFlow::Break(expr) + } else { + ControlFlow::Continue(Descend::Yes) + } } else { ControlFlow::Continue(Descend::No) } }); - if let Some(format_args_expr) = format_args_expr { + if let Some(expr) = format_args_expr { AST_FORMAT_ARGS.with(|ast_format_args| { - ast_format_args.borrow().get(&format_args_expr.span).map(callback); + ast_format_args.borrow().get(&expr.span).map(callback); }); } } +/// Attempt to find the [`rustc_hir::Expr`] that corresponds to the [`FormatArgument`]'s value, if +/// it cannot be found it will return the [`rustc_ast::Expr`]. +pub fn find_format_arg_expr<'hir, 'ast>( + start: &'hir Expr<'hir>, + target: &'ast FormatArgument, +) -> Result<&'hir rustc_hir::Expr<'hir>, &'ast rustc_ast::Expr> { + for_each_expr(start, |expr| { + if expr.span == target.expr.span { + ControlFlow::Break(expr) + } else { + ControlFlow::Continue(()) + } + }) + .ok_or(&target.expr) +} + +/// Span of the `:` and format specifiers +/// +/// ```ignore +/// format!("{:.}"), format!("{foo:.}") +/// ^^ ^^ +/// ``` +pub fn format_placeholder_format_span(placeholder: &FormatPlaceholder) -> Option { + let base = placeholder.span?.data(); + + // `base.hi` is `{...}|`, subtract 1 byte (the length of '}') so that it points before the closing + // brace `{...|}` + Some(Span::new( + placeholder.argument.span?.hi(), + base.hi - BytePos(1), + base.ctxt, + base.parent, + )) +} + +/// Span covering the format string and values +/// +/// ```ignore +/// format("{}.{}", 10, 11) +/// // ^^^^^^^^^^^^^^^ +/// ``` +pub fn format_args_inputs_span(format_args: &FormatArgs) -> Span { + match format_args.arguments.explicit_args() { + [] => format_args.span, + [.., last] => format_args + .span + .to(hygiene::walk_chain(last.expr.span, format_args.span.ctxt())), + } +} + /// Returns the [`Span`] of the value at `index` extended to the previous comma, e.g. for the value /// `10` /// @@ -436,251 +480,6 @@ pub fn format_arg_removal_span(format_args: &FormatArgs, index: usize) -> Option Some(current.with_lo(prev.hi())) } -/// The format string doesn't exist in the HIR, so we reassemble it from source code -#[derive(Debug)] -pub struct FormatString { - /// Span of the whole format string literal, including `[r#]"`. - pub span: Span, - /// Snippet of the whole format string literal, including `[r#]"`. - pub snippet: String, - /// If the string is raw `r"..."`/`r#""#`, how many `#`s does it have on each side. - pub style: Option, - /// The unescaped value of the format string, e.g. `"val – {}"` for the literal - /// `"val \u{2013} {}"`. - pub unescaped: String, - /// The format string split by format args like `{..}`. - pub parts: Vec, -} - -impl FormatString { - fn new(cx: &LateContext<'_>, pieces: &Expr<'_>) -> Option { - // format_args!(r"a {} b \", 1); - // - // expands to - // - // ::core::fmt::Arguments::new_v1(&["a ", " b \\"], - // &[::core::fmt::ArgumentV1::new_display(&1)]); - // - // where `pieces` is the expression `&["a ", " b \\"]`. It has the span of `r"a {} b \"` - let span = pieces.span; - let snippet = snippet_opt(cx, span)?; - - let (inner, style) = match tokenize(&snippet).next()?.kind { - TokenKind::Literal { kind, .. } => { - let style = match kind { - LiteralKind::Str { .. } => None, - LiteralKind::RawStr { n_hashes: Some(n), .. } => Some(n.into()), - _ => return None, - }; - - let start = style.map_or(1, |n| 2 + n); - let end = snippet.len() - style.map_or(1, |n| 1 + n); - - (&snippet[start..end], style) - }, - _ => return None, - }; - - let mode = if style.is_some() { - unescape::Mode::RawStr - } else { - unescape::Mode::Str - }; - - let mut unescaped = String::with_capacity(inner.len()); - // Sometimes the original string comes from a macro which accepts a malformed string, such as in a - // #[display(""somestring)] attribute (accepted by the `displaythis` crate). Reconstructing the - // string from the span will not be possible, so we will just return None here. - let mut unparsable = false; - unescape_literal(inner, mode, &mut |_, ch| match ch { - Ok(ch) => unescaped.push(ch), - Err(e) if !e.is_fatal() => (), - Err(_) => unparsable = true, - }); - if unparsable { - return None; - } - - let mut parts = Vec::new(); - let _: Option = for_each_expr(pieces, |expr| { - if let ExprKind::Lit(lit) = &expr.kind - && let LitKind::Str(symbol, _) = lit.node - { - parts.push(symbol); - } - ControlFlow::Continue(()) - }); - - Some(Self { - span, - snippet, - style, - unescaped, - parts, - }) - } -} - -struct FormatArgsValues<'tcx> { - /// Values passed after the format string and implicit captures. `[1, z + 2, x]` for - /// `format!("{x} {} {}", 1, z + 2)`. - value_args: Vec<&'tcx Expr<'tcx>>, - /// Maps an `rt::v1::Argument::position` or an `rt::v1::Count::Param` to its index in - /// `value_args` - pos_to_value_index: Vec, - /// Used to check if a value is declared inline & to resolve `InnerSpan`s. - format_string_span: SpanData, -} - -impl<'tcx> FormatArgsValues<'tcx> { - fn new_empty(format_string_span: SpanData) -> Self { - Self { - value_args: Vec::new(), - pos_to_value_index: Vec::new(), - format_string_span, - } - } - - fn new(args: &'tcx Expr<'tcx>, format_string_span: SpanData) -> Self { - let mut pos_to_value_index = Vec::new(); - let mut value_args = Vec::new(); - let _: Option = for_each_expr(args, |expr| { - if expr.span.ctxt() == args.span.ctxt() { - // ArgumentV1::new_() - // ArgumentV1::from_usize() - if let ExprKind::Call(callee, [val]) = expr.kind - && let ExprKind::Path(QPath::TypeRelative(ty, _)) = callee.kind - && let TyKind::Path(QPath::LangItem(LangItem::FormatArgument, _, _)) = ty.kind - { - let val_idx = if val.span.ctxt() == expr.span.ctxt() - && let ExprKind::Field(_, field) = val.kind - && let Ok(idx) = field.name.as_str().parse() - { - // tuple index - idx - } else { - // assume the value expression is passed directly - pos_to_value_index.len() - }; - - pos_to_value_index.push(val_idx); - } - ControlFlow::Continue(Descend::Yes) - } else { - // assume that any expr with a differing span is a value - value_args.push(expr); - ControlFlow::Continue(Descend::No) - } - }); - - Self { - value_args, - pos_to_value_index, - format_string_span, - } - } -} - -/// The positions of a format argument's value, precision and width -/// -/// A position is an index into the second argument of `Arguments::new_v1[_formatted]` -#[derive(Debug, Default, Copy, Clone)] -struct ParamPosition { - /// The position stored in `rt::v1::Argument::position`. - value: usize, - /// The position stored in `rt::v1::FormatSpec::width` if it is a `Count::Param`. - width: Option, - /// The position stored in `rt::v1::FormatSpec::precision` if it is a `Count::Param`. - precision: Option, -} - -impl<'tcx> Visitor<'tcx> for ParamPosition { - fn visit_expr_field(&mut self, field: &'tcx ExprField<'tcx>) { - match field.ident.name { - sym::position => { - if let ExprKind::Lit(lit) = &field.expr.kind - && let LitKind::Int(pos, _) = lit.node - { - self.value = pos as usize; - } - }, - sym::precision => { - self.precision = parse_count(field.expr); - }, - sym::width => { - self.width = parse_count(field.expr); - }, - _ => walk_expr(self, field.expr), - } - } -} - -fn parse_count(expr: &Expr<'_>) -> Option { - // <::core::fmt::rt::v1::Count>::Param(1usize), - if let ExprKind::Call(ctor, [val]) = expr.kind - && let ExprKind::Path(QPath::TypeRelative(_, path)) = ctor.kind - && path.ident.name == sym::Param - && let ExprKind::Lit(lit) = &val.kind - && let LitKind::Int(pos, _) = lit.node - { - Some(pos as usize) - } else { - None - } -} - -/// Parses the `fmt` arg of `Arguments::new_v1_formatted(pieces, args, fmt, _)` -fn parse_rt_fmt<'tcx>(fmt_arg: &'tcx Expr<'tcx>) -> Option + 'tcx> { - if let ExprKind::AddrOf(.., array) = fmt_arg.kind - && let ExprKind::Array(specs) = array.kind - { - Some(specs.iter().map(|spec| { - if let ExprKind::Call(f, args) = spec.kind - && let ExprKind::Path(QPath::TypeRelative(ty, f)) = f.kind - && let TyKind::Path(QPath::LangItem(LangItem::FormatPlaceholder, _, _)) = ty.kind - && f.ident.name == sym::new - && let [position, _fill, _align, _flags, precision, width] = args - && let ExprKind::Lit(position) = &position.kind - && let LitKind::Int(position, _) = position.node { - ParamPosition { - value: position as usize, - width: parse_count(width), - precision: parse_count(precision), - } - } else { - ParamPosition::default() - } - })) - } else { - None - } -} - -/// `Span::from_inner`, but for `rustc_parse_format`'s `InnerSpan` -fn span_from_inner(base: SpanData, inner: rpf::InnerSpan) -> Span { - Span::new( - base.lo + BytePos::from_usize(inner.start), - base.lo + BytePos::from_usize(inner.end), - base.ctxt, - base.parent, - ) -} - -/// How a format parameter is used in the format string -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub enum FormatParamKind { - /// An implicit parameter , such as `{}` or `{:?}`. - Implicit, - /// A parameter with an explicit number, e.g. `{1}`, `{0:?}`, or `{:.0$}` - Numbered, - /// A parameter with an asterisk precision. e.g. `{:.*}`. - Starred, - /// A named parameter with a named `value_arg`, such as the `x` in `format!("{x}", x = 1)`. - Named(Symbol), - /// An implicit named parameter, such as the `y` in `format!("{y}")`. - NamedInline(Symbol), -} - /// Where a format parameter is being used in the format string #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum FormatParamUsage { @@ -692,467 +491,6 @@ pub enum FormatParamUsage { Precision, } -/// A `FormatParam` is any place in a `FormatArgument` that refers to a supplied value, e.g. -/// -/// ``` -/// let precision = 2; -/// format!("{:.precision$}", 0.1234); -/// ``` -/// -/// has two `FormatParam`s, a [`FormatParamKind::Implicit`] `.kind` with a `.value` of `0.1234` -/// and a [`FormatParamKind::NamedInline("precision")`] `.kind` with a `.value` of `2` -#[derive(Debug, Copy, Clone)] -pub struct FormatParam<'tcx> { - /// The expression this parameter refers to. - pub value: &'tcx Expr<'tcx>, - /// How this parameter refers to its `value`. - pub kind: FormatParamKind, - /// Where this format param is being used - argument/width/precision - pub usage: FormatParamUsage, - /// Span of the parameter, may be zero width. Includes the whitespace of implicit parameters. - /// - /// ```text - /// format!("{}, { }, {0}, {name}", ...); - /// ^ ~~ ~ ~~~~ - /// ``` - pub span: Span, -} - -impl<'tcx> FormatParam<'tcx> { - fn new( - mut kind: FormatParamKind, - usage: FormatParamUsage, - position: usize, - inner: rpf::InnerSpan, - values: &FormatArgsValues<'tcx>, - ) -> Option { - let value_index = *values.pos_to_value_index.get(position)?; - let value = *values.value_args.get(value_index)?; - let span = span_from_inner(values.format_string_span, inner); - - // if a param is declared inline, e.g. `format!("{x}")`, the generated expr's span points - // into the format string - if let FormatParamKind::Named(name) = kind && values.format_string_span.contains(value.span.data()) { - kind = FormatParamKind::NamedInline(name); - } - - Some(Self { - value, - kind, - usage, - span, - }) - } -} - -/// Used by [width](https://doc.rust-lang.org/std/fmt/#width) and -/// [precision](https://doc.rust-lang.org/std/fmt/#precision) specifiers. -#[derive(Debug, Copy, Clone)] -pub enum Count<'tcx> { - /// Specified with a literal number, stores the value. - Is(usize, Span), - /// Specified using `$` and `*` syntaxes. The `*` format is still considered to be - /// `FormatParamKind::Numbered`. - Param(FormatParam<'tcx>), - /// Not specified. - Implied(Option), -} - -impl<'tcx> Count<'tcx> { - fn new( - usage: FormatParamUsage, - count: rpf::Count<'_>, - position: Option, - inner: Option, - values: &FormatArgsValues<'tcx>, - ) -> Option { - let span = inner.map(|inner| span_from_inner(values.format_string_span, inner)); - - Some(match count { - rpf::Count::CountIs(val) => Self::Is(val, span?), - rpf::Count::CountIsName(name, _) => Self::Param(FormatParam::new( - FormatParamKind::Named(Symbol::intern(name)), - usage, - position?, - inner?, - values, - )?), - rpf::Count::CountIsParam(_) => Self::Param(FormatParam::new( - FormatParamKind::Numbered, - usage, - position?, - inner?, - values, - )?), - rpf::Count::CountIsStar(_) => Self::Param(FormatParam::new( - FormatParamKind::Starred, - usage, - position?, - inner?, - values, - )?), - rpf::Count::CountImplied => Self::Implied(span), - }) - } - - pub fn is_implied(self) -> bool { - matches!(self, Count::Implied(_)) - } - - pub fn param(self) -> Option> { - match self { - Count::Param(param) => Some(param), - _ => None, - } - } - - pub fn span(self) -> Option { - match self { - Count::Is(_, span) => Some(span), - Count::Param(param) => Some(param.span), - Count::Implied(span) => span, - } - } -} - -/// Specification for the formatting of an argument in the format string. See -/// for the precise meanings. -#[derive(Debug)] -pub struct FormatSpec<'tcx> { - /// Optionally specified character to fill alignment with. - pub fill: Option, - /// Optionally specified alignment. - pub align: Alignment, - /// Whether all flag options are set to default (no flags specified). - pub no_flags: bool, - /// Represents either the maximum width or the integer precision. - pub precision: Count<'tcx>, - /// The minimum width, will be padded according to `width`/`align` - pub width: Count<'tcx>, - /// The formatting trait used by the argument, e.g. `sym::Display` for `{}`, `sym::Debug` for - /// `{:?}`. - pub r#trait: Symbol, - pub trait_span: Option, -} - -impl<'tcx> FormatSpec<'tcx> { - fn new(spec: rpf::FormatSpec<'_>, positions: ParamPosition, values: &FormatArgsValues<'tcx>) -> Option { - Some(Self { - fill: spec.fill, - align: spec.align, - no_flags: spec.sign.is_none() && !spec.alternate && !spec.zero_pad && spec.debug_hex.is_none(), - precision: Count::new( - FormatParamUsage::Precision, - spec.precision, - positions.precision, - spec.precision_span, - values, - )?, - width: Count::new( - FormatParamUsage::Width, - spec.width, - positions.width, - spec.width_span, - values, - )?, - r#trait: match spec.ty { - "" => sym::Display, - "?" => sym::Debug, - "o" => sym!(Octal), - "x" => sym!(LowerHex), - "X" => sym!(UpperHex), - "p" => sym::Pointer, - "b" => sym!(Binary), - "e" => sym!(LowerExp), - "E" => sym!(UpperExp), - _ => return None, - }, - trait_span: spec - .ty_span - .map(|span| span_from_inner(values.format_string_span, span)), - }) - } - - /// Returns true if this format spec is unchanged from the default. e.g. returns true for `{}`, - /// `{foo}` and `{2}`, but false for `{:?}`, `{foo:5}` and `{3:.5}` - pub fn is_default(&self) -> bool { - self.r#trait == sym::Display && self.is_default_for_trait() - } - - /// Has no other formatting specifiers than setting the format trait. returns true for `{}`, - /// `{foo}`, `{:?}`, but false for `{foo:5}`, `{3:.5?}` - pub fn is_default_for_trait(&self) -> bool { - self.width.is_implied() && self.precision.is_implied() && self.align == Alignment::AlignUnknown && self.no_flags - } -} - -/// A format argument, such as `{}`, `{foo:?}`. -#[derive(Debug)] -pub struct FormatArg<'tcx> { - /// The parameter the argument refers to. - pub param: FormatParam<'tcx>, - /// How to format `param`. - pub format: FormatSpec<'tcx>, - /// span of the whole argument, `{..}`. - pub span: Span, -} - -impl<'tcx> FormatArg<'tcx> { - /// Span of the `:` and format specifiers - /// - /// ```ignore - /// format!("{:.}"), format!("{foo:.}") - /// ^^ ^^ - /// ``` - pub fn format_span(&self) -> Span { - let base = self.span.data(); - - // `base.hi` is `{...}|`, subtract 1 byte (the length of '}') so that it points before the closing - // brace `{...|}` - Span::new(self.param.span.hi(), base.hi - BytePos(1), base.ctxt, base.parent) - } -} - -/// A parsed `format_args!` expansion. -#[derive(Debug)] -pub struct FormatArgsExpn<'tcx> { - /// The format string literal. - pub format_string: FormatString, - /// The format arguments, such as `{:?}`. - pub args: Vec>, - /// Has an added newline due to `println!()`/`writeln!()`/etc. The last format string part will - /// include this added newline. - pub newline: bool, - /// Spans of the commas between the format string and explicit values, excluding any trailing - /// comma - /// - /// ```ignore - /// format!("..", 1, 2, 3,) - /// // ^ ^ ^ - /// ``` - comma_spans: Vec, - /// Explicit values passed after the format string, ignoring implicit captures. `[1, z + 2]` for - /// `format!("{x} {} {y}", 1, z + 2)`. - explicit_values: Vec<&'tcx Expr<'tcx>>, -} - -impl<'tcx> FormatArgsExpn<'tcx> { - /// Gets the spans of the commas inbetween the format string and explicit args, not including - /// any trailing comma - /// - /// ```ignore - /// format!("{} {}", a, b) - /// // ^ ^ - /// ``` - /// - /// Ensures that the format string and values aren't coming from a proc macro that sets the - /// output span to that of its input - fn comma_spans(cx: &LateContext<'_>, explicit_values: &[&Expr<'_>], fmt_span: Span) -> Option> { - // `format!("{} {} {c}", "one", "two", c = "three")` - // ^^^^^ ^^^^^ ^^^^^^^ - let value_spans = explicit_values - .iter() - .map(|val| hygiene::walk_chain(val.span, fmt_span.ctxt())); - - // `format!("{} {} {c}", "one", "two", c = "three")` - // ^^ ^^ ^^^^^^ - let between_spans = once(fmt_span) - .chain(value_spans) - .tuple_windows() - .map(|(start, end)| start.between(end)); - - let mut comma_spans = Vec::new(); - for between_span in between_spans { - let mut offset = 0; - let mut seen_comma = false; - - for token in tokenize(&snippet_opt(cx, between_span)?) { - match token.kind { - TokenKind::LineComment { .. } | TokenKind::BlockComment { .. } | TokenKind::Whitespace => {}, - TokenKind::Comma if !seen_comma => { - seen_comma = true; - - let base = between_span.data(); - comma_spans.push(Span::new( - base.lo + BytePos(offset), - base.lo + BytePos(offset + 1), - base.ctxt, - base.parent, - )); - }, - // named arguments, `start_val, name = end_val` - // ^^^^^^^^^ between_span - TokenKind::Ident | TokenKind::Eq if seen_comma => {}, - // An unexpected token usually indicates the format string or a value came from a proc macro output - // that sets the span of its output to an input, e.g. `println!(some_proc_macro!("input"), ..)` that - // emits a string literal with the span set to that of `"input"` - _ => return None, - } - offset += token.len; - } - - if !seen_comma { - return None; - } - } - - Some(comma_spans) - } - - pub fn parse(cx: &LateContext<'_>, expr: &'tcx Expr<'tcx>) -> Option { - let macro_name = macro_backtrace(expr.span) - .map(|macro_call| cx.tcx.item_name(macro_call.def_id)) - .find(|&name| matches!(name, sym::const_format_args | sym::format_args | sym::format_args_nl))?; - let newline = macro_name == sym::format_args_nl; - - // ::core::fmt::Arguments::new_const(pieces) - // ::core::fmt::Arguments::new_v1(pieces, args) - // ::core::fmt::Arguments::new_v1_formatted(pieces, args, fmt, _unsafe_arg) - if let ExprKind::Call(callee, [pieces, rest @ ..]) = expr.kind - && let ExprKind::Path(QPath::TypeRelative(ty, seg)) = callee.kind - && let TyKind::Path(QPath::LangItem(LangItem::FormatArguments, _, _)) = ty.kind - && matches!(seg.ident.as_str(), "new_const" | "new_v1" | "new_v1_formatted") - { - let format_string = FormatString::new(cx, pieces)?; - - let mut parser = rpf::Parser::new( - &format_string.unescaped, - format_string.style, - Some(format_string.snippet.clone()), - // `format_string.unescaped` does not contain the appended newline - false, - rpf::ParseMode::Format, - ); - - let parsed_args = parser - .by_ref() - .filter_map(|piece| match piece { - rpf::Piece::NextArgument(a) => Some(a), - rpf::Piece::String(_) => None, - }) - .collect_vec(); - if !parser.errors.is_empty() { - return None; - } - - let positions = if let Some(fmt_arg) = rest.get(1) { - // If the argument contains format specs, `new_v1_formatted(_, _, fmt, _)`, parse - // them. - - Either::Left(parse_rt_fmt(fmt_arg)?) - } else { - // If no format specs are given, the positions are in the given order and there are - // no `precision`/`width`s to consider. - - Either::Right((0..).map(|n| ParamPosition { - value: n, - width: None, - precision: None, - })) - }; - - let values = if let Some(args) = rest.first() { - FormatArgsValues::new(args, format_string.span.data()) - } else { - FormatArgsValues::new_empty(format_string.span.data()) - }; - - let args = izip!(positions, parsed_args, parser.arg_places) - .map(|(position, parsed_arg, arg_span)| { - Some(FormatArg { - param: FormatParam::new( - match parsed_arg.position { - rpf::Position::ArgumentImplicitlyIs(_) => FormatParamKind::Implicit, - rpf::Position::ArgumentIs(_) => FormatParamKind::Numbered, - // NamedInline is handled by `FormatParam::new()` - rpf::Position::ArgumentNamed(name) => FormatParamKind::Named(Symbol::intern(name)), - }, - FormatParamUsage::Argument, - position.value, - parsed_arg.position_span, - &values, - )?, - format: FormatSpec::new(parsed_arg.format, position, &values)?, - span: span_from_inner(values.format_string_span, arg_span), - }) - }) - .collect::>>()?; - - let mut explicit_values = values.value_args; - // remove values generated for implicitly captured vars - let len = explicit_values - .iter() - .take_while(|val| !format_string.span.contains(val.span)) - .count(); - explicit_values.truncate(len); - - let comma_spans = Self::comma_spans(cx, &explicit_values, format_string.span)?; - - Some(Self { - format_string, - args, - newline, - comma_spans, - explicit_values, - }) - } else { - None - } - } - - pub fn find_nested(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, expn_id: ExpnId) -> Option { - for_each_expr(expr, |e| { - let e_ctxt = e.span.ctxt(); - if e_ctxt == expr.span.ctxt() { - ControlFlow::Continue(Descend::Yes) - } else if e_ctxt.outer_expn().is_descendant_of(expn_id) { - if let Some(args) = FormatArgsExpn::parse(cx, e) { - ControlFlow::Break(args) - } else { - ControlFlow::Continue(Descend::No) - } - } else { - ControlFlow::Continue(Descend::No) - } - }) - } - - /// Source callsite span of all inputs - pub fn inputs_span(&self) -> Span { - match *self.explicit_values { - [] => self.format_string.span, - [.., last] => self - .format_string - .span - .to(hygiene::walk_chain(last.span, self.format_string.span.ctxt())), - } - } - - /// Get the span of a value expanded to the previous comma, e.g. for the value `10` - /// - /// ```ignore - /// format("{}.{}", 10, 11) - /// // ^^^^ - /// ``` - pub fn value_with_prev_comma_span(&self, value_id: HirId) -> Option { - for (comma_span, value) in zip(&self.comma_spans, &self.explicit_values) { - if value.hir_id == value_id { - return Some(comma_span.to(hygiene::walk_chain(value.span, comma_span.ctxt()))); - } - } - - None - } - - /// Iterator of all format params, both values and those referenced by `width`/`precision`s. - pub fn params(&'tcx self) -> impl Iterator> { - self.args - .iter() - .flat_map(|arg| [Some(arg.param), arg.format.precision.param(), arg.format.width.param()]) - .flatten() - } -} - /// A node with a `HirId` and a `Span` pub trait HirNode { fn hir_id(&self) -> HirId; diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index c919575bfe906..9be2d0eae80aa 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -23,6 +23,7 @@ pub const CLONE_TRAIT_METHOD: [&str; 4] = ["core", "clone", "Clone", "clone"]; pub const CORE_ITER_CLONED: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "cloned"]; pub const CORE_ITER_COPIED: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "copied"]; pub const CORE_ITER_FILTER: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "filter"]; +pub const CORE_RESULT_OK_METHOD: [&str; 4] = ["core", "result", "Result", "ok"]; pub const CSTRING_AS_C_STR: [&str; 5] = ["alloc", "ffi", "c_str", "CString", "as_c_str"]; pub const DEFAULT_TRAIT_METHOD: [&str; 4] = ["core", "default", "Default", "default"]; pub const DEREF_MUT_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "DerefMut", "deref_mut"]; @@ -113,6 +114,7 @@ pub const STDERR: [&str; 4] = ["std", "io", "stdio", "stderr"]; pub const STDOUT: [&str; 4] = ["std", "io", "stdio", "stdout"]; pub const CONVERT_IDENTITY: [&str; 3] = ["core", "convert", "identity"]; pub const STD_FS_CREATE_DIR: [&str; 3] = ["std", "fs", "create_dir"]; +pub const STD_IO_LINES: [&str; 3] = ["std", "io", "Lines"]; pub const STD_IO_SEEK: [&str; 3] = ["std", "io", "Seek"]; pub const STD_IO_SEEK_FROM_CURRENT: [&str; 4] = ["std", "io", "SeekFrom", "Current"]; pub const STD_IO_SEEKFROM_START: [&str; 4] = ["std", "io", "SeekFrom", "Start"]; diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index 0b47234647fb6..9449f0b55674d 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -541,9 +541,25 @@ pub fn same_type_and_consts<'tcx>(a: Ty<'tcx>, b: Ty<'tcx>) -> bool { 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) + .unwrap_or_else(|_| is_uninit_value_valid_for_ty_fallback(cx, ty)) +} + +/// A fallback for polymorphic types, which are not supported by `check_validity_requirement`. +fn is_uninit_value_valid_for_ty_fallback<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { + match *ty.kind() { + // The array length may be polymorphic, let's try the inner type. + ty::Array(component, _) => is_uninit_value_valid_for_ty(cx, component), + // Peek through tuples and try their fallbacks. + ty::Tuple(types) => types.iter().all(|ty| is_uninit_value_valid_for_ty(cx, ty)), + // Unions are always fine right now. + // This includes MaybeUninit, the main way people use uninitialized memory. + // For ADTs, we could look at all fields just like for tuples, but that's potentially + // exponential, so let's avoid doing that for now. Code doing that is sketchy enough to + // just use an `#[allow()]`. + ty::Adt(adt, _) => adt.is_union(), + // For the rest, conservatively assume that they cannot be uninit. + _ => false, + } } /// Gets an iterator over all predicates which apply to the given item. diff --git a/etc/relicense/RELICENSE_DOCUMENTATION.md b/etc/relicense/RELICENSE_DOCUMENTATION.md index fcd7abbf3f169..ffb99cde4f869 100644 --- a/etc/relicense/RELICENSE_DOCUMENTATION.md +++ b/etc/relicense/RELICENSE_DOCUMENTATION.md @@ -35,7 +35,7 @@ relicensing are archived on GitHub. We also have saved Wayback Machine copies of The usernames of commenters on these issues can be found in relicense_comments.txt -There are a couple people in relicense_comments.txt who are not found in contributors.txt: +There are a few people in relicense_comments.txt who are not found in contributors.txt: - @EpocSquadron has [made minor text contributions to the README](https://github.com/rust-lang/rust-clippy/commits?author=EpocSquadron) which have since been overwritten, and @@ -55,7 +55,7 @@ There are a couple people in relicense_comments.txt who are not found in contrib we rewrote (see below) -Two of these contributors had nonminor contributions (#2184, #427) requiring a rewrite, carried out in #3251 +Two of these contributors had non-minor contributions (#2184, #427) requiring a rewrite, carried out in #3251 ([archive](http://web.archive.org/web/20181005192411/https://github.com/rust-lang-nursery/rust-clippy/pull/3251), [screenshot](https://user-images.githubusercontent.com/1617736/46573515-5cb69580-c94b-11e8-86e5-b456452121b2.png)) diff --git a/lintcheck/README.md b/lintcheck/README.md index e997eb47e321f..faf3ce9093a21 100644 --- a/lintcheck/README.md +++ b/lintcheck/README.md @@ -16,7 +16,7 @@ or cargo lintcheck ``` -By default the logs will be saved into +By default, the logs will be saved into `lintcheck-logs/lintcheck_crates_logs.txt`. You can set a custom sources.toml by adding `--crates-toml custom.toml` or using diff --git a/rust-toolchain b/rust-toolchain index 0b2458ea00708..91e8ccea1f434 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2023-03-24" +channel = "nightly-2023-04-06" components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] diff --git a/src/driver.rs b/src/driver.rs index 9e0822404b6b8..718bc41fb9924 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -130,7 +130,7 @@ impl rustc_driver::Callbacks for ClippyCallbacks { #[allow(rustc::bad_opt_access)] fn config(&mut self, config: &mut interface::Config) { let conf_path = clippy_lints::lookup_conf_file(); - let conf_path_string = if let Ok(Some(path)) = &conf_path { + let conf_path_string = if let Ok((Some(path), _)) = &conf_path { path.to_str().map(String::from) } else { None diff --git a/tests/ui-cargo/multiple_config_files/warn/src/main.stderr b/tests/ui-cargo/multiple_config_files/warn/src/main.stderr index 98697e001f99a..aa1b3c638a036 100644 --- a/tests/ui-cargo/multiple_config_files/warn/src/main.stderr +++ b/tests/ui-cargo/multiple_config_files/warn/src/main.stderr @@ -1,2 +1,4 @@ -Using config file `$SRC_DIR/.clippy.toml` -Warning: `$SRC_DIR/clippy.toml` will be ignored. +warning: using config file `$SRC_DIR/.clippy.toml`, `$SRC_DIR/clippy.toml` will be ignored + +warning: 1 warning emitted + diff --git a/tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.stderr b/tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.stderr index ee94176219615..1be0cda12fc11 100644 --- a/tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.stderr +++ b/tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.stderr @@ -11,29 +11,29 @@ LL - println!("val='{}'", local_i32); LL + println!("val='{local_i32}'"); | -error: literal with an empty format string - --> $DIR/uninlined_format_args.rs:10:35 +error: variables can be used directly in the `format!` string + --> $DIR/uninlined_format_args.rs:10:5 | LL | println!("Hello {} is {:.*}", "x", local_i32, local_f64); - | ^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `-D clippy::print-literal` implied by `-D warnings` -help: try this +help: change this to | LL - println!("Hello {} is {:.*}", "x", local_i32, local_f64); -LL + println!("Hello x is {:.*}", local_i32, local_f64); +LL + println!("Hello {} is {local_f64:.local_i32$}", "x"); | -error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:10:5 +error: literal with an empty format string + --> $DIR/uninlined_format_args.rs:10:35 | LL | println!("Hello {} is {:.*}", "x", local_i32, local_f64); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^ | -help: change this to + = note: `-D clippy::print-literal` implied by `-D warnings` +help: try this | LL - println!("Hello {} is {:.*}", "x", local_i32, local_f64); -LL + println!("Hello {} is {local_f64:.local_i32$}", "x"); +LL + println!("Hello x is {:.*}", local_i32, local_f64); | error: variables can be used directly in the `format!` string diff --git a/tests/ui-toml/extra_unused_type_parameters/clippy.toml b/tests/ui-toml/extra_unused_type_parameters/clippy.toml new file mode 100644 index 0000000000000..5f304987aa94a --- /dev/null +++ b/tests/ui-toml/extra_unused_type_parameters/clippy.toml @@ -0,0 +1 @@ +avoid-breaking-exported-api = true diff --git a/tests/ui-toml/extra_unused_type_parameters/extra_unused_type_parameters.rs b/tests/ui-toml/extra_unused_type_parameters/extra_unused_type_parameters.rs new file mode 100644 index 0000000000000..5655232455cb7 --- /dev/null +++ b/tests/ui-toml/extra_unused_type_parameters/extra_unused_type_parameters.rs @@ -0,0 +1,9 @@ +pub struct S; + +impl S { + pub fn exported_fn() { + unimplemented!(); + } +} + +fn main() {} diff --git a/tests/ui-toml/large_futures/clippy.toml b/tests/ui-toml/large_futures/clippy.toml new file mode 100644 index 0000000000000..61bb17fdf6bdb --- /dev/null +++ b/tests/ui-toml/large_futures/clippy.toml @@ -0,0 +1 @@ +future-size-threshold = 1024 diff --git a/tests/ui-toml/large_futures/large_futures.rs b/tests/ui-toml/large_futures/large_futures.rs new file mode 100644 index 0000000000000..4158df8b5ff55 --- /dev/null +++ b/tests/ui-toml/large_futures/large_futures.rs @@ -0,0 +1,27 @@ +#![warn(clippy::large_futures)] + +fn main() {} + +pub async fn should_warn() { + let x = [0u8; 1024]; + async {}.await; + dbg!(x); +} + +pub async fn should_not_warn() { + let x = [0u8; 1020]; + async {}.await; + dbg!(x); +} + +pub async fn bar() { + should_warn().await; + + async { + let x = [0u8; 1024]; + dbg!(x); + } + .await; + + should_not_warn().await; +} diff --git a/tests/ui-toml/large_futures/large_futures.stderr b/tests/ui-toml/large_futures/large_futures.stderr new file mode 100644 index 0000000000000..b92734de2f08c --- /dev/null +++ b/tests/ui-toml/large_futures/large_futures.stderr @@ -0,0 +1,10 @@ +error: large future with a size of 1026 bytes + --> $DIR/large_futures.rs:18:5 + | +LL | should_warn().await; + | ^^^^^^^^^^^^^ help: consider `Box::pin` on it: `Box::pin(should_warn())` + | + = note: `-D clippy::large-futures` implied by `-D warnings` + +error: aborting due to previous error + diff --git a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr index 6a246afac76e0..8447c31722dd0 100644 --- a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr +++ b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr @@ -24,6 +24,7 @@ error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown fie enforced-import-renames enum-variant-name-threshold enum-variant-size-threshold + future-size-threshold ignore-interior-mutability large-error-threshold literal-representation-threshold diff --git a/tests/ui/arithmetic_side_effects.rs b/tests/ui/arithmetic_side_effects.rs index ee7d2ba444b20..3c06676d7228a 100644 --- a/tests/ui/arithmetic_side_effects.rs +++ b/tests/ui/arithmetic_side_effects.rs @@ -425,4 +425,8 @@ pub fn integer_arithmetic() { i ^= i; } +pub fn issue_10583(a: u16) -> u16 { + 10 / a +} + fn main() {} diff --git a/tests/ui/arithmetic_side_effects.stderr b/tests/ui/arithmetic_side_effects.stderr index 3895f08964ce8..2c8ee2884e732 100644 --- a/tests/ui/arithmetic_side_effects.stderr +++ b/tests/ui/arithmetic_side_effects.stderr @@ -576,6 +576,12 @@ error: arithmetic operation that can potentially result in unexpected side-effec LL | i * 2; | ^^^^^ +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:394:5 + | +LL | 1 % i / 2; + | ^^^^^ + error: arithmetic operation that can potentially result in unexpected side-effects --> $DIR/arithmetic_side_effects.rs:395:5 | @@ -642,5 +648,11 @@ error: arithmetic operation that can potentially result in unexpected side-effec LL | i %= var2; | ^^^^^^^^^ -error: aborting due to 107 previous errors +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:429:5 + | +LL | 10 / a + | ^^^^^^ + +error: aborting due to 109 previous errors diff --git a/tests/ui/auxiliary/proc_macros.rs b/tests/ui/auxiliary/proc_macros.rs index 325be83a0d73d..3d5beab1eff1c 100644 --- a/tests/ui/auxiliary/proc_macros.rs +++ b/tests/ui/auxiliary/proc_macros.rs @@ -63,7 +63,7 @@ fn group_with_span(delimiter: Delimiter, stream: TokenStream, span: Span) -> Gro /// 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 +/// Takes a single token followed by a sequence of 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 { diff --git a/tests/ui/cast.rs b/tests/ui/cast.rs index 8b2673c2a7fdb..a86b85706a345 100644 --- a/tests/ui/cast.rs +++ b/tests/ui/cast.rs @@ -29,6 +29,12 @@ fn main() { 1f64 as isize; 1f64 as usize; 1f32 as u32 as u16; + { + let _x: i8 = 1i32 as _; + 1f32 as i32; + 1f64 as i32; + 1f32 as u8; + } // Test clippy::cast_possible_wrap 1u8 as i8; 1u16 as i16; diff --git a/tests/ui/cast.stderr b/tests/ui/cast.stderr index 451078de23b22..65ecf1aa37aaa 100644 --- a/tests/ui/cast.stderr +++ b/tests/ui/cast.stderr @@ -44,10 +44,6 @@ LL | 1f32 as i32; | = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... = note: `-D clippy::cast-possible-truncation` implied by `-D warnings` -help: ... or use `try_from` and handle the error accordingly - | -LL | i32::try_from(1f32); - | ~~~~~~~~~~~~~~~~~~~ error: casting `f32` to `u32` may truncate the value --> $DIR/cast.rs:25:5 @@ -56,10 +52,6 @@ LL | 1f32 as u32; | ^^^^^^^^^^^ | = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... -help: ... or use `try_from` and handle the error accordingly - | -LL | u32::try_from(1f32); - | ~~~~~~~~~~~~~~~~~~~ error: casting `f32` to `u32` may lose the sign of the value --> $DIR/cast.rs:25:5 @@ -76,10 +68,6 @@ LL | 1f64 as f32; | ^^^^^^^^^^^ | = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... -help: ... or use `try_from` and handle the error accordingly - | -LL | f32::try_from(1f64); - | ~~~~~~~~~~~~~~~~~~~ error: casting `i32` to `i8` may truncate the value --> $DIR/cast.rs:27:5 @@ -112,10 +100,6 @@ LL | 1f64 as isize; | ^^^^^^^^^^^^^ | = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... -help: ... or use `try_from` and handle the error accordingly - | -LL | isize::try_from(1f64); - | ~~~~~~~~~~~~~~~~~~~~~ error: casting `f64` to `usize` may truncate the value --> $DIR/cast.rs:30:5 @@ -124,10 +108,6 @@ LL | 1f64 as usize; | ^^^^^^^^^^^^^ | = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... -help: ... or use `try_from` and handle the error accordingly - | -LL | usize::try_from(1f64); - | ~~~~~~~~~~~~~~~~~~~~~ error: casting `f64` to `usize` may lose the sign of the value --> $DIR/cast.rs:30:5 @@ -154,10 +134,6 @@ LL | 1f32 as u32 as u16; | ^^^^^^^^^^^ | = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... -help: ... or use `try_from` and handle the error accordingly - | -LL | u32::try_from(1f32) as u16; - | ~~~~~~~~~~~~~~~~~~~ error: casting `f32` to `u32` may lose the sign of the value --> $DIR/cast.rs:31:5 @@ -165,8 +141,50 @@ error: casting `f32` to `u32` may lose the sign of the value LL | 1f32 as u32 as u16; | ^^^^^^^^^^^ +error: casting `i32` to `i8` may truncate the value + --> $DIR/cast.rs:33:22 + | +LL | let _x: i8 = 1i32 as _; + | ^^^^^^^^^ + | + = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... +help: ... or use `try_from` and handle the error accordingly + | +LL | let _x: i8 = 1i32.try_into(); + | ~~~~~~~~~~~~~~~ + +error: casting `f32` to `i32` may truncate the value + --> $DIR/cast.rs:34:9 + | +LL | 1f32 as i32; + | ^^^^^^^^^^^ + | + = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... + +error: casting `f64` to `i32` may truncate the value + --> $DIR/cast.rs:35:9 + | +LL | 1f64 as i32; + | ^^^^^^^^^^^ + | + = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... + +error: casting `f32` to `u8` may truncate the value + --> $DIR/cast.rs:36:9 + | +LL | 1f32 as u8; + | ^^^^^^^^^^ + | + = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... + +error: casting `f32` to `u8` may lose the sign of the value + --> $DIR/cast.rs:36:9 + | +LL | 1f32 as u8; + | ^^^^^^^^^^ + error: casting `u8` to `i8` may wrap around the value - --> $DIR/cast.rs:33:5 + --> $DIR/cast.rs:39:5 | LL | 1u8 as i8; | ^^^^^^^^^ @@ -174,43 +192,43 @@ LL | 1u8 as i8; = note: `-D clippy::cast-possible-wrap` implied by `-D warnings` error: casting `u16` to `i16` may wrap around the value - --> $DIR/cast.rs:34:5 + --> $DIR/cast.rs:40:5 | LL | 1u16 as i16; | ^^^^^^^^^^^ error: casting `u32` to `i32` may wrap around the value - --> $DIR/cast.rs:35:5 + --> $DIR/cast.rs:41:5 | LL | 1u32 as i32; | ^^^^^^^^^^^ error: casting `u64` to `i64` may wrap around the value - --> $DIR/cast.rs:36:5 + --> $DIR/cast.rs:42:5 | LL | 1u64 as i64; | ^^^^^^^^^^^ error: casting `usize` to `isize` may wrap around the value - --> $DIR/cast.rs:37:5 + --> $DIR/cast.rs:43:5 | LL | 1usize as isize; | ^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> $DIR/cast.rs:40:5 + --> $DIR/cast.rs:46:5 | LL | -1i32 as u32; | ^^^^^^^^^^^^ error: casting `isize` to `usize` may lose the sign of the value - --> $DIR/cast.rs:42:5 + --> $DIR/cast.rs:48:5 | LL | -1isize as usize; | ^^^^^^^^^^^^^^^^ error: casting `i64` to `i8` may truncate the value - --> $DIR/cast.rs:109:5 + --> $DIR/cast.rs:115:5 | LL | (-99999999999i64).min(1) as i8; // should be linted because signed | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -222,7 +240,7 @@ LL | i8::try_from((-99999999999i64).min(1)); // should be linted because sig | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: casting `u64` to `u8` may truncate the value - --> $DIR/cast.rs:121:5 + --> $DIR/cast.rs:127:5 | LL | 999999u64.clamp(0, 256) as u8; // should still be linted | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -234,7 +252,7 @@ LL | u8::try_from(999999u64.clamp(0, 256)); // should still be linted | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: casting `main::E2` to `u8` may truncate the value - --> $DIR/cast.rs:142:21 + --> $DIR/cast.rs:148:21 | LL | let _ = self as u8; | ^^^^^^^^^^ @@ -246,7 +264,7 @@ LL | let _ = u8::try_from(self); | ~~~~~~~~~~~~~~~~~~ error: casting `main::E2::B` to `u8` will truncate the value - --> $DIR/cast.rs:143:21 + --> $DIR/cast.rs:149:21 | LL | let _ = Self::B as u8; | ^^^^^^^^^^^^^ @@ -254,7 +272,7 @@ LL | let _ = Self::B as u8; = note: `-D clippy::cast-enum-truncation` implied by `-D warnings` error: casting `main::E5` to `i8` may truncate the value - --> $DIR/cast.rs:179:21 + --> $DIR/cast.rs:185:21 | LL | let _ = self as i8; | ^^^^^^^^^^ @@ -266,13 +284,13 @@ LL | let _ = i8::try_from(self); | ~~~~~~~~~~~~~~~~~~ error: casting `main::E5::A` to `i8` will truncate the value - --> $DIR/cast.rs:180:21 + --> $DIR/cast.rs:186:21 | LL | let _ = Self::A as i8; | ^^^^^^^^^^^^^ error: casting `main::E6` to `i16` may truncate the value - --> $DIR/cast.rs:194:21 + --> $DIR/cast.rs:200:21 | LL | let _ = self as i16; | ^^^^^^^^^^^ @@ -284,7 +302,7 @@ LL | let _ = i16::try_from(self); | ~~~~~~~~~~~~~~~~~~~ error: casting `main::E7` to `usize` may truncate the value on targets with 32-bit wide pointers - --> $DIR/cast.rs:209:21 + --> $DIR/cast.rs:215:21 | LL | let _ = self as usize; | ^^^^^^^^^^^^^ @@ -296,7 +314,7 @@ LL | let _ = usize::try_from(self); | ~~~~~~~~~~~~~~~~~~~~~ error: casting `main::E10` to `u16` may truncate the value - --> $DIR/cast.rs:250:21 + --> $DIR/cast.rs:256:21 | LL | let _ = self as u16; | ^^^^^^^^^^^ @@ -308,7 +326,7 @@ LL | let _ = u16::try_from(self); | ~~~~~~~~~~~~~~~~~~~ error: casting `u32` to `u8` may truncate the value - --> $DIR/cast.rs:258:13 + --> $DIR/cast.rs:264:13 | LL | let c = (q >> 16) as u8; | ^^^^^^^^^^^^^^^ @@ -316,11 +334,11 @@ LL | let c = (q >> 16) as u8; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... help: ... or use `try_from` and handle the error accordingly | -LL | let c = u8::try_from((q >> 16)); - | ~~~~~~~~~~~~~~~~~~~~~~~ +LL | let c = u8::try_from(q >> 16); + | ~~~~~~~~~~~~~~~~~~~~~ error: casting `u32` to `u8` may truncate the value - --> $DIR/cast.rs:261:13 + --> $DIR/cast.rs:267:13 | LL | let c = (q / 1000) as u8; | ^^^^^^^^^^^^^^^^ @@ -328,8 +346,8 @@ LL | let c = (q / 1000) as u8; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... help: ... or use `try_from` and handle the error accordingly | -LL | let c = u8::try_from((q / 1000)); - | ~~~~~~~~~~~~~~~~~~~~~~~~ +LL | let c = u8::try_from(q / 1000); + | ~~~~~~~~~~~~~~~~~~~~~~ -error: aborting due to 36 previous errors +error: aborting due to 41 previous errors diff --git a/tests/ui/clear_with_drain.fixed b/tests/ui/clear_with_drain.fixed new file mode 100644 index 0000000000000..2d9545eeed197 --- /dev/null +++ b/tests/ui/clear_with_drain.fixed @@ -0,0 +1,358 @@ +// run-rustfix +#![allow(unused)] +#![warn(clippy::clear_with_drain)] + +use std::collections::{BinaryHeap, HashMap, HashSet, VecDeque}; + +fn vec_range() { + // Do not lint because iterator is assigned + let mut v = vec![1, 2, 3]; + let iter = v.drain(0..v.len()); + + // Do not lint because iterator is used + let mut v = vec![1, 2, 3]; + let n = v.drain(0..v.len()).count(); + + // Do not lint because iterator is assigned and used + let mut v = vec![1, 2, 3]; + let iter = v.drain(usize::MIN..v.len()); + let n = iter.count(); + + // Do lint + let mut v = vec![1, 2, 3]; + v.clear(); + + // Do lint + let mut v = vec![1, 2, 3]; + v.clear(); +} + +fn vec_range_from() { + // Do not lint because iterator is assigned + let mut v = vec![1, 2, 3]; + let iter = v.drain(0..); + + // Do not lint because iterator is assigned and used + let mut v = vec![1, 2, 3]; + let mut iter = v.drain(0..); + let next = iter.next(); + + // Do not lint because iterator is used + let mut v = vec![1, 2, 3]; + let next = v.drain(usize::MIN..).next(); + + // Do lint + let mut v = vec![1, 2, 3]; + v.clear(); + + // Do lint + let mut v = vec![1, 2, 3]; + v.clear(); +} + +fn vec_range_full() { + // Do not lint because iterator is assigned + let mut v = vec![1, 2, 3]; + let iter = v.drain(..); + + // Do not lint because iterator is used + let mut v = vec![1, 2, 3]; + for x in v.drain(..) { + let y = format!("x = {x}"); + } + + // Do lint + let mut v = vec![1, 2, 3]; + v.clear(); +} + +fn vec_range_to() { + // Do not lint because iterator is assigned + let mut v = vec![1, 2, 3]; + let iter = v.drain(..v.len()); + + // Do not lint because iterator is assigned and used + let mut v = vec![1, 2, 3]; + let iter = v.drain(..v.len()); + for x in iter { + let y = format!("x = {x}"); + } + + // Do lint + let mut v = vec![1, 2, 3]; + v.clear(); +} + +fn vec_partial_drains() { + // Do not lint any of these because the ranges are not full + + let mut v = vec![1, 2, 3]; + v.drain(1..); + let mut v = vec![1, 2, 3]; + v.drain(1..).max(); + + let mut v = vec![1, 2, 3]; + v.drain(..v.len() - 1); + let mut v = vec![1, 2, 3]; + v.drain(..v.len() - 1).min(); + + let mut v = vec![1, 2, 3]; + v.drain(1..v.len() - 1); + let mut v = vec![1, 2, 3]; + let w: Vec = v.drain(1..v.len() - 1).collect(); +} + +fn vec_deque_range() { + // Do not lint because iterator is assigned + let mut deque = VecDeque::from([1, 2, 3]); + let iter = deque.drain(0..deque.len()); + + // Do not lint because iterator is used + let mut deque = VecDeque::from([1, 2, 3]); + let n = deque.drain(0..deque.len()).count(); + + // Do not lint because iterator is assigned and used + let mut deque = VecDeque::from([1, 2, 3]); + let iter = deque.drain(usize::MIN..deque.len()); + let n = iter.count(); + + // Do lint + let mut deque = VecDeque::from([1, 2, 3]); + deque.clear(); + + // Do lint + let mut deque = VecDeque::from([1, 2, 3]); + deque.clear(); +} + +fn vec_deque_range_from() { + // Do not lint because iterator is assigned + let mut deque = VecDeque::from([1, 2, 3]); + let iter = deque.drain(0..); + + // Do not lint because iterator is assigned and used + let mut deque = VecDeque::from([1, 2, 3]); + let mut iter = deque.drain(0..); + let next = iter.next(); + + // Do not lint because iterator is used + let mut deque = VecDeque::from([1, 2, 3]); + let next = deque.drain(usize::MIN..).next(); + + // Do lint + let mut deque = VecDeque::from([1, 2, 3]); + deque.clear(); + + // Do lint + let mut deque = VecDeque::from([1, 2, 3]); + deque.clear(); +} + +fn vec_deque_range_full() { + // Do not lint because iterator is assigned + let mut deque = VecDeque::from([1, 2, 3]); + let iter = deque.drain(..); + + // Do not lint because iterator is used + let mut deque = VecDeque::from([1, 2, 3]); + for x in deque.drain(..) { + let y = format!("x = {x}"); + } + + // Do lint + let mut deque = VecDeque::from([1, 2, 3]); + deque.clear(); +} + +fn vec_deque_range_to() { + // Do not lint because iterator is assigned + let mut deque = VecDeque::from([1, 2, 3]); + let iter = deque.drain(..deque.len()); + + // Do not lint because iterator is assigned and used + let mut deque = VecDeque::from([1, 2, 3]); + let iter = deque.drain(..deque.len()); + for x in iter { + let y = format!("x = {x}"); + } + + // Do lint + let mut deque = VecDeque::from([1, 2, 3]); + deque.clear(); +} + +fn vec_deque_partial_drains() { + // Do not lint any of these because the ranges are not full + + let mut deque = VecDeque::from([1, 2, 3]); + deque.drain(1..); + let mut deque = VecDeque::from([1, 2, 3]); + deque.drain(1..).max(); + + let mut deque = VecDeque::from([1, 2, 3]); + deque.drain(..deque.len() - 1); + let mut deque = VecDeque::from([1, 2, 3]); + deque.drain(..deque.len() - 1).min(); + + let mut deque = VecDeque::from([1, 2, 3]); + deque.drain(1..deque.len() - 1); + let mut deque = VecDeque::from([1, 2, 3]); + let w: Vec = deque.drain(1..deque.len() - 1).collect(); +} + +fn string_range() { + // Do not lint because iterator is assigned + let mut s = String::from("Hello, world!"); + let iter = s.drain(0..s.len()); + + // Do not lint because iterator is used + let mut s = String::from("Hello, world!"); + let n = s.drain(0..s.len()).count(); + + // Do not lint because iterator is assigned and used + let mut s = String::from("Hello, world!"); + let iter = s.drain(usize::MIN..s.len()); + let n = iter.count(); + + // Do lint + let mut s = String::from("Hello, world!"); + s.clear(); + + // Do lint + let mut s = String::from("Hello, world!"); + s.clear(); +} + +fn string_range_from() { + // Do not lint because iterator is assigned + let mut s = String::from("Hello, world!"); + let iter = s.drain(0..); + + // Do not lint because iterator is assigned and used + let mut s = String::from("Hello, world!"); + let mut iter = s.drain(0..); + let next = iter.next(); + + // Do not lint because iterator is used + let mut s = String::from("Hello, world!"); + let next = s.drain(usize::MIN..).next(); + + // Do lint + let mut s = String::from("Hello, world!"); + s.clear(); + + // Do lint + let mut s = String::from("Hello, world!"); + s.clear(); +} + +fn string_range_full() { + // Do not lint because iterator is assigned + let mut s = String::from("Hello, world!"); + let iter = s.drain(..); + + // Do not lint because iterator is used + let mut s = String::from("Hello, world!"); + for x in s.drain(..) { + let y = format!("x = {x}"); + } + + // Do lint + let mut s = String::from("Hello, world!"); + s.clear(); +} + +fn string_range_to() { + // Do not lint because iterator is assigned + let mut s = String::from("Hello, world!"); + let iter = s.drain(..s.len()); + + // Do not lint because iterator is assigned and used + let mut s = String::from("Hello, world!"); + let iter = s.drain(..s.len()); + for x in iter { + let y = format!("x = {x}"); + } + + // Do lint + let mut s = String::from("Hello, world!"); + s.clear(); +} + +fn string_partial_drains() { + // Do not lint any of these because the ranges are not full + + let mut s = String::from("Hello, world!"); + s.drain(1..); + let mut s = String::from("Hello, world!"); + s.drain(1..).max(); + + let mut s = String::from("Hello, world!"); + s.drain(..s.len() - 1); + let mut s = String::from("Hello, world!"); + s.drain(..s.len() - 1).min(); + + let mut s = String::from("Hello, world!"); + s.drain(1..s.len() - 1); + let mut s = String::from("Hello, world!"); + let w: String = s.drain(1..s.len() - 1).collect(); +} + +fn hash_set() { + // Do not lint because iterator is assigned + let mut set = HashSet::from([1, 2, 3]); + let iter = set.drain(); + + // Do not lint because iterator is assigned and used + let mut set = HashSet::from([1, 2, 3]); + let mut iter = set.drain(); + let next = iter.next(); + + // Do not lint because iterator is used + let mut set = HashSet::from([1, 2, 3]); + let next = set.drain().next(); + + // Do lint + let mut set = HashSet::from([1, 2, 3]); + set.clear(); +} + +fn hash_map() { + // Do not lint because iterator is assigned + let mut map = HashMap::from([(1, "a"), (2, "b")]); + let iter = map.drain(); + + // Do not lint because iterator is assigned and used + let mut map = HashMap::from([(1, "a"), (2, "b")]); + let mut iter = map.drain(); + let next = iter.next(); + + // Do not lint because iterator is used + let mut map = HashMap::from([(1, "a"), (2, "b")]); + let next = map.drain().next(); + + // Do lint + let mut map = HashMap::from([(1, "a"), (2, "b")]); + map.clear(); +} + +fn binary_heap() { + // Do not lint because iterator is assigned + let mut heap = BinaryHeap::from([1, 2]); + let iter = heap.drain(); + + // Do not lint because iterator is assigned and used + let mut heap = BinaryHeap::from([1, 2]); + let mut iter = heap.drain(); + let next = iter.next(); + + // Do not lint because iterator is used + let mut heap = BinaryHeap::from([1, 2]); + let next = heap.drain().next(); + + // Do lint + let mut heap = BinaryHeap::from([1, 2]); + heap.clear(); +} + +fn main() {} diff --git a/tests/ui/clear_with_drain.rs b/tests/ui/clear_with_drain.rs new file mode 100644 index 0000000000000..4d60ee46e1865 --- /dev/null +++ b/tests/ui/clear_with_drain.rs @@ -0,0 +1,358 @@ +// run-rustfix +#![allow(unused)] +#![warn(clippy::clear_with_drain)] + +use std::collections::{BinaryHeap, HashMap, HashSet, VecDeque}; + +fn vec_range() { + // Do not lint because iterator is assigned + let mut v = vec![1, 2, 3]; + let iter = v.drain(0..v.len()); + + // Do not lint because iterator is used + let mut v = vec![1, 2, 3]; + let n = v.drain(0..v.len()).count(); + + // Do not lint because iterator is assigned and used + let mut v = vec![1, 2, 3]; + let iter = v.drain(usize::MIN..v.len()); + let n = iter.count(); + + // Do lint + let mut v = vec![1, 2, 3]; + v.drain(0..v.len()); + + // Do lint + let mut v = vec![1, 2, 3]; + v.drain(usize::MIN..v.len()); +} + +fn vec_range_from() { + // Do not lint because iterator is assigned + let mut v = vec![1, 2, 3]; + let iter = v.drain(0..); + + // Do not lint because iterator is assigned and used + let mut v = vec![1, 2, 3]; + let mut iter = v.drain(0..); + let next = iter.next(); + + // Do not lint because iterator is used + let mut v = vec![1, 2, 3]; + let next = v.drain(usize::MIN..).next(); + + // Do lint + let mut v = vec![1, 2, 3]; + v.drain(0..); + + // Do lint + let mut v = vec![1, 2, 3]; + v.drain(usize::MIN..); +} + +fn vec_range_full() { + // Do not lint because iterator is assigned + let mut v = vec![1, 2, 3]; + let iter = v.drain(..); + + // Do not lint because iterator is used + let mut v = vec![1, 2, 3]; + for x in v.drain(..) { + let y = format!("x = {x}"); + } + + // Do lint + let mut v = vec![1, 2, 3]; + v.drain(..); +} + +fn vec_range_to() { + // Do not lint because iterator is assigned + let mut v = vec![1, 2, 3]; + let iter = v.drain(..v.len()); + + // Do not lint because iterator is assigned and used + let mut v = vec![1, 2, 3]; + let iter = v.drain(..v.len()); + for x in iter { + let y = format!("x = {x}"); + } + + // Do lint + let mut v = vec![1, 2, 3]; + v.drain(..v.len()); +} + +fn vec_partial_drains() { + // Do not lint any of these because the ranges are not full + + let mut v = vec![1, 2, 3]; + v.drain(1..); + let mut v = vec![1, 2, 3]; + v.drain(1..).max(); + + let mut v = vec![1, 2, 3]; + v.drain(..v.len() - 1); + let mut v = vec![1, 2, 3]; + v.drain(..v.len() - 1).min(); + + let mut v = vec![1, 2, 3]; + v.drain(1..v.len() - 1); + let mut v = vec![1, 2, 3]; + let w: Vec = v.drain(1..v.len() - 1).collect(); +} + +fn vec_deque_range() { + // Do not lint because iterator is assigned + let mut deque = VecDeque::from([1, 2, 3]); + let iter = deque.drain(0..deque.len()); + + // Do not lint because iterator is used + let mut deque = VecDeque::from([1, 2, 3]); + let n = deque.drain(0..deque.len()).count(); + + // Do not lint because iterator is assigned and used + let mut deque = VecDeque::from([1, 2, 3]); + let iter = deque.drain(usize::MIN..deque.len()); + let n = iter.count(); + + // Do lint + let mut deque = VecDeque::from([1, 2, 3]); + deque.drain(0..deque.len()); + + // Do lint + let mut deque = VecDeque::from([1, 2, 3]); + deque.drain(usize::MIN..deque.len()); +} + +fn vec_deque_range_from() { + // Do not lint because iterator is assigned + let mut deque = VecDeque::from([1, 2, 3]); + let iter = deque.drain(0..); + + // Do not lint because iterator is assigned and used + let mut deque = VecDeque::from([1, 2, 3]); + let mut iter = deque.drain(0..); + let next = iter.next(); + + // Do not lint because iterator is used + let mut deque = VecDeque::from([1, 2, 3]); + let next = deque.drain(usize::MIN..).next(); + + // Do lint + let mut deque = VecDeque::from([1, 2, 3]); + deque.drain(0..); + + // Do lint + let mut deque = VecDeque::from([1, 2, 3]); + deque.drain(usize::MIN..); +} + +fn vec_deque_range_full() { + // Do not lint because iterator is assigned + let mut deque = VecDeque::from([1, 2, 3]); + let iter = deque.drain(..); + + // Do not lint because iterator is used + let mut deque = VecDeque::from([1, 2, 3]); + for x in deque.drain(..) { + let y = format!("x = {x}"); + } + + // Do lint + let mut deque = VecDeque::from([1, 2, 3]); + deque.drain(..); +} + +fn vec_deque_range_to() { + // Do not lint because iterator is assigned + let mut deque = VecDeque::from([1, 2, 3]); + let iter = deque.drain(..deque.len()); + + // Do not lint because iterator is assigned and used + let mut deque = VecDeque::from([1, 2, 3]); + let iter = deque.drain(..deque.len()); + for x in iter { + let y = format!("x = {x}"); + } + + // Do lint + let mut deque = VecDeque::from([1, 2, 3]); + deque.drain(..deque.len()); +} + +fn vec_deque_partial_drains() { + // Do not lint any of these because the ranges are not full + + let mut deque = VecDeque::from([1, 2, 3]); + deque.drain(1..); + let mut deque = VecDeque::from([1, 2, 3]); + deque.drain(1..).max(); + + let mut deque = VecDeque::from([1, 2, 3]); + deque.drain(..deque.len() - 1); + let mut deque = VecDeque::from([1, 2, 3]); + deque.drain(..deque.len() - 1).min(); + + let mut deque = VecDeque::from([1, 2, 3]); + deque.drain(1..deque.len() - 1); + let mut deque = VecDeque::from([1, 2, 3]); + let w: Vec = deque.drain(1..deque.len() - 1).collect(); +} + +fn string_range() { + // Do not lint because iterator is assigned + let mut s = String::from("Hello, world!"); + let iter = s.drain(0..s.len()); + + // Do not lint because iterator is used + let mut s = String::from("Hello, world!"); + let n = s.drain(0..s.len()).count(); + + // Do not lint because iterator is assigned and used + let mut s = String::from("Hello, world!"); + let iter = s.drain(usize::MIN..s.len()); + let n = iter.count(); + + // Do lint + let mut s = String::from("Hello, world!"); + s.drain(0..s.len()); + + // Do lint + let mut s = String::from("Hello, world!"); + s.drain(usize::MIN..s.len()); +} + +fn string_range_from() { + // Do not lint because iterator is assigned + let mut s = String::from("Hello, world!"); + let iter = s.drain(0..); + + // Do not lint because iterator is assigned and used + let mut s = String::from("Hello, world!"); + let mut iter = s.drain(0..); + let next = iter.next(); + + // Do not lint because iterator is used + let mut s = String::from("Hello, world!"); + let next = s.drain(usize::MIN..).next(); + + // Do lint + let mut s = String::from("Hello, world!"); + s.drain(0..); + + // Do lint + let mut s = String::from("Hello, world!"); + s.drain(usize::MIN..); +} + +fn string_range_full() { + // Do not lint because iterator is assigned + let mut s = String::from("Hello, world!"); + let iter = s.drain(..); + + // Do not lint because iterator is used + let mut s = String::from("Hello, world!"); + for x in s.drain(..) { + let y = format!("x = {x}"); + } + + // Do lint + let mut s = String::from("Hello, world!"); + s.drain(..); +} + +fn string_range_to() { + // Do not lint because iterator is assigned + let mut s = String::from("Hello, world!"); + let iter = s.drain(..s.len()); + + // Do not lint because iterator is assigned and used + let mut s = String::from("Hello, world!"); + let iter = s.drain(..s.len()); + for x in iter { + let y = format!("x = {x}"); + } + + // Do lint + let mut s = String::from("Hello, world!"); + s.drain(..s.len()); +} + +fn string_partial_drains() { + // Do not lint any of these because the ranges are not full + + let mut s = String::from("Hello, world!"); + s.drain(1..); + let mut s = String::from("Hello, world!"); + s.drain(1..).max(); + + let mut s = String::from("Hello, world!"); + s.drain(..s.len() - 1); + let mut s = String::from("Hello, world!"); + s.drain(..s.len() - 1).min(); + + let mut s = String::from("Hello, world!"); + s.drain(1..s.len() - 1); + let mut s = String::from("Hello, world!"); + let w: String = s.drain(1..s.len() - 1).collect(); +} + +fn hash_set() { + // Do not lint because iterator is assigned + let mut set = HashSet::from([1, 2, 3]); + let iter = set.drain(); + + // Do not lint because iterator is assigned and used + let mut set = HashSet::from([1, 2, 3]); + let mut iter = set.drain(); + let next = iter.next(); + + // Do not lint because iterator is used + let mut set = HashSet::from([1, 2, 3]); + let next = set.drain().next(); + + // Do lint + let mut set = HashSet::from([1, 2, 3]); + set.drain(); +} + +fn hash_map() { + // Do not lint because iterator is assigned + let mut map = HashMap::from([(1, "a"), (2, "b")]); + let iter = map.drain(); + + // Do not lint because iterator is assigned and used + let mut map = HashMap::from([(1, "a"), (2, "b")]); + let mut iter = map.drain(); + let next = iter.next(); + + // Do not lint because iterator is used + let mut map = HashMap::from([(1, "a"), (2, "b")]); + let next = map.drain().next(); + + // Do lint + let mut map = HashMap::from([(1, "a"), (2, "b")]); + map.drain(); +} + +fn binary_heap() { + // Do not lint because iterator is assigned + let mut heap = BinaryHeap::from([1, 2]); + let iter = heap.drain(); + + // Do not lint because iterator is assigned and used + let mut heap = BinaryHeap::from([1, 2]); + let mut iter = heap.drain(); + let next = iter.next(); + + // Do not lint because iterator is used + let mut heap = BinaryHeap::from([1, 2]); + let next = heap.drain().next(); + + // Do lint + let mut heap = BinaryHeap::from([1, 2]); + heap.drain(); +} + +fn main() {} diff --git a/tests/ui/clear_with_drain.stderr b/tests/ui/clear_with_drain.stderr new file mode 100644 index 0000000000000..20158da1121b7 --- /dev/null +++ b/tests/ui/clear_with_drain.stderr @@ -0,0 +1,130 @@ +error: `drain` used to clear a `Vec` + --> $DIR/clear_with_drain.rs:23:7 + | +LL | v.drain(0..v.len()); + | ^^^^^^^^^^^^^^^^^ help: try: `clear()` + | + = note: `-D clippy::clear-with-drain` implied by `-D warnings` + +error: `drain` used to clear a `Vec` + --> $DIR/clear_with_drain.rs:27:7 + | +LL | v.drain(usize::MIN..v.len()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `clear()` + +error: `drain` used to clear a `Vec` + --> $DIR/clear_with_drain.rs:46:7 + | +LL | v.drain(0..); + | ^^^^^^^^^^ help: try: `clear()` + +error: `drain` used to clear a `Vec` + --> $DIR/clear_with_drain.rs:50:7 + | +LL | v.drain(usize::MIN..); + | ^^^^^^^^^^^^^^^^^^^ help: try: `clear()` + +error: `drain` used to clear a `Vec` + --> $DIR/clear_with_drain.rs:66:7 + | +LL | v.drain(..); + | ^^^^^^^^^ help: try: `clear()` + +error: `drain` used to clear a `Vec` + --> $DIR/clear_with_drain.rs:83:7 + | +LL | v.drain(..v.len()); + | ^^^^^^^^^^^^^^^^ help: try: `clear()` + +error: `drain` used to clear a `VecDeque` + --> $DIR/clear_with_drain.rs:121:11 + | +LL | deque.drain(0..deque.len()); + | ^^^^^^^^^^^^^^^^^^^^^ help: try: `clear()` + +error: `drain` used to clear a `VecDeque` + --> $DIR/clear_with_drain.rs:125:11 + | +LL | deque.drain(usize::MIN..deque.len()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `clear()` + +error: `drain` used to clear a `VecDeque` + --> $DIR/clear_with_drain.rs:144:11 + | +LL | deque.drain(0..); + | ^^^^^^^^^^ help: try: `clear()` + +error: `drain` used to clear a `VecDeque` + --> $DIR/clear_with_drain.rs:148:11 + | +LL | deque.drain(usize::MIN..); + | ^^^^^^^^^^^^^^^^^^^ help: try: `clear()` + +error: `drain` used to clear a `VecDeque` + --> $DIR/clear_with_drain.rs:164:11 + | +LL | deque.drain(..); + | ^^^^^^^^^ help: try: `clear()` + +error: `drain` used to clear a `VecDeque` + --> $DIR/clear_with_drain.rs:181:11 + | +LL | deque.drain(..deque.len()); + | ^^^^^^^^^^^^^^^^^^^^ help: try: `clear()` + +error: `drain` used to clear a `String` + --> $DIR/clear_with_drain.rs:219:7 + | +LL | s.drain(0..s.len()); + | ^^^^^^^^^^^^^^^^^ help: try: `clear()` + +error: `drain` used to clear a `String` + --> $DIR/clear_with_drain.rs:223:7 + | +LL | s.drain(usize::MIN..s.len()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `clear()` + +error: `drain` used to clear a `String` + --> $DIR/clear_with_drain.rs:242:7 + | +LL | s.drain(0..); + | ^^^^^^^^^^ help: try: `clear()` + +error: `drain` used to clear a `String` + --> $DIR/clear_with_drain.rs:246:7 + | +LL | s.drain(usize::MIN..); + | ^^^^^^^^^^^^^^^^^^^ help: try: `clear()` + +error: `drain` used to clear a `String` + --> $DIR/clear_with_drain.rs:262:7 + | +LL | s.drain(..); + | ^^^^^^^^^ help: try: `clear()` + +error: `drain` used to clear a `String` + --> $DIR/clear_with_drain.rs:279:7 + | +LL | s.drain(..s.len()); + | ^^^^^^^^^^^^^^^^ help: try: `clear()` + +error: `drain` used to clear a `HashSet` + --> $DIR/clear_with_drain.rs:317:9 + | +LL | set.drain(); + | ^^^^^^^ help: try: `clear()` + +error: `drain` used to clear a `HashMap` + --> $DIR/clear_with_drain.rs:336:9 + | +LL | map.drain(); + | ^^^^^^^ help: try: `clear()` + +error: `drain` used to clear a `BinaryHeap` + --> $DIR/clear_with_drain.rs:355:10 + | +LL | heap.drain(); + | ^^^^^^^ help: try: `clear()` + +error: aborting due to 21 previous errors + diff --git a/tests/ui/collection_is_never_read.rs b/tests/ui/collection_is_never_read.rs index 068a49486cf8a..01259a983ab6f 100644 --- a/tests/ui/collection_is_never_read.rs +++ b/tests/ui/collection_is_never_read.rs @@ -84,13 +84,18 @@ fn shadowing_2() { } #[allow(clippy::let_unit_value)] -fn fake_read() { - let mut x = vec![1, 2, 3]; // Ok +fn fake_read_1() { + let mut x = vec![1, 2, 3]; // WARNING x.reverse(); - // `collection_is_never_read` gets fooled, but other lints should catch this. let _: () = x.clear(); } +fn fake_read_2() { + let mut x = vec![1, 2, 3]; // WARNING + x.reverse(); + println!("{:?}", x.push(5)); +} + fn assignment() { let mut x = vec![1, 2, 3]; // WARNING let y = vec![4, 5, 6]; // Ok @@ -163,3 +168,23 @@ fn function_argument() { let x = vec![1, 2, 3]; // Ok foo(&x); } + +fn string() { + // Do lint (write without read) + let mut s = String::new(); + s.push_str("Hello, World!"); + + // Do not lint (read without write) + let mut s = String::from("Hello, World!"); + let _ = s.len(); + + // Do not lint (write and read) + let mut s = String::from("Hello, World!"); + s.push_str("foo, bar"); + let _ = s.len(); + + // Do lint the first line, but not the second + let mut s = String::from("Hello, World!"); + let t = String::from("foo, bar"); + s = t; +} diff --git a/tests/ui/collection_is_never_read.stderr b/tests/ui/collection_is_never_read.stderr index 7654b74be3d17..cf51a53686f2d 100644 --- a/tests/ui/collection_is_never_read.stderr +++ b/tests/ui/collection_is_never_read.stderr @@ -25,28 +25,52 @@ LL | let mut x = HashMap::new(); // WARNING | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: collection is never read - --> $DIR/collection_is_never_read.rs:95:5 + --> $DIR/collection_is_never_read.rs:88:5 | LL | let mut x = vec![1, 2, 3]; // WARNING | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: collection is never read - --> $DIR/collection_is_never_read.rs:102:5 + --> $DIR/collection_is_never_read.rs:94:5 | LL | let mut x = vec![1, 2, 3]; // WARNING | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: collection is never read - --> $DIR/collection_is_never_read.rs:119:5 + --> $DIR/collection_is_never_read.rs:100:5 + | +LL | let mut x = vec![1, 2, 3]; // WARNING + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: collection is never read + --> $DIR/collection_is_never_read.rs:107:5 + | +LL | let mut x = vec![1, 2, 3]; // WARNING + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: collection is never read + --> $DIR/collection_is_never_read.rs:124:5 | LL | let mut x = HashSet::new(); // WARNING | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: collection is never read - --> $DIR/collection_is_never_read.rs:133:5 + --> $DIR/collection_is_never_read.rs:138:5 | LL | let x = vec![1, 2, 3]; // WARNING | ^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 8 previous errors +error: collection is never read + --> $DIR/collection_is_never_read.rs:174:5 + | +LL | let mut s = String::new(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: collection is never read + --> $DIR/collection_is_never_read.rs:187:5 + | +LL | let mut s = String::from("Hello, World!"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 12 previous errors diff --git a/tests/ui/double_must_use.rs b/tests/ui/double_must_use.rs index 05e087b08bc14..26a387b3cf049 100644 --- a/tests/ui/double_must_use.rs +++ b/tests/ui/double_must_use.rs @@ -21,6 +21,17 @@ pub fn must_use_with_note() -> Result<(), ()> { unimplemented!(); } +// vvvv Should not lint (#10486) +#[must_use] +async fn async_must_use() -> usize { + unimplemented!(); +} + +#[must_use] +async fn async_must_use_result() -> Result<(), ()> { + Ok(()) +} + fn main() { must_use_result(); must_use_tuple(); diff --git a/tests/ui/double_must_use.stderr b/tests/ui/double_must_use.stderr index 3d34557a881bd..49ab2ea3e12b4 100644 --- a/tests/ui/double_must_use.stderr +++ b/tests/ui/double_must_use.stderr @@ -23,5 +23,13 @@ LL | pub fn must_use_array() -> [Result<(), ()>; 1] { | = help: either add some descriptive text or remove the attribute -error: aborting due to 3 previous errors +error: this function has an empty `#[must_use]` attribute, but returns a type already marked as `#[must_use]` + --> $DIR/double_must_use.rs:31:1 + | +LL | async fn async_must_use_result() -> Result<(), ()> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: either add some descriptive text or remove the attribute + +error: aborting due to 4 previous errors diff --git a/tests/ui/extra_unused_type_parameters.fixed b/tests/ui/extra_unused_type_parameters.fixed new file mode 100644 index 0000000000000..19e718625582c --- /dev/null +++ b/tests/ui/extra_unused_type_parameters.fixed @@ -0,0 +1,105 @@ +// run-rustfix + +#![allow(unused, clippy::needless_lifetimes)] +#![warn(clippy::extra_unused_type_parameters)] + +fn unused_ty(x: u8) { + unimplemented!() +} + +fn unused_multi(x: u8) { + unimplemented!() +} + +fn unused_with_lt<'a>(x: &'a u8) { + unimplemented!() +} + +fn used_ty(x: T, y: u8) {} + +fn used_ref<'a, T>(x: &'a T) {} + +fn used_ret(x: u8) -> T { + T::default() +} + +fn unused_bounded(x: U) { + unimplemented!(); +} + +fn some_unused(b: B, c: C) { + unimplemented!(); +} + +fn used_opaque(iter: impl Iterator) -> usize { + iter.count() +} + +fn used_ret_opaque() -> impl Iterator { + std::iter::empty() +} + +fn used_vec_box(x: Vec>) {} + +fn used_body() -> String { + T::default().to_string() +} + +fn used_closure() -> impl Fn() { + || println!("{}", T::default().to_string()) +} + +struct S; + +impl S { + fn unused_ty_impl(&self) { + unimplemented!() + } +} + +// Don't lint on trait methods +trait Foo { + fn bar(&self); +} + +impl Foo for S { + fn bar(&self) {} +} + +fn skip_index(iter: Iter, index: usize) -> impl Iterator +where + Iter: Iterator, +{ + iter.enumerate() + .filter_map(move |(i, a)| if i == index { None } else { Some(a) }) +} + +fn unused_opaque(dummy: impl Default) { + unimplemented!() +} + +mod unexported_trait_bounds { + mod private { + pub trait Private {} + } + + fn priv_trait_bound() { + unimplemented!(); + } + + fn unused_with_priv_trait_bound() { + unimplemented!(); + } +} + +mod issue10319 { + fn assert_send() {} + + fn assert_send_where() + where + T: Send, + { + } +} + +fn main() {} diff --git a/tests/ui/extra_unused_type_parameters.rs b/tests/ui/extra_unused_type_parameters.rs index 4801743427657..e53bb587e89ac 100644 --- a/tests/ui/extra_unused_type_parameters.rs +++ b/tests/ui/extra_unused_type_parameters.rs @@ -1,3 +1,5 @@ +// run-rustfix + #![allow(unused, clippy::needless_lifetimes)] #![warn(clippy::extra_unused_type_parameters)] @@ -21,14 +23,7 @@ fn used_ret(x: u8) -> T { T::default() } -fn unused_bounded(x: U) { - unimplemented!(); -} - -fn unused_where_clause(x: U) -where - T: Default, -{ +fn unused_bounded(x: U) { unimplemented!(); } diff --git a/tests/ui/extra_unused_type_parameters.stderr b/tests/ui/extra_unused_type_parameters.stderr index 86c88fc9bf006..c042a5a2290e5 100644 --- a/tests/ui/extra_unused_type_parameters.stderr +++ b/tests/ui/extra_unused_type_parameters.stderr @@ -1,75 +1,64 @@ -error: type parameter goes unused in function definition - --> $DIR/extra_unused_type_parameters.rs:4:13 +error: type parameter `T` goes unused in function definition + --> $DIR/extra_unused_type_parameters.rs:6:13 | LL | fn unused_ty(x: u8) { - | ^^^ + | ^^^ help: consider removing the parameter | - = help: consider removing the parameter = note: `-D clippy::extra-unused-type-parameters` implied by `-D warnings` -error: type parameters go unused in function definition - --> $DIR/extra_unused_type_parameters.rs:8:16 +error: type parameters go unused in function definition: T, U + --> $DIR/extra_unused_type_parameters.rs:10:16 | LL | fn unused_multi(x: u8) { - | ^^^^^^ - | - = help: consider removing the parameters + | ^^^^^^ help: consider removing the parameters -error: type parameter goes unused in function definition - --> $DIR/extra_unused_type_parameters.rs:12:23 +error: type parameter `T` goes unused in function definition + --> $DIR/extra_unused_type_parameters.rs:14:21 | LL | fn unused_with_lt<'a, T>(x: &'a u8) { - | ^ - | - = help: consider removing the parameter + | ^^^ help: consider removing the parameter -error: type parameter goes unused in function definition - --> $DIR/extra_unused_type_parameters.rs:24:19 +error: type parameters go unused in function definition: T, V + --> $DIR/extra_unused_type_parameters.rs:26:19 | -LL | fn unused_bounded(x: U) { - | ^^^^^^^^^^^ +LL | fn unused_bounded(x: U) { + | ^^^^^^^^^^^^ ^^^^^^^^^^^^ | - = help: consider removing the parameter - -error: type parameter goes unused in function definition - --> $DIR/extra_unused_type_parameters.rs:28:24 +help: consider removing the parameters | -LL | fn unused_where_clause(x: U) - | ^^ +LL - fn unused_bounded(x: U) { +LL + fn unused_bounded(x: U) { | - = help: consider removing the parameter -error: type parameters go unused in function definition - --> $DIR/extra_unused_type_parameters.rs:35:16 +error: type parameters go unused in function definition: A, D, E + --> $DIR/extra_unused_type_parameters.rs:30:16 | LL | fn some_unused, E>(b: B, c: C) { - | ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^ + | ^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider removing the parameters + | +LL - fn some_unused, E>(b: B, c: C) { +LL + fn some_unused(b: B, c: C) { | - = help: consider removing the parameters -error: type parameter goes unused in function definition - --> $DIR/extra_unused_type_parameters.rs:60:22 +error: type parameter `T` goes unused in function definition + --> $DIR/extra_unused_type_parameters.rs:55:22 | LL | fn unused_ty_impl(&self) { - | ^^^ - | - = help: consider removing the parameter + | ^^^ help: consider removing the parameter -error: type parameters go unused in function definition - --> $DIR/extra_unused_type_parameters.rs:82:17 +error: type parameters go unused in function definition: A, B + --> $DIR/extra_unused_type_parameters.rs:77:17 | LL | fn unused_opaque(dummy: impl Default) { - | ^^^^^^ - | - = help: consider removing the parameters + | ^^^^^^ help: consider removing the parameters -error: type parameter goes unused in function definition - --> $DIR/extra_unused_type_parameters.rs:95:58 +error: type parameter `U` goes unused in function definition + --> $DIR/extra_unused_type_parameters.rs:90:56 | LL | fn unused_with_priv_trait_bound() { - | ^ - | - = help: consider removing the parameter + | ^^^ help: consider removing the parameter -error: aborting due to 9 previous errors +error: aborting due to 8 previous errors diff --git a/tests/ui/extra_unused_type_parameters_unfixable.rs b/tests/ui/extra_unused_type_parameters_unfixable.rs new file mode 100644 index 0000000000000..10b39aa8f2c5b --- /dev/null +++ b/tests/ui/extra_unused_type_parameters_unfixable.rs @@ -0,0 +1,24 @@ +#![warn(clippy::extra_unused_type_parameters)] + +fn unused_where_clause(x: U) +where + T: Default, +{ + unimplemented!(); +} + +fn unused_multi_where_clause(x: U) +where + T: Default, +{ + unimplemented!(); +} + +fn unused_all_where_clause() +where + T: Default, +{ + unimplemented!(); +} + +fn main() {} diff --git a/tests/ui/extra_unused_type_parameters_unfixable.stderr b/tests/ui/extra_unused_type_parameters_unfixable.stderr new file mode 100644 index 0000000000000..a9580cc894f35 --- /dev/null +++ b/tests/ui/extra_unused_type_parameters_unfixable.stderr @@ -0,0 +1,27 @@ +error: type parameter `T` goes unused in function definition + --> $DIR/extra_unused_type_parameters_unfixable.rs:3:24 + | +LL | fn unused_where_clause(x: U) + | ^ + | + = help: consider removing the parameter + = note: `-D clippy::extra-unused-type-parameters` implied by `-D warnings` + +error: type parameters go unused in function definition: T, V + --> $DIR/extra_unused_type_parameters_unfixable.rs:10:30 + | +LL | fn unused_multi_where_clause(x: U) + | ^ ^^^^^^^^^^ + | + = help: consider removing the parameters + +error: type parameters go unused in function definition: T, U, V + --> $DIR/extra_unused_type_parameters_unfixable.rs:17:28 + | +LL | fn unused_all_where_clause() + | ^ ^^^^^^^^^^ ^^^^^^^^^^ + | + = help: consider removing the parameters + +error: aborting due to 3 previous errors + diff --git a/tests/ui/format_args_unfixable.rs b/tests/ui/format_args_unfixable.rs index eb0ac15bfbf12..423bfaf97965e 100644 --- a/tests/ui/format_args_unfixable.rs +++ b/tests/ui/format_args_unfixable.rs @@ -1,4 +1,5 @@ #![warn(clippy::format_in_format_args, clippy::to_string_in_format_args)] +#![allow(unused)] #![allow(clippy::assertions_on_constants, clippy::eq_op, clippy::uninlined_format_args)] use std::io::{stdout, Error, ErrorKind, Write}; @@ -57,3 +58,46 @@ fn main() { my_macro!(); println!("error: {}", my_other_macro!()); } + +macro_rules! _internal { + ($($args:tt)*) => { + println!("{}", format_args!($($args)*)) + }; +} + +macro_rules! my_println2 { + ($target:expr, $($args:tt)+) => {{ + if $target { + _internal!($($args)+) + } + }}; +} + +macro_rules! my_println2_args { + ($target:expr, $($args:tt)+) => {{ + if $target { + _internal!("foo: {}", format_args!($($args)+)) + } + }}; +} + +fn test2() { + let error = Error::new(ErrorKind::Other, "bad thing"); + + // None of these should be linted without the config change + my_println2!(true, "error: {}", format!("something failed at {}", Location::caller())); + my_println2!( + true, + "{}: {}", + error, + format!("something failed at {}", Location::caller()) + ); + + my_println2_args!(true, "error: {}", format!("something failed at {}", Location::caller())); + my_println2_args!( + true, + "{}: {}", + error, + format!("something failed at {}", Location::caller()) + ); +} diff --git a/tests/ui/format_args_unfixable.stderr b/tests/ui/format_args_unfixable.stderr index b291d475ad906..c1be48c3b7269 100644 --- a/tests/ui/format_args_unfixable.stderr +++ b/tests/ui/format_args_unfixable.stderr @@ -1,5 +1,5 @@ error: `format!` in `println!` args - --> $DIR/format_args_unfixable.rs:25:5 + --> $DIR/format_args_unfixable.rs:26:5 | LL | println!("error: {}", format!("something failed at {}", Location::caller())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -9,7 +9,7 @@ LL | println!("error: {}", format!("something failed at {}", Location::calle = note: `-D clippy::format-in-format-args` implied by `-D warnings` error: `format!` in `println!` args - --> $DIR/format_args_unfixable.rs:26:5 + --> $DIR/format_args_unfixable.rs:27:5 | LL | println!("{}: {}", error, format!("something failed at {}", Location::caller())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -18,7 +18,7 @@ LL | println!("{}: {}", error, format!("something failed at {}", Location::c = help: or consider changing `format!` to `format_args!` error: `format!` in `println!` args - --> $DIR/format_args_unfixable.rs:27:5 + --> $DIR/format_args_unfixable.rs:28:5 | LL | println!("{:?}: {}", error, format!("something failed at {}", Location::caller())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -27,7 +27,7 @@ LL | println!("{:?}: {}", error, format!("something failed at {}", Location: = help: or consider changing `format!` to `format_args!` error: `format!` in `println!` args - --> $DIR/format_args_unfixable.rs:28:5 + --> $DIR/format_args_unfixable.rs:29:5 | LL | println!("{{}}: {}", format!("something failed at {}", Location::caller())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -36,7 +36,7 @@ LL | println!("{{}}: {}", format!("something failed at {}", Location::caller = help: or consider changing `format!` to `format_args!` error: `format!` in `println!` args - --> $DIR/format_args_unfixable.rs:29:5 + --> $DIR/format_args_unfixable.rs:30:5 | LL | println!(r#"error: "{}""#, format!("something failed at {}", Location::caller())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -45,7 +45,7 @@ LL | println!(r#"error: "{}""#, format!("something failed at {}", Location:: = help: or consider changing `format!` to `format_args!` error: `format!` in `println!` args - --> $DIR/format_args_unfixable.rs:30:5 + --> $DIR/format_args_unfixable.rs:31:5 | LL | println!("error: {}", format!(r#"something failed at "{}""#, Location::caller())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -54,7 +54,7 @@ LL | println!("error: {}", format!(r#"something failed at "{}""#, Location:: = help: or consider changing `format!` to `format_args!` error: `format!` in `println!` args - --> $DIR/format_args_unfixable.rs:31:5 + --> $DIR/format_args_unfixable.rs:32:5 | LL | println!("error: {}", format!("something failed at {} {0}", Location::caller())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -63,7 +63,7 @@ LL | println!("error: {}", format!("something failed at {} {0}", Location::c = help: or consider changing `format!` to `format_args!` error: `format!` in `format!` args - --> $DIR/format_args_unfixable.rs:32:13 + --> $DIR/format_args_unfixable.rs:33:13 | LL | let _ = format!("error: {}", format!("something failed at {}", Location::caller())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -72,7 +72,7 @@ LL | let _ = format!("error: {}", format!("something failed at {}", Location = help: or consider changing `format!` to `format_args!` error: `format!` in `write!` args - --> $DIR/format_args_unfixable.rs:33:13 + --> $DIR/format_args_unfixable.rs:34:13 | LL | let _ = write!( | _____________^ @@ -86,7 +86,7 @@ LL | | ); = help: or consider changing `format!` to `format_args!` error: `format!` in `writeln!` args - --> $DIR/format_args_unfixable.rs:38:13 + --> $DIR/format_args_unfixable.rs:39:13 | LL | let _ = writeln!( | _____________^ @@ -100,7 +100,7 @@ LL | | ); = help: or consider changing `format!` to `format_args!` error: `format!` in `print!` args - --> $DIR/format_args_unfixable.rs:43:5 + --> $DIR/format_args_unfixable.rs:44:5 | LL | print!("error: {}", format!("something failed at {}", Location::caller())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -109,7 +109,7 @@ LL | print!("error: {}", format!("something failed at {}", Location::caller( = help: or consider changing `format!` to `format_args!` error: `format!` in `eprint!` args - --> $DIR/format_args_unfixable.rs:44:5 + --> $DIR/format_args_unfixable.rs:45:5 | LL | eprint!("error: {}", format!("something failed at {}", Location::caller())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -118,7 +118,7 @@ LL | eprint!("error: {}", format!("something failed at {}", Location::caller = help: or consider changing `format!` to `format_args!` error: `format!` in `eprintln!` args - --> $DIR/format_args_unfixable.rs:45:5 + --> $DIR/format_args_unfixable.rs:46:5 | LL | eprintln!("error: {}", format!("something failed at {}", Location::caller())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -127,7 +127,7 @@ LL | eprintln!("error: {}", format!("something failed at {}", Location::call = help: or consider changing `format!` to `format_args!` error: `format!` in `format_args!` args - --> $DIR/format_args_unfixable.rs:46:13 + --> $DIR/format_args_unfixable.rs:47:13 | LL | let _ = format_args!("error: {}", format!("something failed at {}", Location::caller())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -136,7 +136,7 @@ LL | let _ = format_args!("error: {}", format!("something failed at {}", Loc = help: or consider changing `format!` to `format_args!` error: `format!` in `assert!` args - --> $DIR/format_args_unfixable.rs:47:5 + --> $DIR/format_args_unfixable.rs:48:5 | LL | assert!(true, "error: {}", format!("something failed at {}", Location::caller())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -145,7 +145,7 @@ LL | assert!(true, "error: {}", format!("something failed at {}", Location:: = help: or consider changing `format!` to `format_args!` error: `format!` in `assert_eq!` args - --> $DIR/format_args_unfixable.rs:48:5 + --> $DIR/format_args_unfixable.rs:49:5 | LL | assert_eq!(0, 0, "error: {}", format!("something failed at {}", Location::caller())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -154,7 +154,7 @@ LL | assert_eq!(0, 0, "error: {}", format!("something failed at {}", Locatio = help: or consider changing `format!` to `format_args!` error: `format!` in `assert_ne!` args - --> $DIR/format_args_unfixable.rs:49:5 + --> $DIR/format_args_unfixable.rs:50:5 | LL | assert_ne!(0, 0, "error: {}", format!("something failed at {}", Location::caller())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -163,7 +163,7 @@ LL | assert_ne!(0, 0, "error: {}", format!("something failed at {}", Locatio = help: or consider changing `format!` to `format_args!` error: `format!` in `panic!` args - --> $DIR/format_args_unfixable.rs:50:5 + --> $DIR/format_args_unfixable.rs:51:5 | LL | panic!("error: {}", format!("something failed at {}", Location::caller())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/item_after_statement.rs b/tests/ui/items_after_statement.rs similarity index 69% rename from tests/ui/item_after_statement.rs rename to tests/ui/items_after_statement.rs index 5e92dcab1f5a2..f12cb8f22e270 100644 --- a/tests/ui/item_after_statement.rs +++ b/tests/ui/items_after_statement.rs @@ -51,3 +51,20 @@ fn semicolon() { let _ = S::new(3); } + +fn item_from_macro() { + macro_rules! static_assert_size { + ($ty:ty, $size:expr) => { + const _: [(); $size] = [(); ::std::mem::size_of::<$ty>()]; + }; + } + + let _ = 1; + static_assert_size!(u32, 4); +} + +fn allow_attribute() { + let _ = 1; + #[allow(clippy::items_after_statements)] + const _: usize = 1; +} diff --git a/tests/ui/item_after_statement.stderr b/tests/ui/items_after_statement.stderr similarity index 87% rename from tests/ui/item_after_statement.stderr rename to tests/ui/items_after_statement.stderr index 2523c53ac53a1..f69635a977bd7 100644 --- a/tests/ui/item_after_statement.stderr +++ b/tests/ui/items_after_statement.stderr @@ -1,5 +1,5 @@ error: adding items after statements is confusing, since items exist from the start of the scope - --> $DIR/item_after_statement.rs:13:5 + --> $DIR/items_after_statement.rs:13:5 | LL | / fn foo() { LL | | println!("foo"); @@ -9,7 +9,7 @@ LL | | } = note: `-D clippy::items-after-statements` implied by `-D warnings` error: adding items after statements is confusing, since items exist from the start of the scope - --> $DIR/item_after_statement.rs:20:5 + --> $DIR/items_after_statement.rs:20:5 | LL | / fn foo() { LL | | println!("foo"); @@ -17,7 +17,7 @@ LL | | } | |_____^ error: adding items after statements is confusing, since items exist from the start of the scope - --> $DIR/item_after_statement.rs:33:13 + --> $DIR/items_after_statement.rs:33:13 | LL | / fn say_something() { LL | | println!("something"); diff --git a/tests/ui/large_futures.rs b/tests/ui/large_futures.rs new file mode 100644 index 0000000000000..4a8ba995da556 --- /dev/null +++ b/tests/ui/large_futures.rs @@ -0,0 +1,61 @@ +#![feature(generators)] +#![warn(clippy::large_futures)] +#![allow(clippy::future_not_send)] +#![allow(clippy::manual_async_fn)] + +async fn big_fut(_arg: [u8; 1024 * 16]) {} + +async fn wait() { + let f = async { + big_fut([0u8; 1024 * 16]).await; + }; + f.await +} +async fn calls_fut(fut: impl std::future::Future) { + loop { + wait().await; + if true { + return fut.await; + } else { + wait().await; + } + } +} + +pub async fn test() { + let fut = big_fut([0u8; 1024 * 16]); + foo().await; + calls_fut(fut).await; +} + +pub fn foo() -> impl std::future::Future { + async { + let x = [0i32; 1024 * 16]; + async {}.await; + dbg!(x); + } +} + +pub async fn lines() { + async { + let x = [0i32; 1024 * 16]; + async {}.await; + println!("{:?}", x); + } + .await; +} + +pub async fn macro_expn() { + macro_rules! macro_ { + () => { + async { + let x = [0i32; 1024 * 16]; + async {}.await; + println!("macro: {:?}", x); + } + }; + } + macro_!().await +} + +fn main() {} diff --git a/tests/ui/large_futures.stderr b/tests/ui/large_futures.stderr new file mode 100644 index 0000000000000..67e0fceff6ef3 --- /dev/null +++ b/tests/ui/large_futures.stderr @@ -0,0 +1,82 @@ +error: large future with a size of 16385 bytes + --> $DIR/large_futures.rs:10:9 + | +LL | big_fut([0u8; 1024 * 16]).await; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Box::pin` on it: `Box::pin(big_fut([0u8; 1024 * 16]))` + | + = note: `-D clippy::large-futures` implied by `-D warnings` + +error: large future with a size of 16386 bytes + --> $DIR/large_futures.rs:12:5 + | +LL | f.await + | ^ help: consider `Box::pin` on it: `Box::pin(f)` + +error: large future with a size of 16387 bytes + --> $DIR/large_futures.rs:16:9 + | +LL | wait().await; + | ^^^^^^ help: consider `Box::pin` on it: `Box::pin(wait())` + +error: large future with a size of 16387 bytes + --> $DIR/large_futures.rs:20:13 + | +LL | wait().await; + | ^^^^^^ help: consider `Box::pin` on it: `Box::pin(wait())` + +error: large future with a size of 65540 bytes + --> $DIR/large_futures.rs:27:5 + | +LL | foo().await; + | ^^^^^ help: consider `Box::pin` on it: `Box::pin(foo())` + +error: large future with a size of 49159 bytes + --> $DIR/large_futures.rs:28:5 + | +LL | calls_fut(fut).await; + | ^^^^^^^^^^^^^^ help: consider `Box::pin` on it: `Box::pin(calls_fut(fut))` + +error: large future with a size of 65540 bytes + --> $DIR/large_futures.rs:40:5 + | +LL | / async { +LL | | let x = [0i32; 1024 * 16]; +LL | | async {}.await; +LL | | println!("{:?}", x); +LL | | } + | |_____^ + | +help: consider `Box::pin` on it + | +LL ~ Box::pin(async { +LL + let x = [0i32; 1024 * 16]; +LL + async {}.await; +LL + println!("{:?}", x); +LL + }) + | + +error: large future with a size of 65540 bytes + --> $DIR/large_futures.rs:51:13 + | +LL | / async { +LL | | let x = [0i32; 1024 * 16]; +LL | | async {}.await; +LL | | println!("macro: {:?}", x); +LL | | } + | |_____________^ +... +LL | macro_!().await + | --------- in this macro invocation + | + = note: this error originates in the macro `macro_` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider `Box::pin` on it + | +LL ~ Box::pin(async { +LL + let x = [0i32; 1024 * 16]; +LL + async {}.await; +LL + println!("macro: {:?}", x); +LL + }) + | + +error: aborting due to 8 previous errors + diff --git a/tests/ui/lines_filter_map_ok.fixed b/tests/ui/lines_filter_map_ok.fixed new file mode 100644 index 0000000000000..f4033cd8ed850 --- /dev/null +++ b/tests/ui/lines_filter_map_ok.fixed @@ -0,0 +1,29 @@ +// run-rustfix + +#![allow(unused, clippy::map_identity)] +#![warn(clippy::lines_filter_map_ok)] + +use std::io::{self, BufRead, BufReader}; + +fn main() -> io::Result<()> { + let f = std::fs::File::open("/")?; + // Lint + BufReader::new(f).lines().map_while(Result::ok).for_each(|_| ()); + // Lint + let f = std::fs::File::open("/")?; + BufReader::new(f).lines().map_while(Result::ok).for_each(|_| ()); + let s = "foo\nbar\nbaz\n"; + // Lint + io::stdin().lines().map_while(Result::ok).for_each(|_| ()); + // Lint + io::stdin().lines().map_while(Result::ok).for_each(|_| ()); + // Do not lint (not a `Lines` iterator) + io::stdin() + .lines() + .map(std::convert::identity) + .filter_map(|x| x.ok()) + .for_each(|_| ()); + // Do not lint (not a `Result::ok()` extractor) + io::stdin().lines().filter_map(|x| x.err()).for_each(|_| ()); + Ok(()) +} diff --git a/tests/ui/lines_filter_map_ok.rs b/tests/ui/lines_filter_map_ok.rs new file mode 100644 index 0000000000000..7e11816b2acd3 --- /dev/null +++ b/tests/ui/lines_filter_map_ok.rs @@ -0,0 +1,29 @@ +// run-rustfix + +#![allow(unused, clippy::map_identity)] +#![warn(clippy::lines_filter_map_ok)] + +use std::io::{self, BufRead, BufReader}; + +fn main() -> io::Result<()> { + let f = std::fs::File::open("/")?; + // Lint + BufReader::new(f).lines().filter_map(Result::ok).for_each(|_| ()); + // Lint + let f = std::fs::File::open("/")?; + BufReader::new(f).lines().flat_map(Result::ok).for_each(|_| ()); + let s = "foo\nbar\nbaz\n"; + // Lint + io::stdin().lines().filter_map(Result::ok).for_each(|_| ()); + // Lint + io::stdin().lines().filter_map(|x| x.ok()).for_each(|_| ()); + // Do not lint (not a `Lines` iterator) + io::stdin() + .lines() + .map(std::convert::identity) + .filter_map(|x| x.ok()) + .for_each(|_| ()); + // Do not lint (not a `Result::ok()` extractor) + io::stdin().lines().filter_map(|x| x.err()).for_each(|_| ()); + Ok(()) +} diff --git a/tests/ui/lines_filter_map_ok.stderr b/tests/ui/lines_filter_map_ok.stderr new file mode 100644 index 0000000000000..cddd403d589c3 --- /dev/null +++ b/tests/ui/lines_filter_map_ok.stderr @@ -0,0 +1,51 @@ +error: `filter_map()` will run forever if the iterator repeatedly produces an `Err` + --> $DIR/lines_filter_map_ok.rs:11:31 + | +LL | BufReader::new(f).lines().filter_map(Result::ok).for_each(|_| ()); + | ^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `map_while(Result::ok)` + | +note: this expression returning a `std::io::Lines` may produce an infinite number of `Err` in case of a read error + --> $DIR/lines_filter_map_ok.rs:11:5 + | +LL | BufReader::new(f).lines().filter_map(Result::ok).for_each(|_| ()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: `-D clippy::lines-filter-map-ok` implied by `-D warnings` + +error: `flat_map()` will run forever if the iterator repeatedly produces an `Err` + --> $DIR/lines_filter_map_ok.rs:14:31 + | +LL | BufReader::new(f).lines().flat_map(Result::ok).for_each(|_| ()); + | ^^^^^^^^^^^^^^^^^^^^ help: replace with: `map_while(Result::ok)` + | +note: this expression returning a `std::io::Lines` may produce an infinite number of `Err` in case of a read error + --> $DIR/lines_filter_map_ok.rs:14:5 + | +LL | BufReader::new(f).lines().flat_map(Result::ok).for_each(|_| ()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `filter_map()` will run forever if the iterator repeatedly produces an `Err` + --> $DIR/lines_filter_map_ok.rs:17:25 + | +LL | io::stdin().lines().filter_map(Result::ok).for_each(|_| ()); + | ^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `map_while(Result::ok)` + | +note: this expression returning a `std::io::Lines` may produce an infinite number of `Err` in case of a read error + --> $DIR/lines_filter_map_ok.rs:17:5 + | +LL | io::stdin().lines().filter_map(Result::ok).for_each(|_| ()); + | ^^^^^^^^^^^^^^^^^^^ + +error: `filter_map()` will run forever if the iterator repeatedly produces an `Err` + --> $DIR/lines_filter_map_ok.rs:19:25 + | +LL | io::stdin().lines().filter_map(|x| x.ok()).for_each(|_| ()); + | ^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `map_while(Result::ok)` + | +note: this expression returning a `std::io::Lines` may produce an infinite number of `Err` in case of a read error + --> $DIR/lines_filter_map_ok.rs:19:5 + | +LL | io::stdin().lines().filter_map(|x| x.ok()).for_each(|_| ()); + | ^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 4 previous errors + diff --git a/tests/ui/manual_slice_size_calculation.rs b/tests/ui/manual_slice_size_calculation.rs new file mode 100644 index 0000000000000..5082f931f3c2b --- /dev/null +++ b/tests/ui/manual_slice_size_calculation.rs @@ -0,0 +1,36 @@ +#![allow(unused)] +#![warn(clippy::manual_slice_size_calculation)] + +use core::mem::{align_of, size_of}; + +fn main() { + let v_i32 = Vec::::new(); + let s_i32 = v_i32.as_slice(); + + // True positives: + let _ = s_i32.len() * size_of::(); // WARNING + let _ = size_of::() * s_i32.len(); // WARNING + let _ = size_of::() * s_i32.len() * 5; // WARNING + + let len = s_i32.len(); + let size = size_of::(); + let _ = len * size_of::(); // WARNING + let _ = s_i32.len() * size; // WARNING + let _ = len * size; // WARNING + + // True negatives: + let _ = size_of::() + s_i32.len(); // Ok, not a multiplication + let _ = size_of::() * s_i32.partition_point(|_| true); // Ok, not len() + let _ = size_of::() * v_i32.len(); // Ok, not a slice + let _ = align_of::() * s_i32.len(); // Ok, not size_of() + let _ = size_of::() * s_i32.len(); // Ok, different types + + // False negatives: + let _ = 5 * size_of::() * s_i32.len(); // Ok (MISSED OPPORTUNITY) + let _ = size_of::() * 5 * s_i32.len(); // Ok (MISSED OPPORTUNITY) +} + +const fn _const(s_i32: &[i32]) { + // True negative: + let _ = s_i32.len() * size_of::(); // Ok, can't use size_of_val in const +} diff --git a/tests/ui/manual_slice_size_calculation.stderr b/tests/ui/manual_slice_size_calculation.stderr new file mode 100644 index 0000000000000..4a24fc60a0faf --- /dev/null +++ b/tests/ui/manual_slice_size_calculation.stderr @@ -0,0 +1,51 @@ +error: manual slice size calculation + --> $DIR/manual_slice_size_calculation.rs:11:13 + | +LL | let _ = s_i32.len() * size_of::(); // WARNING + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using std::mem::size_of_value instead + = note: `-D clippy::manual-slice-size-calculation` implied by `-D warnings` + +error: manual slice size calculation + --> $DIR/manual_slice_size_calculation.rs:12:13 + | +LL | let _ = size_of::() * s_i32.len(); // WARNING + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using std::mem::size_of_value instead + +error: manual slice size calculation + --> $DIR/manual_slice_size_calculation.rs:13:13 + | +LL | let _ = size_of::() * s_i32.len() * 5; // WARNING + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using std::mem::size_of_value instead + +error: manual slice size calculation + --> $DIR/manual_slice_size_calculation.rs:17:13 + | +LL | let _ = len * size_of::(); // WARNING + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using std::mem::size_of_value instead + +error: manual slice size calculation + --> $DIR/manual_slice_size_calculation.rs:18:13 + | +LL | let _ = s_i32.len() * size; // WARNING + | ^^^^^^^^^^^^^^^^^^ + | + = help: consider using std::mem::size_of_value instead + +error: manual slice size calculation + --> $DIR/manual_slice_size_calculation.rs:19:13 + | +LL | let _ = len * size; // WARNING + | ^^^^^^^^^^ + | + = help: consider using std::mem::size_of_value instead + +error: aborting due to 6 previous errors + diff --git a/tests/ui/mem_replace.fixed b/tests/ui/mem_replace.fixed index 874d558433034..7fd340173af9e 100644 --- a/tests/ui/mem_replace.fixed +++ b/tests/ui/mem_replace.fixed @@ -90,3 +90,37 @@ fn msrv_1_40() { let mut s = String::from("foo"); let _ = std::mem::take(&mut s); } + +fn issue9824() { + struct Foo<'a>(Option<&'a str>); + impl<'a> std::ops::Deref for Foo<'a> { + type Target = Option<&'a str>; + + fn deref(&self) -> &Self::Target { + &self.0 + } + } + impl<'a> std::ops::DerefMut for Foo<'a> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } + } + + struct Bar { + opt: Option, + val: String, + } + + let mut f = Foo(Some("foo")); + let mut b = Bar { + opt: Some(1), + val: String::from("bar"), + }; + + // replace option with none + let _ = f.0.take(); + let _ = (*f).take(); + let _ = b.opt.take(); + // replace with default + let _ = std::mem::take(&mut b.val); +} diff --git a/tests/ui/mem_replace.rs b/tests/ui/mem_replace.rs index f4f3bff514463..fa2903addbc03 100644 --- a/tests/ui/mem_replace.rs +++ b/tests/ui/mem_replace.rs @@ -90,3 +90,37 @@ fn msrv_1_40() { let mut s = String::from("foo"); let _ = std::mem::replace(&mut s, String::default()); } + +fn issue9824() { + struct Foo<'a>(Option<&'a str>); + impl<'a> std::ops::Deref for Foo<'a> { + type Target = Option<&'a str>; + + fn deref(&self) -> &Self::Target { + &self.0 + } + } + impl<'a> std::ops::DerefMut for Foo<'a> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } + } + + struct Bar { + opt: Option, + val: String, + } + + let mut f = Foo(Some("foo")); + let mut b = Bar { + opt: Some(1), + val: String::from("bar"), + }; + + // replace option with none + let _ = std::mem::replace(&mut f.0, None); + let _ = std::mem::replace(&mut *f, None); + let _ = std::mem::replace(&mut b.opt, None); + // replace with default + let _ = std::mem::replace(&mut b.val, String::default()); +} diff --git a/tests/ui/mem_replace.stderr b/tests/ui/mem_replace.stderr index caa127f76eeff..58b57be750702 100644 --- a/tests/ui/mem_replace.stderr +++ b/tests/ui/mem_replace.stderr @@ -122,5 +122,29 @@ error: replacing a value of type `T` with `T::default()` is better expressed usi LL | let _ = std::mem::replace(&mut s, String::default()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut s)` -error: aborting due to 20 previous errors +error: replacing an `Option` with `None` + --> $DIR/mem_replace.rs:121:13 + | +LL | let _ = std::mem::replace(&mut f.0, None); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `f.0.take()` + +error: replacing an `Option` with `None` + --> $DIR/mem_replace.rs:122:13 + | +LL | let _ = std::mem::replace(&mut *f, None); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `(*f).take()` + +error: replacing an `Option` with `None` + --> $DIR/mem_replace.rs:123:13 + | +LL | let _ = std::mem::replace(&mut b.opt, None); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `b.opt.take()` + +error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` + --> $DIR/mem_replace.rs:125:13 + | +LL | let _ = std::mem::replace(&mut b.val, String::default()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut b.val)` + +error: aborting due to 24 previous errors diff --git a/tests/ui/needless_return.fixed b/tests/ui/needless_return.fixed index 0f525dd294c9b..57c08996ce25d 100644 --- a/tests/ui/needless_return.fixed +++ b/tests/ui/needless_return.fixed @@ -307,4 +307,13 @@ mod issue10049 { } } +fn test_match_as_stmt() { + let x = 9; + match x { + 1 => 2, + 2 => return, + _ => 0, + }; +} + fn main() {} diff --git a/tests/ui/needless_return.rs b/tests/ui/needless_return.rs index a1db8375d95b9..7c1feefbe32bb 100644 --- a/tests/ui/needless_return.rs +++ b/tests/ui/needless_return.rs @@ -317,4 +317,13 @@ mod issue10049 { } } +fn test_match_as_stmt() { + let x = 9; + match x { + 1 => 2, + 2 => return, + _ => 0, + }; +} + fn main() {} diff --git a/tests/ui/nonminimal_bool.rs b/tests/ui/nonminimal_bool.rs index 3b5a374b4a7b4..80cc7c60f56e5 100644 --- a/tests/ui/nonminimal_bool.rs +++ b/tests/ui/nonminimal_bool.rs @@ -92,3 +92,21 @@ fn issue_10523_2() { } if a!() {} } + +fn issue_10435() { + let x = vec![0]; + let y = vec![1]; + let z = vec![2]; + + // vvv Should not lint + #[allow(clippy::nonminimal_bool)] + if !x.is_empty() && !(y.is_empty() || z.is_empty()) { + println!("{}", line!()); + } + + // vvv Should not lint (#10435 talks about a bug where it lints) + #[allow(clippy::nonminimal_bool)] + if !(x == [0]) { + println!("{}", line!()); + } +} diff --git a/tests/ui/print_literal.rs b/tests/ui/print_literal.rs index 86f908f66b8f3..538513e9156f8 100644 --- a/tests/ui/print_literal.rs +++ b/tests/ui/print_literal.rs @@ -38,4 +38,8 @@ fn main() { // named args shouldn't change anything either println!("{foo} {bar}", foo = "hello", bar = "world"); println!("{bar} {foo}", foo = "hello", bar = "world"); + + // The string literal from `file!()` has a callsite span that isn't marked as coming from an + // expansion + println!("file: {}", file!()); } diff --git a/tests/ui/redundant_async_block.fixed b/tests/ui/redundant_async_block.fixed index d26b7a332cbbf..ad96993c4a78c 100644 --- a/tests/ui/redundant_async_block.fixed +++ b/tests/ui/redundant_async_block.fixed @@ -1,6 +1,6 @@ // run-rustfix -#![allow(unused)] +#![allow(unused, clippy::manual_async_fn)] #![warn(clippy::redundant_async_block)] use std::future::Future; @@ -16,40 +16,16 @@ async fn func2() -> String { x.await } -macro_rules! await_in_macro { - ($e:expr) => { - std::convert::identity($e).await - }; -} - -async fn func3(n: usize) -> usize { - // Do not lint (suggestion would be `std::convert::identity(func1(n))` - // which copies code from inside the macro) - async move { await_in_macro!(func1(n)) }.await -} - -// This macro should never be linted as `$e` might contain `.await` -macro_rules! async_await_parameter_in_macro { - ($e:expr) => { - async { $e.await } - }; -} - -// MISSED OPPORTUNITY: this macro could be linted as the `async` block does not -// contain code coming from the parameters -macro_rules! async_await_in_macro { - ($f:expr) => { - ($f)(async { func2().await }) - }; -} - fn main() { let fut1 = async { 17 }; + // Lint let fut2 = fut1; let fut1 = async { 25 }; + // Lint let fut2 = fut1; + // Lint let fut = async { 42 }; // Do not lint: not a single expression @@ -60,15 +36,12 @@ fn main() { // Do not lint: expression contains `.await` let fut = async { func1(func2().await.len()).await }; - - 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 }; + // Lint fut } @@ -80,11 +53,39 @@ fn capture_local_closure(s: &str) -> impl Future { #[allow(clippy::let_and_return)] fn capture_arg(s: &str) -> impl Future { - // Lint let fut = async move { s }; + // Lint fut } +fn capture_future_arg(f: impl Future) -> impl Future { + // Lint + f +} + +fn capture_func_result(f: FN) -> impl Future +where + F: Future, + FN: FnOnce() -> F, +{ + // Do not lint, as f() would be evaluated prematurely + async { f().await } +} + +fn double_future(f: impl Future>) -> impl Future { + // Do not lint, we will get a `.await` outside a `.async` + async { f.await.await } +} + +fn await_in_async(f: F) -> impl Future +where + F: FnOnce() -> R, + R: Future, +{ + // Lint + async { f().await + 1 } +} + #[derive(Debug, Clone)] struct F {} @@ -109,3 +110,84 @@ fn capture() { // Do not lint: `val` would not live long enough spawn(async { work(&{ val }).await }); } + +fn await_from_macro() -> impl Future { + macro_rules! mac { + ($e:expr) => { + $e.await + }; + } + // Do not lint: the macro may change in the future + // or return different things depending on its argument + async { mac!(async { 42 }) } +} + +fn async_expr_from_macro() -> impl Future { + macro_rules! mac { + () => { + async { 42 } + }; + } + // Do not lint: the macro may change in the future + async { mac!().await } +} + +fn async_expr_from_macro_deep() -> impl Future { + macro_rules! mac { + () => { + async { 42 } + }; + } + // Do not lint: the macro may change in the future + async { ({ mac!() }).await } +} + +fn all_from_macro() -> impl Future { + macro_rules! mac { + () => { + // Lint + async { 42 } + }; + } + mac!() +} + +fn parts_from_macro() -> impl Future { + macro_rules! mac { + ($e: expr) => { + // Do not lint: `$e` might not always be side-effect free + async { $e.await } + }; + } + mac!(async { 42 }) +} + +fn safe_parts_from_macro() -> impl Future { + macro_rules! mac { + ($e: expr) => { + // Lint + async { $e } + }; + } + mac!(42) +} + +fn parts_from_macro_deep() -> impl Future { + macro_rules! mac { + ($e: expr) => { + // Do not lint: `$e` might not always be side-effect free + async { ($e,).0.await } + }; + } + let f = std::future::ready(42); + mac!(f) +} + +fn await_from_macro_deep() -> impl Future { + macro_rules! mac { + ($e:expr) => {{ $e }.await}; + } + // Do not lint: the macro may change in the future + // or return different things depending on its argument + async { mac!(async { 42 }) } +} diff --git a/tests/ui/redundant_async_block.rs b/tests/ui/redundant_async_block.rs index 04726e6280508..7ae235583694d 100644 --- a/tests/ui/redundant_async_block.rs +++ b/tests/ui/redundant_async_block.rs @@ -1,6 +1,6 @@ // run-rustfix -#![allow(unused)] +#![allow(unused, clippy::manual_async_fn)] #![warn(clippy::redundant_async_block)] use std::future::Future; @@ -16,40 +16,16 @@ async fn func2() -> String { x.await } -macro_rules! await_in_macro { - ($e:expr) => { - std::convert::identity($e).await - }; -} - -async fn func3(n: usize) -> usize { - // Do not lint (suggestion would be `std::convert::identity(func1(n))` - // which copies code from inside the macro) - async move { await_in_macro!(func1(n)) }.await -} - -// This macro should never be linted as `$e` might contain `.await` -macro_rules! async_await_parameter_in_macro { - ($e:expr) => { - async { $e.await } - }; -} - -// MISSED OPPORTUNITY: this macro could be linted as the `async` block does not -// contain code coming from the parameters -macro_rules! async_await_in_macro { - ($f:expr) => { - ($f)(async { func2().await }) - }; -} - fn main() { let fut1 = async { 17 }; + // Lint let fut2 = async { fut1.await }; let fut1 = async { 25 }; + // Lint let fut2 = async move { fut1.await }; + // Lint let fut = async { async { 42 }.await }; // Do not lint: not a single expression @@ -60,15 +36,12 @@ fn main() { // Do not lint: expression contains `.await` let fut = async { func1(func2().await.len()).await }; - - 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 }; + // Lint async move { fut.await } } @@ -80,11 +53,39 @@ fn capture_local_closure(s: &str) -> impl Future { #[allow(clippy::let_and_return)] fn capture_arg(s: &str) -> impl Future { - // Lint let fut = async move { s }; + // Lint async move { fut.await } } +fn capture_future_arg(f: impl Future) -> impl Future { + // Lint + async { f.await } +} + +fn capture_func_result(f: FN) -> impl Future +where + F: Future, + FN: FnOnce() -> F, +{ + // Do not lint, as f() would be evaluated prematurely + async { f().await } +} + +fn double_future(f: impl Future>) -> impl Future { + // Do not lint, we will get a `.await` outside a `.async` + async { f.await.await } +} + +fn await_in_async(f: F) -> impl Future +where + F: FnOnce() -> R, + R: Future, +{ + // Lint + async { async { f().await + 1 }.await } +} + #[derive(Debug, Clone)] struct F {} @@ -109,3 +110,84 @@ fn capture() { // Do not lint: `val` would not live long enough spawn(async { work(&{ val }).await }); } + +fn await_from_macro() -> impl Future { + macro_rules! mac { + ($e:expr) => { + $e.await + }; + } + // Do not lint: the macro may change in the future + // or return different things depending on its argument + async { mac!(async { 42 }) } +} + +fn async_expr_from_macro() -> impl Future { + macro_rules! mac { + () => { + async { 42 } + }; + } + // Do not lint: the macro may change in the future + async { mac!().await } +} + +fn async_expr_from_macro_deep() -> impl Future { + macro_rules! mac { + () => { + async { 42 } + }; + } + // Do not lint: the macro may change in the future + async { ({ mac!() }).await } +} + +fn all_from_macro() -> impl Future { + macro_rules! mac { + () => { + // Lint + async { async { 42 }.await } + }; + } + mac!() +} + +fn parts_from_macro() -> impl Future { + macro_rules! mac { + ($e: expr) => { + // Do not lint: `$e` might not always be side-effect free + async { $e.await } + }; + } + mac!(async { 42 }) +} + +fn safe_parts_from_macro() -> impl Future { + macro_rules! mac { + ($e: expr) => { + // Lint + async { async { $e }.await } + }; + } + mac!(42) +} + +fn parts_from_macro_deep() -> impl Future { + macro_rules! mac { + ($e: expr) => { + // Do not lint: `$e` might not always be side-effect free + async { ($e,).0.await } + }; + } + let f = std::future::ready(42); + mac!(f) +} + +fn await_from_macro_deep() -> impl Future { + macro_rules! mac { + ($e:expr) => {{ $e }.await}; + } + // Do not lint: the macro may change in the future + // or return different things depending on its argument + async { mac!(async { 42 }) } +} diff --git a/tests/ui/redundant_async_block.stderr b/tests/ui/redundant_async_block.stderr index 1a1c1603e0809..f3dcb09b4440a 100644 --- a/tests/ui/redundant_async_block.stderr +++ b/tests/ui/redundant_async_block.stderr @@ -7,34 +7,68 @@ 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:48:16 + --> $DIR/redundant_async_block.rs:22: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:51:16 + --> $DIR/redundant_async_block.rs:26: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:53:15 + --> $DIR/redundant_async_block.rs:29:15 | LL | let fut = async { async { 42 }.await }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `async { 42 }` error: this async expression only awaits a single future - --> $DIR/redundant_async_block.rs:72:5 + --> $DIR/redundant_async_block.rs:45: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 + --> $DIR/redundant_async_block.rs:58:5 | LL | async move { fut.await } | ^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `fut` -error: aborting due to 6 previous errors +error: this async expression only awaits a single future + --> $DIR/redundant_async_block.rs:63:5 + | +LL | async { f.await } + | ^^^^^^^^^^^^^^^^^ help: you can reduce it to: `f` + +error: this async expression only awaits a single future + --> $DIR/redundant_async_block.rs:86:5 + | +LL | async { async { f().await + 1 }.await } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `async { f().await + 1 }` + +error: this async expression only awaits a single future + --> $DIR/redundant_async_block.rs:149:13 + | +LL | async { async { 42 }.await } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `async { 42 }` +... +LL | mac!() + | ------ in this macro invocation + | + = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: this async expression only awaits a single future + --> $DIR/redundant_async_block.rs:169:13 + | +LL | async { async { $e }.await } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `async { $e }` +... +LL | mac!(42) + | -------- in this macro invocation + | + = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 10 previous errors diff --git a/tests/ui/single_component_path_imports.fixed b/tests/ui/single_component_path_imports.fixed index 4c40739d6f553..8c96c4715d308 100644 --- a/tests/ui/single_component_path_imports.fixed +++ b/tests/ui/single_component_path_imports.fixed @@ -2,9 +2,11 @@ #![warn(clippy::single_component_path_imports)] #![allow(unused_imports)] +use core; use serde as edres; pub use serde; +use std; macro_rules! m { () => { @@ -17,6 +19,10 @@ fn main() { // False positive #5154, shouldn't trigger lint. m!(); + + // False positive #10549 + let _ = self::std::io::stdout(); + let _ = 0 as self::core::ffi::c_uint; } mod hello_mod { diff --git a/tests/ui/single_component_path_imports.rs b/tests/ui/single_component_path_imports.rs index 9280bab3c71b5..8434bf7eaf1f5 100644 --- a/tests/ui/single_component_path_imports.rs +++ b/tests/ui/single_component_path_imports.rs @@ -2,9 +2,11 @@ #![warn(clippy::single_component_path_imports)] #![allow(unused_imports)] +use core; use regex; use serde as edres; pub use serde; +use std; macro_rules! m { () => { @@ -17,6 +19,10 @@ fn main() { // False positive #5154, shouldn't trigger lint. m!(); + + // False positive #10549 + let _ = self::std::io::stdout(); + let _ = 0 as self::core::ffi::c_uint; } mod hello_mod { diff --git a/tests/ui/single_component_path_imports.stderr b/tests/ui/single_component_path_imports.stderr index 71dcc25d6e5b8..d69a86470a5e5 100644 --- a/tests/ui/single_component_path_imports.stderr +++ b/tests/ui/single_component_path_imports.stderr @@ -1,5 +1,5 @@ error: this import is redundant - --> $DIR/single_component_path_imports.rs:5:1 + --> $DIR/single_component_path_imports.rs:6:1 | LL | use regex; | ^^^^^^^^^^ help: remove it entirely @@ -7,7 +7,7 @@ LL | use regex; = note: `-D clippy::single-component-path-imports` implied by `-D warnings` error: this import is redundant - --> $DIR/single_component_path_imports.rs:23:5 + --> $DIR/single_component_path_imports.rs:29:5 | LL | use regex; | ^^^^^^^^^^ help: remove it entirely diff --git a/tests/ui/suspicious_doc_comments.fixed b/tests/ui/suspicious_doc_comments.fixed new file mode 100644 index 0000000000000..b404df94d3c29 --- /dev/null +++ b/tests/ui/suspicious_doc_comments.fixed @@ -0,0 +1,81 @@ +// run-rustfix +#![allow(unused)] +#![warn(clippy::suspicious_doc_comments)] + +//! Real module documentation. +//! Fake module documentation. +fn baz() {} + +pub mod singleline_outer_doc { + //! This module contains useful functions. + + pub fn bar() {} +} + +pub mod singleline_inner_doc { + //! This module contains useful functions. + + pub fn bar() {} +} + +pub mod multiline_outer_doc { + /*! This module contains useful functions. + */ + + pub fn bar() {} +} + +pub mod multiline_inner_doc { + /*! This module contains useful functions. + */ + + pub fn bar() {} +} + +pub mod multiline_outer_doc2 { + //! This module + //! contains + //! useful functions. + + pub fn bar() {} +} + +pub mod multiline_outer_doc3 { + //! a + //! b + + /// c + pub fn bar() {} +} + +pub mod multiline_outer_doc4 { + //! a + /// b + pub fn bar() {} +} + +pub mod multiline_outer_doc_gap { + //! a + + //! b + pub fn bar() {} +} + +pub mod multiline_outer_doc_commented { + /////! This outer doc comment was commented out. + pub fn bar() {} +} + +pub mod outer_doc_macro { + //! Very cool macro + macro_rules! x { + () => {}; + } +} + +pub mod useless_outer_doc { + //! Huh. + use std::mem; +} + +fn main() {} diff --git a/tests/ui/suspicious_doc_comments.rs b/tests/ui/suspicious_doc_comments.rs new file mode 100644 index 0000000000000..46eff51e220f5 --- /dev/null +++ b/tests/ui/suspicious_doc_comments.rs @@ -0,0 +1,81 @@ +// run-rustfix +#![allow(unused)] +#![warn(clippy::suspicious_doc_comments)] + +//! Real module documentation. +///! Fake module documentation. +fn baz() {} + +pub mod singleline_outer_doc { + ///! This module contains useful functions. + + pub fn bar() {} +} + +pub mod singleline_inner_doc { + //! This module contains useful functions. + + pub fn bar() {} +} + +pub mod multiline_outer_doc { + /**! This module contains useful functions. + */ + + pub fn bar() {} +} + +pub mod multiline_inner_doc { + /*! This module contains useful functions. + */ + + pub fn bar() {} +} + +pub mod multiline_outer_doc2 { + ///! This module + ///! contains + ///! useful functions. + + pub fn bar() {} +} + +pub mod multiline_outer_doc3 { + ///! a + ///! b + + /// c + pub fn bar() {} +} + +pub mod multiline_outer_doc4 { + ///! a + /// b + pub fn bar() {} +} + +pub mod multiline_outer_doc_gap { + ///! a + + ///! b + pub fn bar() {} +} + +pub mod multiline_outer_doc_commented { + /////! This outer doc comment was commented out. + pub fn bar() {} +} + +pub mod outer_doc_macro { + ///! Very cool macro + macro_rules! x { + () => {}; + } +} + +pub mod useless_outer_doc { + ///! Huh. + use std::mem; +} + +fn main() {} diff --git a/tests/ui/suspicious_doc_comments.stderr b/tests/ui/suspicious_doc_comments.stderr new file mode 100644 index 0000000000000..6c167df27873c --- /dev/null +++ b/tests/ui/suspicious_doc_comments.stderr @@ -0,0 +1,114 @@ +error: this is an outer doc comment and does not apply to the parent module or crate + --> $DIR/suspicious_doc_comments.rs:6:1 + | +LL | ///! Fake module documentation. + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::suspicious-doc-comments` implied by `-D warnings` +help: use an inner doc comment to document the parent module or crate + | +LL | //! Fake module documentation. + | + +error: this is an outer doc comment and does not apply to the parent module or crate + --> $DIR/suspicious_doc_comments.rs:10:5 + | +LL | ///! This module contains useful functions. + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use an inner doc comment to document the parent module or crate + | +LL | //! This module contains useful functions. + | + +error: this is an outer doc comment and does not apply to the parent module or crate + --> $DIR/suspicious_doc_comments.rs:22:5 + | +LL | / /**! This module contains useful functions. +LL | | */ + | |_______^ + | +help: use an inner doc comment to document the parent module or crate + | +LL ~ /*! This module contains useful functions. +LL + */ + | + +error: this is an outer doc comment and does not apply to the parent module or crate + --> $DIR/suspicious_doc_comments.rs:36:5 + | +LL | / ///! This module +LL | | ///! contains +LL | | ///! useful functions. + | |__________________________^ + | +help: use an inner doc comment to document the parent module or crate + | +LL ~ //! This module +LL ~ //! contains +LL ~ //! useful functions. + | + +error: this is an outer doc comment and does not apply to the parent module or crate + --> $DIR/suspicious_doc_comments.rs:44:5 + | +LL | / ///! a +LL | | ///! b + | |__________^ + | +help: use an inner doc comment to document the parent module or crate + | +LL ~ //! a +LL ~ //! b + | + +error: this is an outer doc comment and does not apply to the parent module or crate + --> $DIR/suspicious_doc_comments.rs:52:5 + | +LL | ///! a + | ^^^^^^ + | +help: use an inner doc comment to document the parent module or crate + | +LL | //! a + | + +error: this is an outer doc comment and does not apply to the parent module or crate + --> $DIR/suspicious_doc_comments.rs:58:5 + | +LL | / ///! a +LL | | +LL | | ///! b + | |__________^ + | +help: use an inner doc comment to document the parent module or crate + | +LL ~ //! a +LL | +LL ~ //! b + | + +error: this is an outer doc comment and does not apply to the parent module or crate + --> $DIR/suspicious_doc_comments.rs:70:5 + | +LL | ///! Very cool macro + | ^^^^^^^^^^^^^^^^^^^^ + | +help: use an inner doc comment to document the parent module or crate + | +LL | //! Very cool macro + | + +error: this is an outer doc comment and does not apply to the parent module or crate + --> $DIR/suspicious_doc_comments.rs:77:5 + | +LL | ///! Huh. + | ^^^^^^^^^ + | +help: use an inner doc comment to document the parent module or crate + | +LL | //! Huh. + | + +error: aborting due to 9 previous errors + diff --git a/tests/ui/suspicious_doc_comments_unfixable.rs b/tests/ui/suspicious_doc_comments_unfixable.rs new file mode 100644 index 0000000000000..ad98c7f4966ff --- /dev/null +++ b/tests/ui/suspicious_doc_comments_unfixable.rs @@ -0,0 +1,16 @@ +#![allow(unused)] +#![warn(clippy::suspicious_doc_comments)] + +///! a +///! b +/// c +///! d +pub fn foo() {} + +///! a +///! b +/// c +///! d +use std::mem; + +fn main() {} diff --git a/tests/ui/suspicious_doc_comments_unfixable.stderr b/tests/ui/suspicious_doc_comments_unfixable.stderr new file mode 100644 index 0000000000000..f89146dad36e0 --- /dev/null +++ b/tests/ui/suspicious_doc_comments_unfixable.stderr @@ -0,0 +1,37 @@ +error: this is an outer doc comment and does not apply to the parent module or crate + --> $DIR/suspicious_doc_comments_unfixable.rs:4:1 + | +LL | / ///! a +LL | | ///! b +LL | | /// c +LL | | ///! d + | |______^ + | + = note: `-D clippy::suspicious-doc-comments` implied by `-D warnings` +help: use an inner doc comment to document the parent module or crate + | +LL + //! a +LL + //! b +LL | /// c +LL + //! d + | + +error: this is an outer doc comment and does not apply to the parent module or crate + --> $DIR/suspicious_doc_comments_unfixable.rs:10:1 + | +LL | / ///! a +LL | | ///! b +LL | | /// c +LL | | ///! d + | |______^ + | +help: use an inner doc comment to document the parent module or crate + | +LL + //! a +LL + //! b +LL | /// c +LL + //! d + | + +error: aborting due to 2 previous errors + diff --git a/tests/ui/tests_outside_test_module.rs b/tests/ui/tests_outside_test_module.rs new file mode 100644 index 0000000000000..1982b1d0107f8 --- /dev/null +++ b/tests/ui/tests_outside_test_module.rs @@ -0,0 +1,18 @@ +// compile-flags: --test +#![allow(unused)] +#![warn(clippy::tests_outside_test_module)] + +fn main() { + // test code goes here +} + +// Should lint +#[test] +fn my_test() {} + +#[cfg(test)] +mod tests { + // Should not lint + #[test] + fn my_test() {} +} diff --git a/tests/ui/tests_outside_test_module.stderr b/tests/ui/tests_outside_test_module.stderr new file mode 100644 index 0000000000000..125a79d6edfed --- /dev/null +++ b/tests/ui/tests_outside_test_module.stderr @@ -0,0 +1,11 @@ +error: this function marked with #[test] is outside a #[cfg(test)] module + --> $DIR/tests_outside_test_module.rs:11:1 + | +LL | fn my_test() {} + | ^^^^^^^^^^^^^^^ + | + = note: move it to a testing module marked with #[cfg(test)] + = note: `-D clippy::tests-outside-test-module` implied by `-D warnings` + +error: aborting due to previous error + diff --git a/tests/ui/transmutes_expressible_as_ptr_casts.fixed b/tests/ui/transmutes_expressible_as_ptr_casts.fixed index 55307506eb3c7..cc84ba25bd0d7 100644 --- a/tests/ui/transmutes_expressible_as_ptr_casts.fixed +++ b/tests/ui/transmutes_expressible_as_ptr_casts.fixed @@ -4,7 +4,7 @@ // would otherwise be responsible for #![warn(clippy::useless_transmute)] #![warn(clippy::transmute_ptr_to_ptr)] -#![allow(dead_code, unused_unsafe, clippy::borrow_as_ptr)] +#![allow(unused, clippy::borrow_as_ptr)] use std::mem::{size_of, transmute}; @@ -77,3 +77,9 @@ fn cannot_be_expressed_as_pointer_cast(in_param: Single) -> Pair { unsafe { transmute::(in_param) } } + +fn issue_10449() { + fn f() {} + + let _x: u8 = unsafe { *(f as *const u8) }; +} diff --git a/tests/ui/transmutes_expressible_as_ptr_casts.rs b/tests/ui/transmutes_expressible_as_ptr_casts.rs index e7360f3f9dcba..aa65ab4dd2475 100644 --- a/tests/ui/transmutes_expressible_as_ptr_casts.rs +++ b/tests/ui/transmutes_expressible_as_ptr_casts.rs @@ -4,7 +4,7 @@ // would otherwise be responsible for #![warn(clippy::useless_transmute)] #![warn(clippy::transmute_ptr_to_ptr)] -#![allow(dead_code, unused_unsafe, clippy::borrow_as_ptr)] +#![allow(unused, clippy::borrow_as_ptr)] use std::mem::{size_of, transmute}; @@ -77,3 +77,9 @@ fn cannot_be_expressed_as_pointer_cast(in_param: Single) -> Pair { unsafe { transmute::(in_param) } } + +fn issue_10449() { + fn f() {} + + let _x: u8 = unsafe { *std::mem::transmute::(f) }; +} diff --git a/tests/ui/transmutes_expressible_as_ptr_casts.stderr b/tests/ui/transmutes_expressible_as_ptr_casts.stderr index e862fcb67a4a0..58f5162c78e78 100644 --- a/tests/ui/transmutes_expressible_as_ptr_casts.stderr +++ b/tests/ui/transmutes_expressible_as_ptr_casts.stderr @@ -58,5 +58,11 @@ error: transmute from a reference to a pointer LL | unsafe { transmute::<&[i32; 1], *const u8>(in_param) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `in_param as *const [i32; 1] as *const u8` -error: aborting due to 9 previous errors +error: transmute from `fn()` to `*const u8` which could be expressed as a pointer cast instead + --> $DIR/transmutes_expressible_as_ptr_casts.rs:84:28 + | +LL | let _x: u8 = unsafe { *std::mem::transmute::(f) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(f as *const u8)` + +error: aborting due to 10 previous errors diff --git a/tests/ui/uninit.rs b/tests/ui/uninit.rs index 412b36b4ee8f1..c996de89422b5 100644 --- a/tests/ui/uninit.rs +++ b/tests/ui/uninit.rs @@ -1,7 +1,7 @@ #![feature(stmt_expr_attributes)] #![allow(clippy::let_unit_value, invalid_value)] -use std::mem::{self, MaybeUninit}; +use std::mem::MaybeUninit; union MyOwnMaybeUninit { value: u8, @@ -30,12 +30,24 @@ fn main() { let _: [u8; 0] = unsafe { MaybeUninit::uninit().assume_init() }; // Was a false negative. - let _: usize = unsafe { mem::MaybeUninit::uninit().assume_init() }; + let _: usize = unsafe { MaybeUninit::uninit().assume_init() }; polymorphic::<()>(); + polymorphic_maybe_uninit_array::<10>(); + polymorphic_maybe_uninit::(); fn polymorphic() { // We are conservative around polymorphic types. - let _: T = unsafe { mem::MaybeUninit::uninit().assume_init() }; + let _: T = unsafe { MaybeUninit::uninit().assume_init() }; + } + + fn polymorphic_maybe_uninit_array() { + // While the type is polymorphic, MaybeUninit is not. + let _: [MaybeUninit; N] = unsafe { MaybeUninit::uninit().assume_init() }; + } + + fn polymorphic_maybe_uninit() { + // The entire type is polymorphic, but it's wrapped in a MaybeUninit. + let _: MaybeUninit = unsafe { MaybeUninit::uninit().assume_init() }; } } diff --git a/tests/ui/uninit.stderr b/tests/ui/uninit.stderr index 9e01b9a4aa816..248de56da76cb 100644 --- a/tests/ui/uninit.stderr +++ b/tests/ui/uninit.stderr @@ -9,14 +9,14 @@ LL | let _: usize = unsafe { MaybeUninit::uninit().assume_init() }; error: this call for this type may be undefined behavior --> $DIR/uninit.rs:33:29 | -LL | let _: usize = unsafe { mem::MaybeUninit::uninit().assume_init() }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | let _: usize = unsafe { MaybeUninit::uninit().assume_init() }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this call for this type may be undefined behavior - --> $DIR/uninit.rs:39:29 + --> $DIR/uninit.rs:41:29 | -LL | let _: T = unsafe { mem::MaybeUninit::uninit().assume_init() }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | let _: T = unsafe { 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 59ec64a7ab1b9..79effc82fdf7c 100644 --- a/tests/ui/uninit_vec.rs +++ b/tests/ui/uninit_vec.rs @@ -124,4 +124,12 @@ fn main() { vec.set_len(10); } } + + fn poly_maybe_uninit() { + // We are conservative around polymorphic types. + let mut vec: Vec> = Vec::with_capacity(1000); + unsafe { + vec.set_len(10); + } + } } diff --git a/tests/ui/uninlined_format_args.fixed b/tests/ui/uninlined_format_args.fixed index 1475d781c6734..3122081a44f98 100644 --- a/tests/ui/uninlined_format_args.fixed +++ b/tests/ui/uninlined_format_args.fixed @@ -1,7 +1,7 @@ // aux-build:proc_macros.rs // run-rustfix #![warn(clippy::uninlined_format_args)] -#![allow(named_arguments_used_positionally, unused_imports, unused_macros, unused_variables)] +#![allow(named_arguments_used_positionally, unused)] #![allow(clippy::eq_op, clippy::format_in_format_args, clippy::print_literal)] extern crate proc_macros; @@ -119,7 +119,7 @@ fn tester(fn_arg: i32) { println!("Width = {local_i32}, value with width = {local_f64:local_i32$}"); println!("{local_i32:width$.prec$}"); println!("{width:width$.prec$}"); - println!("{}", format!("{local_i32}")); + println!("{}", format!("{}", local_i32)); my_println!("{}", local_i32); my_println_args!("{}", local_i32); @@ -178,3 +178,87 @@ fn _meets_msrv() { fn _do_not_fire() { println!("{:?}", None::<()>); } + +macro_rules! _internal { + ($($args:tt)*) => { + println!("{}", format_args!($($args)*)) + }; +} + +macro_rules! my_println2 { + ($target:expr, $($args:tt)+) => {{ + if $target { + _internal!($($args)+) + } + }}; +} + +macro_rules! my_println2_args { + ($target:expr, $($args:tt)+) => {{ + if $target { + _internal!("foo: {}", format_args!($($args)+)) + } + }}; +} + +macro_rules! my_concat { + ($fmt:literal $(, $e:expr)*) => { + println!(concat!("ERROR: ", $fmt), $($e,)*) + } +} + +macro_rules! my_good_macro { + ($fmt:literal $(, $e:expr)* $(,)?) => { + println!($fmt $(, $e)*) + } +} + +macro_rules! my_bad_macro { + ($fmt:literal, $($e:expr),*) => { + println!($fmt, $($e,)*) + } +} + +macro_rules! my_bad_macro2 { + ($fmt:literal) => { + let s = $fmt.clone(); + println!("{}", s); + }; + ($fmt:literal, $($e:expr)+) => { + println!($fmt, $($e,)*) + }; +} + +// This abomination was suggested by @Alexendoo, may the Rust gods have mercy on their soul... +// https://github.com/rust-lang/rust-clippy/pull/9948#issuecomment-1327965962 +macro_rules! used_twice { + ( + large = $large:literal, + small = $small:literal, + $val:expr, + ) => { + if $val < 5 { + println!($small, $val); + } else { + println!($large, $val); + } + }; +} + +fn tester2() { + let local_i32 = 1; + my_println2_args!(true, "{}", local_i32); + my_println2!(true, "{}", local_i32); + my_concat!("{}", local_i32); + my_good_macro!("{}", local_i32); + my_good_macro!("{}", local_i32,); + + // FIXME: Broken false positives, currently unhandled + my_bad_macro!("{}", local_i32); + my_bad_macro2!("{}", local_i32); + used_twice! { + large = "large value: {}", + small = "small value: {}", + local_i32, + }; +} diff --git a/tests/ui/uninlined_format_args.rs b/tests/ui/uninlined_format_args.rs index 835afac393fae..b153ef256e0c2 100644 --- a/tests/ui/uninlined_format_args.rs +++ b/tests/ui/uninlined_format_args.rs @@ -1,7 +1,7 @@ // aux-build:proc_macros.rs // run-rustfix #![warn(clippy::uninlined_format_args)] -#![allow(named_arguments_used_positionally, unused_imports, unused_macros, unused_variables)] +#![allow(named_arguments_used_positionally, unused)] #![allow(clippy::eq_op, clippy::format_in_format_args, clippy::print_literal)] extern crate proc_macros; @@ -183,3 +183,87 @@ fn _meets_msrv() { fn _do_not_fire() { println!("{:?}", None::<()>); } + +macro_rules! _internal { + ($($args:tt)*) => { + println!("{}", format_args!($($args)*)) + }; +} + +macro_rules! my_println2 { + ($target:expr, $($args:tt)+) => {{ + if $target { + _internal!($($args)+) + } + }}; +} + +macro_rules! my_println2_args { + ($target:expr, $($args:tt)+) => {{ + if $target { + _internal!("foo: {}", format_args!($($args)+)) + } + }}; +} + +macro_rules! my_concat { + ($fmt:literal $(, $e:expr)*) => { + println!(concat!("ERROR: ", $fmt), $($e,)*) + } +} + +macro_rules! my_good_macro { + ($fmt:literal $(, $e:expr)* $(,)?) => { + println!($fmt $(, $e)*) + } +} + +macro_rules! my_bad_macro { + ($fmt:literal, $($e:expr),*) => { + println!($fmt, $($e,)*) + } +} + +macro_rules! my_bad_macro2 { + ($fmt:literal) => { + let s = $fmt.clone(); + println!("{}", s); + }; + ($fmt:literal, $($e:expr)+) => { + println!($fmt, $($e,)*) + }; +} + +// This abomination was suggested by @Alexendoo, may the Rust gods have mercy on their soul... +// https://github.com/rust-lang/rust-clippy/pull/9948#issuecomment-1327965962 +macro_rules! used_twice { + ( + large = $large:literal, + small = $small:literal, + $val:expr, + ) => { + if $val < 5 { + println!($small, $val); + } else { + println!($large, $val); + } + }; +} + +fn tester2() { + let local_i32 = 1; + my_println2_args!(true, "{}", local_i32); + my_println2!(true, "{}", local_i32); + my_concat!("{}", local_i32); + my_good_macro!("{}", local_i32); + my_good_macro!("{}", local_i32,); + + // FIXME: Broken false positives, currently unhandled + my_bad_macro!("{}", local_i32); + my_bad_macro2!("{}", local_i32); + used_twice! { + large = "large value: {}", + small = "small value: {}", + local_i32, + }; +} diff --git a/tests/ui/uninlined_format_args.stderr b/tests/ui/uninlined_format_args.stderr index a12abf8bef8af..dc4af6ef42ecd 100644 --- a/tests/ui/uninlined_format_args.stderr +++ b/tests/ui/uninlined_format_args.stderr @@ -774,18 +774,6 @@ LL - println!("{:w$.p$}", w = width, p = prec); LL + println!("{width:width$.prec$}"); | -error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:125:20 - | -LL | println!("{}", format!("{}", local_i32)); - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: change this to - | -LL - println!("{}", format!("{}", local_i32)); -LL + println!("{}", format!("{local_i32}")); - | - error: variables can be used directly in the `format!` string --> $DIR/uninlined_format_args.rs:143:5 | @@ -856,5 +844,5 @@ LL - println!("expand='{}'", local_i32); LL + println!("expand='{local_i32}'"); | -error: aborting due to 72 previous errors +error: aborting due to 71 previous errors diff --git a/tests/ui/unnecessary_box_returns.rs b/tests/ui/unnecessary_box_returns.rs new file mode 100644 index 0000000000000..fe60d929759ba --- /dev/null +++ b/tests/ui/unnecessary_box_returns.rs @@ -0,0 +1,60 @@ +#![warn(clippy::unnecessary_box_returns)] + +trait Bar { + // lint + fn baz(&self) -> Box; +} + +pub struct Foo {} + +impl Bar for Foo { + // don't lint: this is a problem with the trait, not the implementation + fn baz(&self) -> Box { + Box::new(42) + } +} + +impl Foo { + fn baz(&self) -> Box { + // lint + Box::new(13) + } +} + +// lint +fn bxed_usize() -> Box { + Box::new(5) +} + +// lint +fn _bxed_foo() -> Box { + Box::new(Foo {}) +} + +// don't lint: this is exported +pub fn bxed_foo() -> Box { + Box::new(Foo {}) +} + +// don't lint: str is unsized +fn bxed_str() -> Box { + "Hello, world!".to_string().into_boxed_str() +} + +// don't lint: function contains the word, "box" +fn boxed_usize() -> Box { + Box::new(7) +} + +// don't lint: this has an unspecified return type +fn default() {} + +// don't lint: this doesn't return a Box +fn string() -> String { + String::from("Hello, world") +} + +fn main() { + // don't lint: this is a closure + let a = || -> Box { Box::new(5) }; +} diff --git a/tests/ui/unnecessary_box_returns.stderr b/tests/ui/unnecessary_box_returns.stderr new file mode 100644 index 0000000000000..b17512c10a177 --- /dev/null +++ b/tests/ui/unnecessary_box_returns.stderr @@ -0,0 +1,35 @@ +error: boxed return of the sized type `usize` + --> $DIR/unnecessary_box_returns.rs:5:22 + | +LL | fn baz(&self) -> Box; + | ^^^^^^^^^^ help: try: `usize` + | + = help: changing this also requires a change to the return expressions in this function + = note: `-D clippy::unnecessary-box-returns` implied by `-D warnings` + +error: boxed return of the sized type `usize` + --> $DIR/unnecessary_box_returns.rs:18:22 + | +LL | fn baz(&self) -> Box { + | ^^^^^^^^^^ help: try: `usize` + | + = help: changing this also requires a change to the return expressions in this function + +error: boxed return of the sized type `usize` + --> $DIR/unnecessary_box_returns.rs:25:20 + | +LL | fn bxed_usize() -> Box { + | ^^^^^^^^^^ help: try: `usize` + | + = help: changing this also requires a change to the return expressions in this function + +error: boxed return of the sized type `Foo` + --> $DIR/unnecessary_box_returns.rs:30:19 + | +LL | fn _bxed_foo() -> Box { + | ^^^^^^^^ help: try: `Foo` + | + = help: changing this also requires a change to the return expressions in this function + +error: aborting due to 4 previous errors + diff --git a/tests/ui/unused_format_specs.fixed b/tests/ui/unused_format_specs.fixed deleted file mode 100644 index 2930722b42d9d..0000000000000 --- a/tests/ui/unused_format_specs.fixed +++ /dev/null @@ -1,18 +0,0 @@ -// run-rustfix - -#![warn(clippy::unused_format_specs)] -#![allow(unused)] - -fn main() { - let f = 1.0f64; - println!("{}", 1.0); - println!("{f} {f:?}"); - - println!("{}", 1); -} - -fn should_not_lint() { - let f = 1.0f64; - println!("{:.1}", 1.0); - println!("{f:.w$} {f:.*?}", 3, w = 2); -} diff --git a/tests/ui/unused_format_specs.rs b/tests/ui/unused_format_specs.rs deleted file mode 100644 index ee192a000d4b5..0000000000000 --- a/tests/ui/unused_format_specs.rs +++ /dev/null @@ -1,18 +0,0 @@ -// run-rustfix - -#![warn(clippy::unused_format_specs)] -#![allow(unused)] - -fn main() { - let f = 1.0f64; - println!("{:.}", 1.0); - println!("{f:.} {f:.?}"); - - println!("{:.}", 1); -} - -fn should_not_lint() { - let f = 1.0f64; - println!("{:.1}", 1.0); - println!("{f:.w$} {f:.*?}", 3, w = 2); -} diff --git a/tests/ui/unused_format_specs.stderr b/tests/ui/unused_format_specs.stderr deleted file mode 100644 index 7231c17e74c19..0000000000000 --- a/tests/ui/unused_format_specs.stderr +++ /dev/null @@ -1,54 +0,0 @@ -error: empty precision specifier has no effect - --> $DIR/unused_format_specs.rs:8:17 - | -LL | println!("{:.}", 1.0); - | ^ - | - = note: a precision specifier is not required to format floats - = note: `-D clippy::unused-format-specs` implied by `-D warnings` -help: remove the `.` - | -LL - println!("{:.}", 1.0); -LL + println!("{}", 1.0); - | - -error: empty precision specifier has no effect - --> $DIR/unused_format_specs.rs:9:18 - | -LL | println!("{f:.} {f:.?}"); - | ^ - | - = note: a precision specifier is not required to format floats -help: remove the `.` - | -LL - println!("{f:.} {f:.?}"); -LL + println!("{f} {f:.?}"); - | - -error: empty precision specifier has no effect - --> $DIR/unused_format_specs.rs:9:24 - | -LL | println!("{f:.} {f:.?}"); - | ^ - | - = note: a precision specifier is not required to format floats -help: remove the `.` - | -LL - println!("{f:.} {f:.?}"); -LL + println!("{f:.} {f:?}"); - | - -error: empty precision specifier has no effect - --> $DIR/unused_format_specs.rs:11:17 - | -LL | println!("{:.}", 1); - | ^ - | -help: remove the `.` - | -LL - println!("{:.}", 1); -LL + println!("{}", 1); - | - -error: aborting due to 4 previous errors - diff --git a/tests/ui/unused_format_specs_unfixable.stderr b/tests/ui/unused_format_specs_unfixable.stderr index 9f1890282e6ac..cb7156b6baf0d 100644 --- a/tests/ui/unused_format_specs_unfixable.stderr +++ b/tests/ui/unused_format_specs_unfixable.stderr @@ -37,11 +37,7 @@ error: format specifiers have no effect on `format_args!()` LL | println!("{:5}.", format_args_from_macro!()); | ^^^^ | -help: for the width to apply consider using `format!()` - --> $DIR/unused_format_specs_unfixable.rs:16:17 - | -LL | println!("{:5}.", format_args_from_macro!()); - | ^ + = help: for the width to apply consider using `format!()` help: if the current behavior is intentional, remove the format specifiers | LL - println!("{:5}.", format_args_from_macro!()); @@ -54,11 +50,7 @@ error: format specifiers have no effect on `format_args!()` LL | println!("{args:5}"); | ^^^^^^^^ | -help: for the width to apply consider using `format!()` - --> $DIR/unused_format_specs_unfixable.rs:19:21 - | -LL | println!("{args:5}"); - | ^ + = help: for the width to apply consider using `format!()` help: if the current behavior is intentional, remove the format specifiers | LL - println!("{args:5}"); From 5989400e2e068aec0ecc12e53dddc1d8b0c0e585 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Mon, 10 Apr 2023 19:07:57 +0300 Subject: [PATCH 05/86] resolve: Pre-compute non-reexport module children Instead of repeating the same logic by walking HIR during metadata encoding. The only difference is that we are no longer encoding `macro_rules` items, but we never currently need them as a part of this list. They can be encoded separately if this need ever arises. `module_reexports` is also un-querified, because I don't see any reasons to make it a query, only overhead. --- tests/ui/macro_use_imports.fixed | 2 +- tests/ui/macro_use_imports.stderr | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/ui/macro_use_imports.fixed b/tests/ui/macro_use_imports.fixed index 15f7a099a7de5..a395e4f5653f0 100644 --- a/tests/ui/macro_use_imports.fixed +++ b/tests/ui/macro_use_imports.fixed @@ -16,7 +16,7 @@ extern crate macro_use_helper as mac; extern crate proc_macro_derive as mini_mac; mod a { - use mac::{pub_macro, function_macro, ty_macro, inner_mod_macro, pub_in_private_macro}; + use mac::{pub_macro, inner_mod_macro, function_macro, ty_macro, pub_in_private_macro}; use mac; use mini_mac::ClippyMiniMacroTest; use mini_mac; diff --git a/tests/ui/macro_use_imports.stderr b/tests/ui/macro_use_imports.stderr index 68d558dede054..6fd338cef8688 100644 --- a/tests/ui/macro_use_imports.stderr +++ b/tests/ui/macro_use_imports.stderr @@ -22,7 +22,7 @@ error: `macro_use` attributes are no longer needed in the Rust 2018 edition --> $DIR/macro_use_imports.rs:19:5 | LL | #[macro_use] - | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::{pub_macro, function_macro, ty_macro, inner_mod_macro, pub_in_private_macro};` + | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::{pub_macro, inner_mod_macro, function_macro, ty_macro, pub_in_private_macro};` error: aborting due to 4 previous errors From 7a0fb902bc3c02f7832f8fed074d8dfd21bf7ea8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sat, 18 Mar 2023 02:18:39 +0000 Subject: [PATCH 06/86] Tweak output for 'add line' suggestion --- tests/ui/crashes/ice-6252.stderr | 9 ++++++--- tests/ui/derivable_impls.stderr | 24 ++++++++++++++++-------- tests/ui/new_without_default.stderr | 6 ++++++ 3 files changed, 28 insertions(+), 11 deletions(-) diff --git a/tests/ui/crashes/ice-6252.stderr b/tests/ui/crashes/ice-6252.stderr index efdd56dd47d39..3c7e08ebeae85 100644 --- a/tests/ui/crashes/ice-6252.stderr +++ b/tests/ui/crashes/ice-6252.stderr @@ -6,11 +6,14 @@ LL | _n: PhantomData, | help: consider importing one of these items | -LL | use core::marker::PhantomData; +LL + use core::marker::PhantomData; +LL | trait TypeVal { | -LL | use serde::__private::PhantomData; +LL + use serde::__private::PhantomData; +LL | trait TypeVal { | -LL | use std::marker::PhantomData; +LL + use std::marker::PhantomData; +LL | trait TypeVal { | error[E0412]: cannot find type `VAL` in this scope diff --git a/tests/ui/derivable_impls.stderr b/tests/ui/derivable_impls.stderr index 81963c3be5b5d..8089f5ea0fcb2 100644 --- a/tests/ui/derivable_impls.stderr +++ b/tests/ui/derivable_impls.stderr @@ -14,7 +14,8 @@ LL | | } = help: remove the manual implementation... help: ...and instead derive it | -LL | #[derive(Default)] +LL + #[derive(Default)] +LL | struct FooDefault<'a> { | error: this `impl` can be derived @@ -30,7 +31,8 @@ LL | | } = help: remove the manual implementation... help: ...and instead derive it | -LL | #[derive(Default)] +LL + #[derive(Default)] +LL | struct TupleDefault(bool, i32, u64); | error: this `impl` can be derived @@ -46,7 +48,8 @@ LL | | } = help: remove the manual implementation... help: ...and instead derive it | -LL | #[derive(Default)] +LL + #[derive(Default)] +LL | struct StrDefault<'a>(&'a str); | error: this `impl` can be derived @@ -62,7 +65,8 @@ LL | | } = help: remove the manual implementation... help: ...and instead derive it | -LL | #[derive(Default)] +LL + #[derive(Default)] +LL | struct Y(u32); | error: this `impl` can be derived @@ -78,7 +82,8 @@ LL | | } = help: remove the manual implementation... help: ...and instead derive it | -LL | #[derive(Default)] +LL + #[derive(Default)] +LL | struct WithoutSelfCurly { | error: this `impl` can be derived @@ -94,7 +99,8 @@ LL | | } = help: remove the manual implementation... help: ...and instead derive it | -LL | #[derive(Default)] +LL + #[derive(Default)] +LL | struct WithoutSelfParan(bool); | error: this `impl` can be derived @@ -110,7 +116,8 @@ LL | | } = help: remove the manual implementation... help: ...and instead derive it | -LL | #[derive(Default)] +LL + #[derive(Default)] +LL | pub struct RepeatDefault1 { | error: this `impl` can be derived @@ -126,7 +133,8 @@ LL | | } = help: remove the manual implementation... help: ...and instead derive it... | -LL | #[derive(Default)] +LL + #[derive(Default)] +LL | pub enum SimpleEnum { | help: ...and mark the default variant | diff --git a/tests/ui/new_without_default.stderr b/tests/ui/new_without_default.stderr index 583dd327d6a5d..9b0a2f6ca5bf2 100644 --- a/tests/ui/new_without_default.stderr +++ b/tests/ui/new_without_default.stderr @@ -14,6 +14,7 @@ LL + fn default() -> Self { LL + Self::new() LL + } LL + } +LL | impl Foo { | error: you should consider adding a `Default` implementation for `Bar` @@ -31,6 +32,7 @@ LL + fn default() -> Self { LL + Self::new() LL + } LL + } +LL | impl Bar { | error: you should consider adding a `Default` implementation for `LtKo<'c>` @@ -48,6 +50,7 @@ LL + fn default() -> Self { LL + Self::new() LL + } LL + } +LL | impl<'c> LtKo<'c> { | error: you should consider adding a `Default` implementation for `NewNotEqualToDerive` @@ -65,6 +68,7 @@ LL + fn default() -> Self { LL + Self::new() LL + } LL + } +LL | impl NewNotEqualToDerive { | error: you should consider adding a `Default` implementation for `FooGenerics` @@ -82,6 +86,7 @@ LL + fn default() -> Self { LL + Self::new() LL + } LL + } +LL | impl FooGenerics { | error: you should consider adding a `Default` implementation for `BarGenerics` @@ -99,6 +104,7 @@ LL + fn default() -> Self { LL + Self::new() LL + } LL + } +LL | impl BarGenerics { | error: you should consider adding a `Default` implementation for `Foo` From 4680aa2fd07876a4d2f7059defef2595e3184038 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 10 Apr 2023 16:46:12 +0000 Subject: [PATCH 07/86] Special-case item attributes in the suggestion output --- tests/ui/crashes/ice-6252.stderr | 3 --- tests/ui/new_without_default.stderr | 6 ------ 2 files changed, 9 deletions(-) diff --git a/tests/ui/crashes/ice-6252.stderr b/tests/ui/crashes/ice-6252.stderr index 3c7e08ebeae85..4787282f504a6 100644 --- a/tests/ui/crashes/ice-6252.stderr +++ b/tests/ui/crashes/ice-6252.stderr @@ -7,13 +7,10 @@ LL | _n: PhantomData, help: consider importing one of these items | LL + use core::marker::PhantomData; -LL | trait TypeVal { | LL + use serde::__private::PhantomData; -LL | trait TypeVal { | LL + use std::marker::PhantomData; -LL | trait TypeVal { | error[E0412]: cannot find type `VAL` in this scope diff --git a/tests/ui/new_without_default.stderr b/tests/ui/new_without_default.stderr index 9b0a2f6ca5bf2..583dd327d6a5d 100644 --- a/tests/ui/new_without_default.stderr +++ b/tests/ui/new_without_default.stderr @@ -14,7 +14,6 @@ LL + fn default() -> Self { LL + Self::new() LL + } LL + } -LL | impl Foo { | error: you should consider adding a `Default` implementation for `Bar` @@ -32,7 +31,6 @@ LL + fn default() -> Self { LL + Self::new() LL + } LL + } -LL | impl Bar { | error: you should consider adding a `Default` implementation for `LtKo<'c>` @@ -50,7 +48,6 @@ LL + fn default() -> Self { LL + Self::new() LL + } LL + } -LL | impl<'c> LtKo<'c> { | error: you should consider adding a `Default` implementation for `NewNotEqualToDerive` @@ -68,7 +65,6 @@ LL + fn default() -> Self { LL + Self::new() LL + } LL + } -LL | impl NewNotEqualToDerive { | error: you should consider adding a `Default` implementation for `FooGenerics` @@ -86,7 +82,6 @@ LL + fn default() -> Self { LL + Self::new() LL + } LL + } -LL | impl FooGenerics { | error: you should consider adding a `Default` implementation for `BarGenerics` @@ -104,7 +99,6 @@ LL + fn default() -> Self { LL + Self::new() LL + } LL + } -LL | impl BarGenerics { | error: you should consider adding a `Default` implementation for `Foo` From 8f53926232c43aa9d03e88c24460411542a244ed Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Sat, 25 Mar 2023 10:12:35 +0000 Subject: [PATCH 08/86] Alloc `hir::Lit` in an arena to remove the destructor from `Expr` This allows allocating `Expr`s into a dropless arena, which is useful for using length prefixed thing slices in HIR, since these can only be allocated in the dropless arena and not in a typed arena. This is something I'm working on. --- clippy_lints/src/bool_assert_comparison.rs | 2 +- clippy_lints/src/manual_strip.rs | 2 +- clippy_lints/src/matches/match_like_matches.rs | 2 +- clippy_lints/src/methods/open_options.rs | 2 +- clippy_lints/src/utils/author.rs | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/clippy_lints/src/bool_assert_comparison.rs b/clippy_lints/src/bool_assert_comparison.rs index 1d9096ea64d1c..8c3ad24eeed43 100644 --- a/clippy_lints/src/bool_assert_comparison.rs +++ b/clippy_lints/src/bool_assert_comparison.rs @@ -41,7 +41,7 @@ fn extract_bool_lit(e: &Expr<'_>) -> Option { }) = e.kind && !e.span.from_expansion() { - Some(b) + Some(*b) } else { None } diff --git a/clippy_lints/src/manual_strip.rs b/clippy_lints/src/manual_strip.rs index c795c1d9a16c3..7d28c11162458 100644 --- a/clippy_lints/src/manual_strip.rs +++ b/clippy_lints/src/manual_strip.rs @@ -159,7 +159,7 @@ fn eq_pattern_length<'tcx>(cx: &LateContext<'tcx>, pattern: &Expr<'_>, expr: &'t .. }) = expr.kind { - constant_length(cx, pattern).map_or(false, |length| length == n) + constant_length(cx, pattern).map_or(false, |length| length == *n) } else { len_arg(cx, expr).map_or(false, |arg| eq_expr_value(cx, pattern, arg)) } diff --git a/clippy_lints/src/matches/match_like_matches.rs b/clippy_lints/src/matches/match_like_matches.rs index 107fad32393cf..33bc20dad6b78 100644 --- a/clippy_lints/src/matches/match_like_matches.rs +++ b/clippy_lints/src/matches/match_like_matches.rs @@ -162,7 +162,7 @@ fn find_bool_lit(ex: &ExprKind<'_>) -> Option { node: LitKind::Bool(b), .. }) = exp.kind { - Some(b) + Some(*b) } else { None } diff --git a/clippy_lints/src/methods/open_options.rs b/clippy_lints/src/methods/open_options.rs index c6a27cdd6fac0..23d23f25f14cf 100644 --- a/clippy_lints/src/methods/open_options.rs +++ b/clippy_lints/src/methods/open_options.rs @@ -48,7 +48,7 @@ fn get_open_options(cx: &LateContext<'_>, argument: &Expr<'_>, options: &mut Vec .. } = *span { - if lit { Argument::True } else { Argument::False } + if *lit { Argument::True } else { Argument::False } } else { // The function is called with a literal which is not a boolean literal. // This is theoretically possible, but not very likely. diff --git a/clippy_lints/src/utils/author.rs b/clippy_lints/src/utils/author.rs index bc4adf1596d44..2dac807c420e3 100644 --- a/clippy_lints/src/utils/author.rs +++ b/clippy_lints/src/utils/author.rs @@ -430,7 +430,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { kind!("Unary(UnOp::{op:?}, {inner})"); self.expr(inner); }, - ExprKind::Lit(ref lit) => { + ExprKind::Lit(lit) => { bind!(self, lit); kind!("Lit(ref {lit})"); self.lit(lit); From 0a81f8257e2317b019406c42575d10bbd33c7268 Mon Sep 17 00:00:00 2001 From: Centri3 <114838443+Centri3@users.noreply.github.com> Date: Sun, 16 Apr 2023 23:30:00 -0500 Subject: [PATCH 09/86] add `semicolon_outside_block_if_singleline` lint --- CHANGELOG.md | 1 + clippy_lints/src/declared_lints.rs | 1 + clippy_lints/src/semicolon_block.rs | 92 ++++++++++++++++++- ...emicolon_outside_block_if_singleline.fixed | 85 +++++++++++++++++ .../semicolon_outside_block_if_singleline.rs | 85 +++++++++++++++++ ...micolon_outside_block_if_singleline.stderr | 54 +++++++++++ 6 files changed, 317 insertions(+), 1 deletion(-) create mode 100644 tests/ui/semicolon_outside_block_if_singleline.fixed create mode 100644 tests/ui/semicolon_outside_block_if_singleline.rs create mode 100644 tests/ui/semicolon_outside_block_if_singleline.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 559b560dde4ba..a0a7780f4c278 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4884,6 +4884,7 @@ Released 2018-09-13 [`semicolon_if_nothing_returned`]: https://rust-lang.github.io/rust-clippy/master/index.html#semicolon_if_nothing_returned [`semicolon_inside_block`]: https://rust-lang.github.io/rust-clippy/master/index.html#semicolon_inside_block [`semicolon_outside_block`]: https://rust-lang.github.io/rust-clippy/master/index.html#semicolon_outside_block +[`semicolon_outside_block_if_singleline`]: https://rust-lang.github.io/rust-clippy/master/index.html#semicolon_outside_block_if_singleline [`separated_literal_suffix`]: https://rust-lang.github.io/rust-clippy/master/index.html#separated_literal_suffix [`serde_api_misuse`]: https://rust-lang.github.io/rust-clippy/master/index.html#serde_api_misuse [`shadow_reuse`]: https://rust-lang.github.io/rust-clippy/master/index.html#shadow_reuse diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index f24dab6278095..70379b6caf114 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -546,6 +546,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::self_named_constructors::SELF_NAMED_CONSTRUCTORS_INFO, crate::semicolon_block::SEMICOLON_INSIDE_BLOCK_INFO, crate::semicolon_block::SEMICOLON_OUTSIDE_BLOCK_INFO, + crate::semicolon_block::SEMICOLON_OUTSIDE_BLOCK_IF_SINGLELINE_INFO, crate::semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED_INFO, crate::serde_api::SERDE_API_MISUSE_INFO, crate::shadow::SHADOW_REUSE_INFO, diff --git a/clippy_lints/src/semicolon_block.rs b/clippy_lints/src/semicolon_block.rs index 34a3e5ddf4f6b..d791100b9b9a6 100644 --- a/clippy_lints/src/semicolon_block.rs +++ b/clippy_lints/src/semicolon_block.rs @@ -64,7 +64,48 @@ declare_clippy_lint! { restriction, "add a semicolon outside the block" } -declare_lint_pass!(SemicolonBlock => [SEMICOLON_INSIDE_BLOCK, SEMICOLON_OUTSIDE_BLOCK]); +declare_clippy_lint! { + /// ### What it does + /// + /// Suggests moving the semicolon from a block's final expression outside of + /// the block if it's singleline, and inside the block if it's multiline. + /// + /// ### Why is this bad? + /// + /// Some may prefer if the semicolon is outside if a block is only one + /// expression, as this allows rustfmt to make it singleline. In the case that + /// it isn't, it should be inside. + /// Take a look at both `semicolon_inside_block` and `semicolon_outside_block` for alternatives. + /// + /// ### Example + /// + /// ```rust + /// # fn f(_: u32) {} + /// # let x = 0; + /// unsafe { f(x); } + /// + /// unsafe { + /// let x = 1; + /// f(x) + /// }; + /// ``` + /// Use instead: + /// ```rust + /// # fn f(_: u32) {} + /// # let x = 0; + /// unsafe { f(x) }; + /// + /// unsafe { + /// let x = 1; + /// f(x); + /// } + /// ``` + #[clippy::version = "1.68.0"] + pub SEMICOLON_OUTSIDE_BLOCK_IF_SINGLELINE, + restriction, + "add a semicolon inside the block if it's singleline, otherwise outside" +} +declare_lint_pass!(SemicolonBlock => [SEMICOLON_INSIDE_BLOCK, SEMICOLON_OUTSIDE_BLOCK, SEMICOLON_OUTSIDE_BLOCK_IF_SINGLELINE]); impl LateLintPass<'_> for SemicolonBlock { fn check_stmt(&mut self, cx: &LateContext<'_>, stmt: &Stmt<'_>) { @@ -98,6 +139,8 @@ fn semicolon_inside_block(cx: &LateContext<'_>, block: &Block<'_>, tail: &Expr<' let insert_span = tail.span.source_callsite().shrink_to_hi(); let remove_span = semi_span.with_lo(block.span.hi()); + check_semicolon_outside_block_if_singleline(cx, block, remove_span, insert_span, true, "inside"); + span_lint_and_then( cx, SEMICOLON_INSIDE_BLOCK, @@ -120,6 +163,8 @@ fn semicolon_outside_block(cx: &LateContext<'_>, block: &Block<'_>, tail_stmt_ex let semi_span = cx.sess().source_map().stmt_span(semi_span, block.span); let remove_span = semi_span.with_lo(tail_stmt_expr.span.source_callsite().hi()); + check_semicolon_outside_block_if_singleline(cx, block, remove_span, insert_span, false, "outside"); + span_lint_and_then( cx, SEMICOLON_OUTSIDE_BLOCK, @@ -135,3 +180,48 @@ fn semicolon_outside_block(cx: &LateContext<'_>, block: &Block<'_>, tail_stmt_ex }, ); } + +fn check_semicolon_outside_block_if_singleline( + cx: &LateContext<'_>, + block: &Block<'_>, + remove_span: Span, + insert_span: Span, + inequality: bool, + ty: &str, +) { + let remove_line = cx + .sess() + .source_map() + .lookup_line(remove_span.lo()) + .expect("failed to get `remove_span`'s line") + .line; + let insert_line = cx + .sess() + .source_map() + .lookup_line(insert_span.lo()) + .expect("failed to get `insert_span`'s line") + .line; + + let eq = if inequality { + remove_line != insert_line + } else { + remove_line == insert_line + }; + + if eq { + span_lint_and_then( + cx, + SEMICOLON_OUTSIDE_BLOCK_IF_SINGLELINE, + block.span, + &format!("consider moving the `;` {ty} the block for consistent formatting"), + |diag| { + multispan_sugg_with_applicability( + diag, + "put the `;` here", + Applicability::MachineApplicable, + [(remove_span, String::new()), (insert_span, ";".to_owned())], + ); + }, + ); + } +} diff --git a/tests/ui/semicolon_outside_block_if_singleline.fixed b/tests/ui/semicolon_outside_block_if_singleline.fixed new file mode 100644 index 0000000000000..592f9c49ed77b --- /dev/null +++ b/tests/ui/semicolon_outside_block_if_singleline.fixed @@ -0,0 +1,85 @@ +// run-rustfix +#![allow( + unused, + clippy::unused_unit, + clippy::unnecessary_operation, + clippy::no_effect, + clippy::single_element_loop +)] +#![warn(clippy::semicolon_outside_block_if_singleline)] + +macro_rules! m { + (()) => { + () + }; + (0) => {{ + 0 + };}; + (1) => {{ + 1; + }}; + (2) => {{ + 2; + }}; +} + +fn unit_fn_block() { + () +} + +#[rustfmt::skip] +fn main() { + { unit_fn_block() } + unsafe { unit_fn_block() } + + { + unit_fn_block() + } + + { unit_fn_block() }; + unsafe { unit_fn_block() }; + + { unit_fn_block() }; + unsafe { unit_fn_block() }; + + { unit_fn_block(); }; + unsafe { unit_fn_block(); }; + + { + unit_fn_block(); + unit_fn_block(); + } + { + unit_fn_block(); + unit_fn_block(); + } + { + unit_fn_block(); + unit_fn_block(); + }; + + { m!(()) }; + { m!(()) }; + { m!(()); }; + m!(0); + m!(1); + m!(2); + + for _ in [()] { + unit_fn_block(); + } + for _ in [()] { + unit_fn_block() + } + + let _d = || { + unit_fn_block(); + }; + let _d = || { + unit_fn_block() + }; + + { unit_fn_block(); }; + + unit_fn_block() +} \ No newline at end of file diff --git a/tests/ui/semicolon_outside_block_if_singleline.rs b/tests/ui/semicolon_outside_block_if_singleline.rs new file mode 100644 index 0000000000000..21dd61445a5be --- /dev/null +++ b/tests/ui/semicolon_outside_block_if_singleline.rs @@ -0,0 +1,85 @@ +// run-rustfix +#![allow( + unused, + clippy::unused_unit, + clippy::unnecessary_operation, + clippy::no_effect, + clippy::single_element_loop +)] +#![warn(clippy::semicolon_outside_block_if_singleline)] + +macro_rules! m { + (()) => { + () + }; + (0) => {{ + 0 + };}; + (1) => {{ + 1; + }}; + (2) => {{ + 2; + }}; +} + +fn unit_fn_block() { + () +} + +#[rustfmt::skip] +fn main() { + { unit_fn_block() } + unsafe { unit_fn_block() } + + { + unit_fn_block() + } + + { unit_fn_block() }; + unsafe { unit_fn_block() }; + + { unit_fn_block(); } + unsafe { unit_fn_block(); } + + { unit_fn_block(); }; + unsafe { unit_fn_block(); }; + + { + unit_fn_block(); + unit_fn_block() + }; + { + unit_fn_block(); + unit_fn_block(); + } + { + unit_fn_block(); + unit_fn_block(); + }; + + { m!(()) }; + { m!(()); } + { m!(()); }; + m!(0); + m!(1); + m!(2); + + for _ in [()] { + unit_fn_block(); + } + for _ in [()] { + unit_fn_block() + } + + let _d = || { + unit_fn_block(); + }; + let _d = || { + unit_fn_block() + }; + + { unit_fn_block(); }; + + unit_fn_block() +} \ No newline at end of file diff --git a/tests/ui/semicolon_outside_block_if_singleline.stderr b/tests/ui/semicolon_outside_block_if_singleline.stderr new file mode 100644 index 0000000000000..dda083f2be3e0 --- /dev/null +++ b/tests/ui/semicolon_outside_block_if_singleline.stderr @@ -0,0 +1,54 @@ +error: consider moving the `;` outside the block for consistent formatting + --> $DIR/semicolon_outside_block_if_singleline.rs:42:5 + | +LL | { unit_fn_block(); } + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::semicolon-outside-block-if-singleline` implied by `-D warnings` +help: put the `;` here + | +LL - { unit_fn_block(); } +LL + { unit_fn_block() }; + | + +error: consider moving the `;` outside the block for consistent formatting + --> $DIR/semicolon_outside_block_if_singleline.rs:43:5 + | +LL | unsafe { unit_fn_block(); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: put the `;` here + | +LL - unsafe { unit_fn_block(); } +LL + unsafe { unit_fn_block() }; + | + +error: consider moving the `;` inside the block for consistent formatting + --> $DIR/semicolon_outside_block_if_singleline.rs:48:5 + | +LL | / { +LL | | unit_fn_block(); +LL | | unit_fn_block() +LL | | }; + | |_____^ + | +help: put the `;` here + | +LL ~ unit_fn_block(); +LL ~ } + | + +error: consider moving the `;` outside the block for consistent formatting + --> $DIR/semicolon_outside_block_if_singleline.rs:62:5 + | +LL | { m!(()); } + | ^^^^^^^^^^^ + | +help: put the `;` here + | +LL - { m!(()); } +LL + { m!(()) }; + | + +error: aborting due to 4 previous errors + From dfccebe3e01e8c63ea0fc2833550123e45091e5b Mon Sep 17 00:00:00 2001 From: Centri3 <114838443+Centri3@users.noreply.github.com> Date: Sun, 16 Apr 2023 23:36:01 -0500 Subject: [PATCH 10/86] make cargo test pass --- clippy_lints/src/semicolon_block.rs | 4 ++-- tests/ui/semicolon_outside_block_if_singleline.fixed | 2 +- tests/ui/semicolon_outside_block_if_singleline.rs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/semicolon_block.rs b/clippy_lints/src/semicolon_block.rs index d791100b9b9a6..eabe0e4619f6e 100644 --- a/clippy_lints/src/semicolon_block.rs +++ b/clippy_lints/src/semicolon_block.rs @@ -83,7 +83,7 @@ declare_clippy_lint! { /// # fn f(_: u32) {} /// # let x = 0; /// unsafe { f(x); } - /// + /// /// unsafe { /// let x = 1; /// f(x) @@ -94,7 +94,7 @@ declare_clippy_lint! { /// # fn f(_: u32) {} /// # let x = 0; /// unsafe { f(x) }; - /// + /// /// unsafe { /// let x = 1; /// f(x); diff --git a/tests/ui/semicolon_outside_block_if_singleline.fixed b/tests/ui/semicolon_outside_block_if_singleline.fixed index 592f9c49ed77b..e1ecbf8588d95 100644 --- a/tests/ui/semicolon_outside_block_if_singleline.fixed +++ b/tests/ui/semicolon_outside_block_if_singleline.fixed @@ -82,4 +82,4 @@ fn main() { { unit_fn_block(); }; unit_fn_block() -} \ No newline at end of file +} diff --git a/tests/ui/semicolon_outside_block_if_singleline.rs b/tests/ui/semicolon_outside_block_if_singleline.rs index 21dd61445a5be..80fbb4ce2d5eb 100644 --- a/tests/ui/semicolon_outside_block_if_singleline.rs +++ b/tests/ui/semicolon_outside_block_if_singleline.rs @@ -82,4 +82,4 @@ fn main() { { unit_fn_block(); }; unit_fn_block() -} \ No newline at end of file +} From a7c3301b5884b33fc87f2e498f28426dfbcb1a84 Mon Sep 17 00:00:00 2001 From: Centri3 <114838443+Centri3@users.noreply.github.com> Date: Sun, 16 Apr 2023 23:56:21 -0500 Subject: [PATCH 11/86] refactor --- clippy_lints/src/semicolon_block.rs | 90 +++++++++++++++++++---------- 1 file changed, 61 insertions(+), 29 deletions(-) diff --git a/clippy_lints/src/semicolon_block.rs b/clippy_lints/src/semicolon_block.rs index eabe0e4619f6e..d85d3b5830585 100644 --- a/clippy_lints/src/semicolon_block.rs +++ b/clippy_lints/src/semicolon_block.rs @@ -125,11 +125,15 @@ impl LateLintPass<'_> for SemicolonBlock { .. } = stmt else { return }; semicolon_outside_block(cx, block, expr, span); + semicolon_outside_block_if_singleline_check_outside(cx, block, expr, stmt.span) }, StmtKind::Semi(Expr { kind: ExprKind::Block(block @ Block { expr: Some(tail), .. }, _), .. - }) if !block.span.from_expansion() => semicolon_inside_block(cx, block, tail, stmt.span), + }) if !block.span.from_expansion() => { + semicolon_inside_block(cx, block, tail, stmt.span); + semicolon_outside_block_if_singleline_check_inside(cx, block, tail, stmt.span) + }, _ => (), } } @@ -139,8 +143,6 @@ fn semicolon_inside_block(cx: &LateContext<'_>, block: &Block<'_>, tail: &Expr<' let insert_span = tail.span.source_callsite().shrink_to_hi(); let remove_span = semi_span.with_lo(block.span.hi()); - check_semicolon_outside_block_if_singleline(cx, block, remove_span, insert_span, true, "inside"); - span_lint_and_then( cx, SEMICOLON_INSIDE_BLOCK, @@ -163,8 +165,6 @@ fn semicolon_outside_block(cx: &LateContext<'_>, block: &Block<'_>, tail_stmt_ex let semi_span = cx.sess().source_map().stmt_span(semi_span, block.span); let remove_span = semi_span.with_lo(tail_stmt_expr.span.source_callsite().hi()); - check_semicolon_outside_block_if_singleline(cx, block, remove_span, insert_span, false, "outside"); - span_lint_and_then( cx, SEMICOLON_OUTSIDE_BLOCK, @@ -181,39 +181,54 @@ fn semicolon_outside_block(cx: &LateContext<'_>, block: &Block<'_>, tail_stmt_ex ); } -fn check_semicolon_outside_block_if_singleline( +fn semicolon_outside_block_if_singleline_check_inside( cx: &LateContext<'_>, block: &Block<'_>, - remove_span: Span, - insert_span: Span, - inequality: bool, - ty: &str, + tail: &Expr<'_>, + semi_span: Span, ) { - let remove_line = cx - .sess() - .source_map() - .lookup_line(remove_span.lo()) - .expect("failed to get `remove_span`'s line") - .line; - let insert_line = cx - .sess() - .source_map() - .lookup_line(insert_span.lo()) - .expect("failed to get `insert_span`'s line") - .line; + let insert_span = tail.span.source_callsite().shrink_to_hi(); + let remove_span = semi_span.with_lo(block.span.hi()); + + let (remove_line, insert_line) = get_line(cx, remove_span, insert_span); + + if insert_line != remove_line { + span_lint_and_then( + cx, + SEMICOLON_OUTSIDE_BLOCK_IF_SINGLELINE, + block.span, + &format!("consider moving the `;` inside the block for consistent formatting"), + |diag| { + multispan_sugg_with_applicability( + diag, + "put the `;` here", + Applicability::MachineApplicable, + [(remove_span, String::new()), (insert_span, ";".to_owned())], + ); + }, + ); + } +} - let eq = if inequality { - remove_line != insert_line - } else { - remove_line == insert_line - }; +fn semicolon_outside_block_if_singleline_check_outside( + cx: &LateContext<'_>, + block: &Block<'_>, + tail_stmt_expr: &Expr<'_>, + semi_span: Span, +) { + let insert_span = block.span.with_lo(block.span.hi()); + // account for macro calls + let semi_span = cx.sess().source_map().stmt_span(semi_span, block.span); + let remove_span = semi_span.with_lo(tail_stmt_expr.span.source_callsite().hi()); + + let (remove_line, insert_line) = get_line(cx, remove_span, insert_span); - if eq { + if remove_line == insert_line { span_lint_and_then( cx, SEMICOLON_OUTSIDE_BLOCK_IF_SINGLELINE, block.span, - &format!("consider moving the `;` {ty} the block for consistent formatting"), + &format!("consider moving the `;` outside the block for consistent formatting"), |diag| { multispan_sugg_with_applicability( diag, @@ -225,3 +240,20 @@ fn check_semicolon_outside_block_if_singleline( ); } } + +fn get_line(cx: &LateContext<'_>, remove_span: Span, insert_span: Span) -> (usize, usize) { + let remove_line = cx + .sess() + .source_map() + .lookup_line(remove_span.lo()) + .expect("failed to get `remove_span`'s line") + .line; + let insert_line = cx + .sess() + .source_map() + .lookup_line(insert_span.lo()) + .expect("failed to get `insert_span`'s line") + .line; + + (remove_line, insert_line) +} From a57445d4d6c14adfd2103796a577805a04bb4db5 Mon Sep 17 00:00:00 2001 From: Centri3 <114838443+Centri3@users.noreply.github.com> Date: Sun, 16 Apr 2023 23:59:31 -0500 Subject: [PATCH 12/86] make cargo test pass, again --- clippy_lints/src/semicolon_block.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/clippy_lints/src/semicolon_block.rs b/clippy_lints/src/semicolon_block.rs index d85d3b5830585..c9689454c63b0 100644 --- a/clippy_lints/src/semicolon_block.rs +++ b/clippy_lints/src/semicolon_block.rs @@ -72,7 +72,7 @@ declare_clippy_lint! { /// /// ### Why is this bad? /// - /// Some may prefer if the semicolon is outside if a block is only one + /// Some may prefer if the semicolon is outside if a block is only one /// expression, as this allows rustfmt to make it singleline. In the case that /// it isn't, it should be inside. /// Take a look at both `semicolon_inside_block` and `semicolon_outside_block` for alternatives. @@ -125,14 +125,14 @@ impl LateLintPass<'_> for SemicolonBlock { .. } = stmt else { return }; semicolon_outside_block(cx, block, expr, span); - semicolon_outside_block_if_singleline_check_outside(cx, block, expr, stmt.span) + semicolon_outside_block_if_singleline_check_outside(cx, block, expr, stmt.span); }, StmtKind::Semi(Expr { kind: ExprKind::Block(block @ Block { expr: Some(tail), .. }, _), .. }) if !block.span.from_expansion() => { semicolon_inside_block(cx, block, tail, stmt.span); - semicolon_outside_block_if_singleline_check_inside(cx, block, tail, stmt.span) + semicolon_outside_block_if_singleline_check_inside(cx, block, tail, stmt.span); }, _ => (), } @@ -197,7 +197,7 @@ fn semicolon_outside_block_if_singleline_check_inside( cx, SEMICOLON_OUTSIDE_BLOCK_IF_SINGLELINE, block.span, - &format!("consider moving the `;` inside the block for consistent formatting"), + "consider moving the `;` inside the block for consistent formatting", |diag| { multispan_sugg_with_applicability( diag, @@ -228,7 +228,7 @@ fn semicolon_outside_block_if_singleline_check_outside( cx, SEMICOLON_OUTSIDE_BLOCK_IF_SINGLELINE, block.span, - &format!("consider moving the `;` outside the block for consistent formatting"), + "consider moving the `;` outside the block for consistent formatting", |diag| { multispan_sugg_with_applicability( diag, From 80707aa95faae4acf8b35abf0daf4626afdb446e Mon Sep 17 00:00:00 2001 From: Centri3 <114838443+Centri3@users.noreply.github.com> Date: Mon, 17 Apr 2023 00:37:43 -0500 Subject: [PATCH 13/86] improve description a bit --- clippy_lints/src/semicolon_block.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/semicolon_block.rs b/clippy_lints/src/semicolon_block.rs index c9689454c63b0..8cdfbd5c495a9 100644 --- a/clippy_lints/src/semicolon_block.rs +++ b/clippy_lints/src/semicolon_block.rs @@ -72,10 +72,11 @@ declare_clippy_lint! { /// /// ### Why is this bad? /// - /// Some may prefer if the semicolon is outside if a block is only one - /// expression, as this allows rustfmt to make it singleline. In the case that - /// it isn't, it should be inside. - /// Take a look at both `semicolon_inside_block` and `semicolon_outside_block` for alternatives. + /// Some may prefer if the semicolon is outside of a block if it is only one + /// expression, as this allows rustfmt to make it singleline (and may just be + /// more readable). In the case that it isn't, it should be inside. + /// Take a look at both `semicolon_inside_block` and `semicolon_outside_block` + /// for alternatives. /// /// ### Example /// From 89f0aaaec60f5e67604fd2f98b1e43500c1a0578 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Mon, 17 Apr 2023 13:45:11 +0200 Subject: [PATCH 14/86] Force -Zflatten-format-args=no in Clippy. --- src/driver.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/driver.rs b/src/driver.rs index 718bc41fb9924..205905d509135 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -160,6 +160,9 @@ impl rustc_driver::Callbacks for ClippyCallbacks { // MIR passes can be enabled / disabled separately, we should figure out, what passes to // use for Clippy. config.opts.unstable_opts.mir_opt_level = Some(0); + + // Disable flattening and inlining of format_args!(), so the HIR matches with the AST. + config.opts.unstable_opts.flatten_format_args = false; } } From fa1efa8b104c71721d8317ae59819f6abf2d0ac8 Mon Sep 17 00:00:00 2001 From: Centri3 <114838443+Centri3@users.noreply.github.com> Date: Mon, 17 Apr 2023 20:57:56 -0500 Subject: [PATCH 15/86] refactor --- clippy_lints/src/semicolon_block.rs | 77 +++++++++-------------------- 1 file changed, 22 insertions(+), 55 deletions(-) diff --git a/clippy_lints/src/semicolon_block.rs b/clippy_lints/src/semicolon_block.rs index 8cdfbd5c495a9..7113f0c55d4d3 100644 --- a/clippy_lints/src/semicolon_block.rs +++ b/clippy_lints/src/semicolon_block.rs @@ -126,14 +126,12 @@ impl LateLintPass<'_> for SemicolonBlock { .. } = stmt else { return }; semicolon_outside_block(cx, block, expr, span); - semicolon_outside_block_if_singleline_check_outside(cx, block, expr, stmt.span); }, StmtKind::Semi(Expr { kind: ExprKind::Block(block @ Block { expr: Some(tail), .. }, _), .. }) if !block.span.from_expansion() => { semicolon_inside_block(cx, block, tail, stmt.span); - semicolon_outside_block_if_singleline_check_inside(cx, block, tail, stmt.span); }, _ => (), } @@ -144,6 +142,8 @@ fn semicolon_inside_block(cx: &LateContext<'_>, block: &Block<'_>, tail: &Expr<' let insert_span = tail.span.source_callsite().shrink_to_hi(); let remove_span = semi_span.with_lo(block.span.hi()); + semicolon_outside_block_if_singleline(cx, block, remove_span, insert_span, true, "inside"); + span_lint_and_then( cx, SEMICOLON_INSIDE_BLOCK, @@ -166,6 +166,8 @@ fn semicolon_outside_block(cx: &LateContext<'_>, block: &Block<'_>, tail_stmt_ex let semi_span = cx.sess().source_map().stmt_span(semi_span, block.span); let remove_span = semi_span.with_lo(tail_stmt_expr.span.source_callsite().hi()); + semicolon_outside_block_if_singleline(cx, block, remove_span, insert_span, false, "outside"); + span_lint_and_then( cx, SEMICOLON_OUTSIDE_BLOCK, @@ -182,23 +184,28 @@ fn semicolon_outside_block(cx: &LateContext<'_>, block: &Block<'_>, tail_stmt_ex ); } -fn semicolon_outside_block_if_singleline_check_inside( +fn semicolon_outside_block_if_singleline( cx: &LateContext<'_>, block: &Block<'_>, - tail: &Expr<'_>, - semi_span: Span, + remove_span: Span, + insert_span: Span, + inequality: bool, + ty: &str, ) { - let insert_span = tail.span.source_callsite().shrink_to_hi(); - let remove_span = semi_span.with_lo(block.span.hi()); + let (remove_line, insert_line) = (get_line(cx, remove_span), get_line(cx, insert_span)); - let (remove_line, insert_line) = get_line(cx, remove_span, insert_span); + let eq = if inequality { + remove_line != insert_line + } else { + remove_line == insert_line + }; - if insert_line != remove_line { + if eq { span_lint_and_then( cx, SEMICOLON_OUTSIDE_BLOCK_IF_SINGLELINE, block.span, - "consider moving the `;` inside the block for consistent formatting", + &format!("consider moving the `;` {ty} the block for consistent formatting"), |diag| { multispan_sugg_with_applicability( diag, @@ -211,50 +218,10 @@ fn semicolon_outside_block_if_singleline_check_inside( } } -fn semicolon_outside_block_if_singleline_check_outside( - cx: &LateContext<'_>, - block: &Block<'_>, - tail_stmt_expr: &Expr<'_>, - semi_span: Span, -) { - let insert_span = block.span.with_lo(block.span.hi()); - // account for macro calls - let semi_span = cx.sess().source_map().stmt_span(semi_span, block.span); - let remove_span = semi_span.with_lo(tail_stmt_expr.span.source_callsite().hi()); - - let (remove_line, insert_line) = get_line(cx, remove_span, insert_span); - - if remove_line == insert_line { - span_lint_and_then( - cx, - SEMICOLON_OUTSIDE_BLOCK_IF_SINGLELINE, - block.span, - "consider moving the `;` outside the block for consistent formatting", - |diag| { - multispan_sugg_with_applicability( - diag, - "put the `;` here", - Applicability::MachineApplicable, - [(remove_span, String::new()), (insert_span, ";".to_owned())], - ); - }, - ); - } -} - -fn get_line(cx: &LateContext<'_>, remove_span: Span, insert_span: Span) -> (usize, usize) { - let remove_line = cx - .sess() - .source_map() - .lookup_line(remove_span.lo()) - .expect("failed to get `remove_span`'s line") - .line; - let insert_line = cx - .sess() +fn get_line(cx: &LateContext<'_>, span: Span) -> usize { + cx.sess() .source_map() - .lookup_line(insert_span.lo()) - .expect("failed to get `insert_span`'s line") - .line; - - (remove_line, insert_line) + .lookup_line(span.lo()) + .expect("failed to get span's line") + .line } From 2ebfbc5753529cd50611605f87386c517a4a3f83 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Tue, 18 Apr 2023 17:39:08 +0000 Subject: [PATCH 16/86] Remove very useless `as_substs` usage from clippy --- clippy_utils/src/ty.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index 9449f0b55674d..8b996c188161d 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -975,7 +975,7 @@ pub fn approx_ty_size<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> u64 { } match (cx.layout_of(ty).map(|layout| layout.size.bytes()), ty.kind()) { (Ok(size), _) => size, - (Err(_), ty::Tuple(list)) => list.as_substs().types().map(|t| approx_ty_size(cx, t)).sum(), + (Err(_), ty::Tuple(list)) => list.iter().map(|t| approx_ty_size(cx, t)).sum(), (Err(_), ty::Array(t, n)) => { n.try_eval_target_usize(cx.tcx, cx.param_env).unwrap_or_default() * approx_ty_size(cx, *t) }, From 1dfc231b10baa850b072a6c5f3d845f2e0a19d07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Tue, 18 Apr 2023 18:15:06 +0200 Subject: [PATCH 17/86] clippy: add test for https://github.com/rust-lang/rust-clippy/issues/10645 --- tests/ui/crashes/ice-5207.rs | 5 ++++- tests/ui/crashes/ice-5207.stderr | 16 ++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 tests/ui/crashes/ice-5207.stderr diff --git a/tests/ui/crashes/ice-5207.rs b/tests/ui/crashes/ice-5207.rs index f463f78a99ab7..893c15f5d731c 100644 --- a/tests/ui/crashes/ice-5207.rs +++ b/tests/ui/crashes/ice-5207.rs @@ -1,5 +1,8 @@ -// Regression test for https://github.com/rust-lang/rust-clippy/issues/5207 +// compile-flags: --cap-lints=warn +// ^ for https://github.com/rust-lang/rust-clippy/issues/10645 +// Regression test for https://github.com/rust-lang/rust-clippy/issues/5207 +#![warn(clippy::future_not_send)] pub async fn bar<'a, T: 'a>(_: T) {} fn main() {} diff --git a/tests/ui/crashes/ice-5207.stderr b/tests/ui/crashes/ice-5207.stderr new file mode 100644 index 0000000000000..367e9a08b7563 --- /dev/null +++ b/tests/ui/crashes/ice-5207.stderr @@ -0,0 +1,16 @@ +warning: future cannot be sent between threads safely + --> $DIR/ice-5207.rs:6:35 + | +LL | pub async fn bar<'a, T: 'a>(_: T) {} + | ^ future returned by `bar` is not `Send` + | +note: captured value is not `Send` + --> $DIR/ice-5207.rs:6:29 + | +LL | pub async fn bar<'a, T: 'a>(_: T) {} + | ^ has type `T` which is not `Send` + = note: `T` doesn't implement `std::marker::Send` + = note: `-D clippy::future-not-send` implied by `-D warnings` + +warning: 1 warning emitted + From 2745c878423dd120b5e17ec6260db455f81a6b71 Mon Sep 17 00:00:00 2001 From: Lukas Lueg Date: Wed, 19 Apr 2023 20:04:17 +0200 Subject: [PATCH 18/86] Dont suggest suboptimal_flops unavailable in nostd Fixes #10634 --- clippy_lints/src/floating_point_arithmetic.rs | 13 ++++++-- tests/ui/floating_point_arithmetic_nostd.rs | 31 +++++++++++++++++++ 2 files changed, 41 insertions(+), 3 deletions(-) create mode 100644 tests/ui/floating_point_arithmetic_nostd.rs diff --git a/clippy_lints/src/floating_point_arithmetic.rs b/clippy_lints/src/floating_point_arithmetic.rs index f95b628e6c31e..b50e47e5a1c4e 100644 --- a/clippy_lints/src/floating_point_arithmetic.rs +++ b/clippy_lints/src/floating_point_arithmetic.rs @@ -2,9 +2,10 @@ use clippy_utils::consts::{ constant, constant_simple, Constant, Constant::{Int, F32, F64}, }; -use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::higher; -use clippy_utils::{eq_expr_value, get_parent_expr, in_constant, numeric_literal, peel_blocks, sugg}; +use clippy_utils::{ + diagnostics::span_lint_and_sugg, eq_expr_value, get_parent_expr, higher, in_constant, is_no_std_crate, + numeric_literal, peel_blocks, sugg, +}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, PathSegment, UnOp}; @@ -452,6 +453,9 @@ fn is_float_mul_expr<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<(&' // TODO: Fix rust-lang/rust-clippy#4735 fn check_mul_add(cx: &LateContext<'_>, expr: &Expr<'_>) { + if is_no_std_crate(cx) { + return; // The suggested methods are not available in core + } if let ExprKind::Binary( Spanned { node: op @ (BinOpKind::Add | BinOpKind::Sub), @@ -566,6 +570,9 @@ fn are_negated<'a>(cx: &LateContext<'_>, expr1: &'a Expr<'a>, expr2: &'a Expr<'a } fn check_custom_abs(cx: &LateContext<'_>, expr: &Expr<'_>) { + if is_no_std_crate(cx) { + return; // The suggested methods are not available in core + } if_chain! { if let Some(higher::If { cond, then, r#else: Some(r#else) }) = higher::If::hir(expr); let if_body_expr = peel_blocks(then); diff --git a/tests/ui/floating_point_arithmetic_nostd.rs b/tests/ui/floating_point_arithmetic_nostd.rs new file mode 100644 index 0000000000000..a42c6383ccea2 --- /dev/null +++ b/tests/ui/floating_point_arithmetic_nostd.rs @@ -0,0 +1,31 @@ +#![feature(lang_items, start)] +#![warn(clippy::imprecise_flops)] +#![warn(clippy::suboptimal_flops)] +#![no_std] + +// The following should not lint, as the suggested methods {f32,f64}.mul_add() +// and {f32,f64}::abs() are not available in no_std + +pub fn mul_add() { + let a: f64 = 1234.567; + let b: f64 = 45.67834; + let c: f64 = 0.0004; + let _ = a * b + c; +} + +fn fake_abs1(num: f64) -> f64 { + if num >= 0.0 { num } else { -num } +} + +#[start] +fn main(_argc: isize, _argv: *const *const u8) -> isize { + 0 +} + +#[panic_handler] +fn panic(_info: &core::panic::PanicInfo) -> ! { + loop {} +} + +#[lang = "eh_personality"] +extern "C" fn eh_personality() {} From a3aeec4f75dd0049f6632e26df5aa174b55e730f Mon Sep 17 00:00:00 2001 From: Centri3 <114838443+Centri3@users.noreply.github.com> Date: Wed, 19 Apr 2023 21:46:13 -0500 Subject: [PATCH 19/86] config instead of new lint and don't panic --- CHANGELOG.md | 1 - clippy_lints/src/declared_lints.rs | 1 - clippy_lints/src/lib.rs | 9 +- clippy_lints/src/semicolon_block.rs | 127 ++++++------------ clippy_lints/src/utils/conf.rs | 8 ++ .../semicolon_block/both.fixed} | 3 +- tests/ui-toml/semicolon_block/both.rs | 86 ++++++++++++ .../semicolon_block/both.stderr} | 13 +- tests/ui-toml/semicolon_block/clippy.toml | 2 + .../semicolon_inside_block.fixed | 85 ++++++++++++ .../semicolon_inside_block.rs} | 2 +- .../semicolon_inside_block.stderr | 18 +++ .../semicolon_outside_block.fixed | 85 ++++++++++++ .../semicolon_outside_block.rs | 85 ++++++++++++ .../semicolon_outside_block.stderr | 39 ++++++ .../toml_unknown_key/conf_unknown_key.stderr | 2 + 16 files changed, 468 insertions(+), 98 deletions(-) rename tests/{ui/semicolon_outside_block_if_singleline.fixed => ui-toml/semicolon_block/both.fixed} (93%) create mode 100644 tests/ui-toml/semicolon_block/both.rs rename tests/{ui/semicolon_outside_block_if_singleline.stderr => ui-toml/semicolon_block/both.stderr} (75%) create mode 100644 tests/ui-toml/semicolon_block/clippy.toml create mode 100644 tests/ui-toml/semicolon_block/semicolon_inside_block.fixed rename tests/{ui/semicolon_outside_block_if_singleline.rs => ui-toml/semicolon_block/semicolon_inside_block.rs} (95%) create mode 100644 tests/ui-toml/semicolon_block/semicolon_inside_block.stderr create mode 100644 tests/ui-toml/semicolon_block/semicolon_outside_block.fixed create mode 100644 tests/ui-toml/semicolon_block/semicolon_outside_block.rs create mode 100644 tests/ui-toml/semicolon_block/semicolon_outside_block.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index a0a7780f4c278..559b560dde4ba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4884,7 +4884,6 @@ Released 2018-09-13 [`semicolon_if_nothing_returned`]: https://rust-lang.github.io/rust-clippy/master/index.html#semicolon_if_nothing_returned [`semicolon_inside_block`]: https://rust-lang.github.io/rust-clippy/master/index.html#semicolon_inside_block [`semicolon_outside_block`]: https://rust-lang.github.io/rust-clippy/master/index.html#semicolon_outside_block -[`semicolon_outside_block_if_singleline`]: https://rust-lang.github.io/rust-clippy/master/index.html#semicolon_outside_block_if_singleline [`separated_literal_suffix`]: https://rust-lang.github.io/rust-clippy/master/index.html#separated_literal_suffix [`serde_api_misuse`]: https://rust-lang.github.io/rust-clippy/master/index.html#serde_api_misuse [`shadow_reuse`]: https://rust-lang.github.io/rust-clippy/master/index.html#shadow_reuse diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 70379b6caf114..f24dab6278095 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -546,7 +546,6 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::self_named_constructors::SELF_NAMED_CONSTRUCTORS_INFO, crate::semicolon_block::SEMICOLON_INSIDE_BLOCK_INFO, crate::semicolon_block::SEMICOLON_OUTSIDE_BLOCK_INFO, - crate::semicolon_block::SEMICOLON_OUTSIDE_BLOCK_IF_SINGLELINE_INFO, crate::semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED_INFO, crate::serde_api::SERDE_API_MISUSE_INFO, crate::shadow::SHADOW_REUSE_INFO, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index b0ec14855e71b..cb223ce9d16af 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -932,7 +932,14 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|_| Box::new(from_raw_with_void_ptr::FromRawWithVoidPtr)); store.register_late_pass(|_| Box::new(suspicious_xor_used_as_pow::ConfusingXorAndPow)); store.register_late_pass(move |_| Box::new(manual_is_ascii_check::ManualIsAsciiCheck::new(msrv()))); - store.register_late_pass(|_| Box::new(semicolon_block::SemicolonBlock)); + let semicolon_inside_block_if_multiline = conf.semicolon_inside_block_if_multiline; + let semicolon_outside_block_if_singleline = conf.semicolon_outside_block_if_singleline; + store.register_late_pass(move |_| { + Box::new(semicolon_block::SemicolonBlock::new( + semicolon_inside_block_if_multiline, + semicolon_outside_block_if_singleline, + )) + }); store.register_late_pass(|_| Box::new(fn_null_check::FnNullCheck)); store.register_late_pass(|_| Box::new(permissions_set_readonly_false::PermissionsSetReadonlyFalse)); store.register_late_pass(|_| Box::new(size_of_ref::SizeOfRef)); diff --git a/clippy_lints/src/semicolon_block.rs b/clippy_lints/src/semicolon_block.rs index 7113f0c55d4d3..6be4303371220 100644 --- a/clippy_lints/src/semicolon_block.rs +++ b/clippy_lints/src/semicolon_block.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::{multispan_sugg_with_applicability, span_lint_and use rustc_errors::Applicability; use rustc_hir::{Block, Expr, ExprKind, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::Span; declare_clippy_lint! { @@ -64,49 +64,22 @@ declare_clippy_lint! { restriction, "add a semicolon outside the block" } -declare_clippy_lint! { - /// ### What it does - /// - /// Suggests moving the semicolon from a block's final expression outside of - /// the block if it's singleline, and inside the block if it's multiline. - /// - /// ### Why is this bad? - /// - /// Some may prefer if the semicolon is outside of a block if it is only one - /// expression, as this allows rustfmt to make it singleline (and may just be - /// more readable). In the case that it isn't, it should be inside. - /// Take a look at both `semicolon_inside_block` and `semicolon_outside_block` - /// for alternatives. - /// - /// ### Example - /// - /// ```rust - /// # fn f(_: u32) {} - /// # let x = 0; - /// unsafe { f(x); } - /// - /// unsafe { - /// let x = 1; - /// f(x) - /// }; - /// ``` - /// Use instead: - /// ```rust - /// # fn f(_: u32) {} - /// # let x = 0; - /// unsafe { f(x) }; - /// - /// unsafe { - /// let x = 1; - /// f(x); - /// } - /// ``` - #[clippy::version = "1.68.0"] - pub SEMICOLON_OUTSIDE_BLOCK_IF_SINGLELINE, - restriction, - "add a semicolon inside the block if it's singleline, otherwise outside" +impl_lint_pass!(SemicolonBlock => [SEMICOLON_INSIDE_BLOCK, SEMICOLON_OUTSIDE_BLOCK]); + +#[derive(Copy, Clone)] +pub struct SemicolonBlock { + semicolon_inside_block_if_multiline: bool, + semicolon_outside_block_if_singleline: bool, +} + +impl SemicolonBlock { + pub fn new(semicolon_inside_block_if_multiline: bool, semicolon_outside_block_if_singleline: bool) -> Self { + Self { + semicolon_inside_block_if_multiline, + semicolon_outside_block_if_singleline, + } + } } -declare_lint_pass!(SemicolonBlock => [SEMICOLON_INSIDE_BLOCK, SEMICOLON_OUTSIDE_BLOCK, SEMICOLON_OUTSIDE_BLOCK_IF_SINGLELINE]); impl LateLintPass<'_> for SemicolonBlock { fn check_stmt(&mut self, cx: &LateContext<'_>, stmt: &Stmt<'_>) { @@ -125,24 +98,34 @@ impl LateLintPass<'_> for SemicolonBlock { span, .. } = stmt else { return }; - semicolon_outside_block(cx, block, expr, span); + semicolon_outside_block(self, cx, block, expr, span); }, StmtKind::Semi(Expr { kind: ExprKind::Block(block @ Block { expr: Some(tail), .. }, _), .. }) if !block.span.from_expansion() => { - semicolon_inside_block(cx, block, tail, stmt.span); + semicolon_inside_block(self, cx, block, tail, stmt.span); }, _ => (), } } } -fn semicolon_inside_block(cx: &LateContext<'_>, block: &Block<'_>, tail: &Expr<'_>, semi_span: Span) { +fn semicolon_inside_block( + conf: &mut SemicolonBlock, + cx: &LateContext<'_>, + block: &Block<'_>, + tail: &Expr<'_>, + semi_span: Span, +) { let insert_span = tail.span.source_callsite().shrink_to_hi(); let remove_span = semi_span.with_lo(block.span.hi()); - semicolon_outside_block_if_singleline(cx, block, remove_span, insert_span, true, "inside"); + if conf.semicolon_inside_block_if_multiline { + if get_line(cx, remove_span) == get_line(cx, insert_span) { + return; + } + } span_lint_and_then( cx, @@ -160,13 +143,17 @@ fn semicolon_inside_block(cx: &LateContext<'_>, block: &Block<'_>, tail: &Expr<' ); } -fn semicolon_outside_block(cx: &LateContext<'_>, block: &Block<'_>, tail_stmt_expr: &Expr<'_>, semi_span: Span) { +fn semicolon_outside_block(conf: &mut SemicolonBlock, cx: &LateContext<'_>, block: &Block<'_>, tail_stmt_expr: &Expr<'_>, semi_span: Span) { let insert_span = block.span.with_lo(block.span.hi()); // account for macro calls let semi_span = cx.sess().source_map().stmt_span(semi_span, block.span); let remove_span = semi_span.with_lo(tail_stmt_expr.span.source_callsite().hi()); - semicolon_outside_block_if_singleline(cx, block, remove_span, insert_span, false, "outside"); + if conf.semicolon_outside_block_if_singleline { + if get_line(cx, remove_span) != get_line(cx, insert_span) { + return; + } + } span_lint_and_then( cx, @@ -184,44 +171,10 @@ fn semicolon_outside_block(cx: &LateContext<'_>, block: &Block<'_>, tail_stmt_ex ); } -fn semicolon_outside_block_if_singleline( - cx: &LateContext<'_>, - block: &Block<'_>, - remove_span: Span, - insert_span: Span, - inequality: bool, - ty: &str, -) { - let (remove_line, insert_line) = (get_line(cx, remove_span), get_line(cx, insert_span)); - - let eq = if inequality { - remove_line != insert_line - } else { - remove_line == insert_line - }; - - if eq { - span_lint_and_then( - cx, - SEMICOLON_OUTSIDE_BLOCK_IF_SINGLELINE, - block.span, - &format!("consider moving the `;` {ty} the block for consistent formatting"), - |diag| { - multispan_sugg_with_applicability( - diag, - "put the `;` here", - Applicability::MachineApplicable, - [(remove_span, String::new()), (insert_span, ";".to_owned())], - ); - }, - ); +fn get_line(cx: &LateContext<'_>, span: Span) -> Option { + if let Ok(line) = cx.sess().source_map().lookup_line(span.lo()) { + return Some(line.line); } -} -fn get_line(cx: &LateContext<'_>, span: Span) -> usize { - cx.sess() - .source_map() - .lookup_line(span.lo()) - .expect("failed to get span's line") - .line + None } diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index 896a01af37d99..26123549b94c6 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -463,6 +463,14 @@ define_Conf! { /// /// The maximum byte size a `Future` can have, before it triggers the `clippy::large_futures` lint (future_size_threshold: u64 = 16 * 1024), + /// Lint: SEMICOLON_INSIDE_BLOCK. + /// + /// Whether to lint only if it's multiline. + (semicolon_inside_block_if_multiline: bool = false), + /// Lint: SEMICOLON_OUTSIDE_BLOCK. + /// + /// Whether to lint only if it's singleline. + (semicolon_outside_block_if_singleline: bool = false), } /// Search for the configuration file. diff --git a/tests/ui/semicolon_outside_block_if_singleline.fixed b/tests/ui-toml/semicolon_block/both.fixed similarity index 93% rename from tests/ui/semicolon_outside_block_if_singleline.fixed rename to tests/ui-toml/semicolon_block/both.fixed index e1ecbf8588d95..981b661bc7862 100644 --- a/tests/ui/semicolon_outside_block_if_singleline.fixed +++ b/tests/ui-toml/semicolon_block/both.fixed @@ -6,7 +6,8 @@ clippy::no_effect, clippy::single_element_loop )] -#![warn(clippy::semicolon_outside_block_if_singleline)] +#![warn(clippy::semicolon_inside_block)] +#![warn(clippy::semicolon_outside_block)] macro_rules! m { (()) => { diff --git a/tests/ui-toml/semicolon_block/both.rs b/tests/ui-toml/semicolon_block/both.rs new file mode 100644 index 0000000000000..d4dcd6e7240e7 --- /dev/null +++ b/tests/ui-toml/semicolon_block/both.rs @@ -0,0 +1,86 @@ +// run-rustfix +#![allow( + unused, + clippy::unused_unit, + clippy::unnecessary_operation, + clippy::no_effect, + clippy::single_element_loop +)] +#![warn(clippy::semicolon_inside_block)] +#![warn(clippy::semicolon_outside_block)] + +macro_rules! m { + (()) => { + () + }; + (0) => {{ + 0 + };}; + (1) => {{ + 1; + }}; + (2) => {{ + 2; + }}; +} + +fn unit_fn_block() { + () +} + +#[rustfmt::skip] +fn main() { + { unit_fn_block() } + unsafe { unit_fn_block() } + + { + unit_fn_block() + } + + { unit_fn_block() }; + unsafe { unit_fn_block() }; + + { unit_fn_block(); } + unsafe { unit_fn_block(); } + + { unit_fn_block(); }; + unsafe { unit_fn_block(); }; + + { + unit_fn_block(); + unit_fn_block() + }; + { + unit_fn_block(); + unit_fn_block(); + } + { + unit_fn_block(); + unit_fn_block(); + }; + + { m!(()) }; + { m!(()); } + { m!(()); }; + m!(0); + m!(1); + m!(2); + + for _ in [()] { + unit_fn_block(); + } + for _ in [()] { + unit_fn_block() + } + + let _d = || { + unit_fn_block(); + }; + let _d = || { + unit_fn_block() + }; + + { unit_fn_block(); }; + + unit_fn_block() +} diff --git a/tests/ui/semicolon_outside_block_if_singleline.stderr b/tests/ui-toml/semicolon_block/both.stderr similarity index 75% rename from tests/ui/semicolon_outside_block_if_singleline.stderr rename to tests/ui-toml/semicolon_block/both.stderr index dda083f2be3e0..2f58842eab01b 100644 --- a/tests/ui/semicolon_outside_block_if_singleline.stderr +++ b/tests/ui-toml/semicolon_block/both.stderr @@ -1,10 +1,10 @@ error: consider moving the `;` outside the block for consistent formatting - --> $DIR/semicolon_outside_block_if_singleline.rs:42:5 + --> $DIR/both.rs:43:5 | LL | { unit_fn_block(); } | ^^^^^^^^^^^^^^^^^^^^ | - = note: `-D clippy::semicolon-outside-block-if-singleline` implied by `-D warnings` + = note: `-D clippy::semicolon-outside-block` implied by `-D warnings` help: put the `;` here | LL - { unit_fn_block(); } @@ -12,7 +12,7 @@ LL + { unit_fn_block() }; | error: consider moving the `;` outside the block for consistent formatting - --> $DIR/semicolon_outside_block_if_singleline.rs:43:5 + --> $DIR/both.rs:44:5 | LL | unsafe { unit_fn_block(); } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -24,14 +24,15 @@ LL + unsafe { unit_fn_block() }; | error: consider moving the `;` inside the block for consistent formatting - --> $DIR/semicolon_outside_block_if_singleline.rs:48:5 + --> $DIR/both.rs:49:5 | LL | / { LL | | unit_fn_block(); LL | | unit_fn_block() LL | | }; - | |_____^ + | |______^ | + = note: `-D clippy::semicolon-inside-block` implied by `-D warnings` help: put the `;` here | LL ~ unit_fn_block(); @@ -39,7 +40,7 @@ LL ~ } | error: consider moving the `;` outside the block for consistent formatting - --> $DIR/semicolon_outside_block_if_singleline.rs:62:5 + --> $DIR/both.rs:63:5 | LL | { m!(()); } | ^^^^^^^^^^^ diff --git a/tests/ui-toml/semicolon_block/clippy.toml b/tests/ui-toml/semicolon_block/clippy.toml new file mode 100644 index 0000000000000..cc3bc8cae14be --- /dev/null +++ b/tests/ui-toml/semicolon_block/clippy.toml @@ -0,0 +1,2 @@ +semicolon-inside-block-if-multiline = true +semicolon-outside-block-if-singleline = true diff --git a/tests/ui-toml/semicolon_block/semicolon_inside_block.fixed b/tests/ui-toml/semicolon_block/semicolon_inside_block.fixed new file mode 100644 index 0000000000000..6a08bc905b112 --- /dev/null +++ b/tests/ui-toml/semicolon_block/semicolon_inside_block.fixed @@ -0,0 +1,85 @@ +// run-rustfix +#![allow( + unused, + clippy::unused_unit, + clippy::unnecessary_operation, + clippy::no_effect, + clippy::single_element_loop +)] +#![warn(clippy::semicolon_inside_block)] + +macro_rules! m { + (()) => { + () + }; + (0) => {{ + 0 + };}; + (1) => {{ + 1; + }}; + (2) => {{ + 2; + }}; +} + +fn unit_fn_block() { + () +} + +#[rustfmt::skip] +fn main() { + { unit_fn_block() } + unsafe { unit_fn_block() } + + { + unit_fn_block() + } + + { unit_fn_block() }; + unsafe { unit_fn_block() }; + + { unit_fn_block(); } + unsafe { unit_fn_block(); } + + { unit_fn_block(); }; + unsafe { unit_fn_block(); }; + + { + unit_fn_block(); + unit_fn_block(); + } + { + unit_fn_block(); + unit_fn_block(); + } + { + unit_fn_block(); + unit_fn_block(); + }; + + { m!(()) }; + { m!(()); } + { m!(()); }; + m!(0); + m!(1); + m!(2); + + for _ in [()] { + unit_fn_block(); + } + for _ in [()] { + unit_fn_block() + } + + let _d = || { + unit_fn_block(); + }; + let _d = || { + unit_fn_block() + }; + + { unit_fn_block(); }; + + unit_fn_block() +} diff --git a/tests/ui/semicolon_outside_block_if_singleline.rs b/tests/ui-toml/semicolon_block/semicolon_inside_block.rs similarity index 95% rename from tests/ui/semicolon_outside_block_if_singleline.rs rename to tests/ui-toml/semicolon_block/semicolon_inside_block.rs index 80fbb4ce2d5eb..f40848f702e1c 100644 --- a/tests/ui/semicolon_outside_block_if_singleline.rs +++ b/tests/ui-toml/semicolon_block/semicolon_inside_block.rs @@ -6,7 +6,7 @@ clippy::no_effect, clippy::single_element_loop )] -#![warn(clippy::semicolon_outside_block_if_singleline)] +#![warn(clippy::semicolon_inside_block)] macro_rules! m { (()) => { diff --git a/tests/ui-toml/semicolon_block/semicolon_inside_block.stderr b/tests/ui-toml/semicolon_block/semicolon_inside_block.stderr new file mode 100644 index 0000000000000..2569dc4b4e453 --- /dev/null +++ b/tests/ui-toml/semicolon_block/semicolon_inside_block.stderr @@ -0,0 +1,18 @@ +error: consider moving the `;` inside the block for consistent formatting + --> $DIR/semicolon_inside_block.rs:48:5 + | +LL | / { +LL | | unit_fn_block(); +LL | | unit_fn_block() +LL | | }; + | |______^ + | + = note: `-D clippy::semicolon-inside-block` implied by `-D warnings` +help: put the `;` here + | +LL ~ unit_fn_block(); +LL ~ } + | + +error: aborting due to previous error + diff --git a/tests/ui-toml/semicolon_block/semicolon_outside_block.fixed b/tests/ui-toml/semicolon_block/semicolon_outside_block.fixed new file mode 100644 index 0000000000000..e2d653dc3c35c --- /dev/null +++ b/tests/ui-toml/semicolon_block/semicolon_outside_block.fixed @@ -0,0 +1,85 @@ +// run-rustfix +#![allow( + unused, + clippy::unused_unit, + clippy::unnecessary_operation, + clippy::no_effect, + clippy::single_element_loop +)] +#![warn(clippy::semicolon_outside_block)] + +macro_rules! m { + (()) => { + () + }; + (0) => {{ + 0 + };}; + (1) => {{ + 1; + }}; + (2) => {{ + 2; + }}; +} + +fn unit_fn_block() { + () +} + +#[rustfmt::skip] +fn main() { + { unit_fn_block() } + unsafe { unit_fn_block() } + + { + unit_fn_block() + } + + { unit_fn_block() }; + unsafe { unit_fn_block() }; + + { unit_fn_block() }; + unsafe { unit_fn_block() }; + + { unit_fn_block(); }; + unsafe { unit_fn_block(); }; + + { + unit_fn_block(); + unit_fn_block() + }; + { + unit_fn_block(); + unit_fn_block(); + } + { + unit_fn_block(); + unit_fn_block(); + }; + + { m!(()) }; + { m!(()) }; + { m!(()); }; + m!(0); + m!(1); + m!(2); + + for _ in [()] { + unit_fn_block(); + } + for _ in [()] { + unit_fn_block() + } + + let _d = || { + unit_fn_block(); + }; + let _d = || { + unit_fn_block() + }; + + { unit_fn_block(); }; + + unit_fn_block() +} diff --git a/tests/ui-toml/semicolon_block/semicolon_outside_block.rs b/tests/ui-toml/semicolon_block/semicolon_outside_block.rs new file mode 100644 index 0000000000000..7ce46431fac9a --- /dev/null +++ b/tests/ui-toml/semicolon_block/semicolon_outside_block.rs @@ -0,0 +1,85 @@ +// run-rustfix +#![allow( + unused, + clippy::unused_unit, + clippy::unnecessary_operation, + clippy::no_effect, + clippy::single_element_loop +)] +#![warn(clippy::semicolon_outside_block)] + +macro_rules! m { + (()) => { + () + }; + (0) => {{ + 0 + };}; + (1) => {{ + 1; + }}; + (2) => {{ + 2; + }}; +} + +fn unit_fn_block() { + () +} + +#[rustfmt::skip] +fn main() { + { unit_fn_block() } + unsafe { unit_fn_block() } + + { + unit_fn_block() + } + + { unit_fn_block() }; + unsafe { unit_fn_block() }; + + { unit_fn_block(); } + unsafe { unit_fn_block(); } + + { unit_fn_block(); }; + unsafe { unit_fn_block(); }; + + { + unit_fn_block(); + unit_fn_block() + }; + { + unit_fn_block(); + unit_fn_block(); + } + { + unit_fn_block(); + unit_fn_block(); + }; + + { m!(()) }; + { m!(()); } + { m!(()); }; + m!(0); + m!(1); + m!(2); + + for _ in [()] { + unit_fn_block(); + } + for _ in [()] { + unit_fn_block() + } + + let _d = || { + unit_fn_block(); + }; + let _d = || { + unit_fn_block() + }; + + { unit_fn_block(); }; + + unit_fn_block() +} diff --git a/tests/ui-toml/semicolon_block/semicolon_outside_block.stderr b/tests/ui-toml/semicolon_block/semicolon_outside_block.stderr new file mode 100644 index 0000000000000..6dd3577dd09f0 --- /dev/null +++ b/tests/ui-toml/semicolon_block/semicolon_outside_block.stderr @@ -0,0 +1,39 @@ +error: consider moving the `;` outside the block for consistent formatting + --> $DIR/semicolon_outside_block.rs:42:5 + | +LL | { unit_fn_block(); } + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::semicolon-outside-block` implied by `-D warnings` +help: put the `;` here + | +LL - { unit_fn_block(); } +LL + { unit_fn_block() }; + | + +error: consider moving the `;` outside the block for consistent formatting + --> $DIR/semicolon_outside_block.rs:43:5 + | +LL | unsafe { unit_fn_block(); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: put the `;` here + | +LL - unsafe { unit_fn_block(); } +LL + unsafe { unit_fn_block() }; + | + +error: consider moving the `;` outside the block for consistent formatting + --> $DIR/semicolon_outside_block.rs:62:5 + | +LL | { m!(()); } + | ^^^^^^^^^^^ + | +help: put the `;` here + | +LL - { m!(()); } +LL + { m!(()) }; + | + +error: aborting due to 3 previous errors + diff --git a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr index 8447c31722dd0..c49c9087946da 100644 --- a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr +++ b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr @@ -37,6 +37,8 @@ error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown fie missing-docs-in-crate-items msrv pass-by-value-size-limit + semicolon-inside-block-if-multiline + semicolon-outside-block-if-singleline single-char-binding-names-threshold standard-macro-braces suppress-restriction-lint-in-const From 41f6d88be588b191d7c49547819671c11c9a84e9 Mon Sep 17 00:00:00 2001 From: Centri3 <114838443+Centri3@users.noreply.github.com> Date: Wed, 19 Apr 2023 21:51:58 -0500 Subject: [PATCH 20/86] make cargo test pass --- clippy_lints/src/semicolon_block.rs | 20 +++++++++++--------- clippy_lints/src/utils/conf.rs | 16 ++++++++-------- 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/clippy_lints/src/semicolon_block.rs b/clippy_lints/src/semicolon_block.rs index 6be4303371220..c1c0325b786b7 100644 --- a/clippy_lints/src/semicolon_block.rs +++ b/clippy_lints/src/semicolon_block.rs @@ -121,10 +121,8 @@ fn semicolon_inside_block( let insert_span = tail.span.source_callsite().shrink_to_hi(); let remove_span = semi_span.with_lo(block.span.hi()); - if conf.semicolon_inside_block_if_multiline { - if get_line(cx, remove_span) == get_line(cx, insert_span) { - return; - } + if conf.semicolon_inside_block_if_multiline && get_line(cx, remove_span) == get_line(cx, insert_span) { + return; } span_lint_and_then( @@ -143,16 +141,20 @@ fn semicolon_inside_block( ); } -fn semicolon_outside_block(conf: &mut SemicolonBlock, cx: &LateContext<'_>, block: &Block<'_>, tail_stmt_expr: &Expr<'_>, semi_span: Span) { +fn semicolon_outside_block( + conf: &mut SemicolonBlock, + cx: &LateContext<'_>, + block: &Block<'_>, + tail_stmt_expr: &Expr<'_>, + semi_span: Span, +) { let insert_span = block.span.with_lo(block.span.hi()); // account for macro calls let semi_span = cx.sess().source_map().stmt_span(semi_span, block.span); let remove_span = semi_span.with_lo(tail_stmt_expr.span.source_callsite().hi()); - if conf.semicolon_outside_block_if_singleline { - if get_line(cx, remove_span) != get_line(cx, insert_span) { - return; - } + if conf.semicolon_outside_block_if_singleline && get_line(cx, remove_span) != get_line(cx, insert_span) { + return; } span_lint_and_then( diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index 26123549b94c6..939f6cd5f1fcf 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -277,6 +277,14 @@ define_Conf! { /// `".."` can be used as part of the list to indicate, that the configured values should be appended to the /// default configuration of Clippy. By default, any configuration will replace the default value. (disallowed_names: Vec = super::DEFAULT_DISALLOWED_NAMES.iter().map(ToString::to_string).collect()), + /// Lint: SEMICOLON_INSIDE_BLOCK. + /// + /// Whether to lint only if it's multiline. + (semicolon_inside_block_if_multiline: bool = false), + /// Lint: SEMICOLON_OUTSIDE_BLOCK. + /// + /// Whether to lint only if it's singleline. + (semicolon_outside_block_if_singleline: bool = false), /// Lint: DOC_MARKDOWN. /// /// The list of words this lint should not consider as identifiers needing ticks. The value @@ -463,14 +471,6 @@ define_Conf! { /// /// The maximum byte size a `Future` can have, before it triggers the `clippy::large_futures` lint (future_size_threshold: u64 = 16 * 1024), - /// Lint: SEMICOLON_INSIDE_BLOCK. - /// - /// Whether to lint only if it's multiline. - (semicolon_inside_block_if_multiline: bool = false), - /// Lint: SEMICOLON_OUTSIDE_BLOCK. - /// - /// Whether to lint only if it's singleline. - (semicolon_outside_block_if_singleline: bool = false), } /// Search for the configuration file. From 8ead58c67bb4cc0c23e5f3c9d335a2b6e90d1854 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 8 May 2022 15:53:19 +0200 Subject: [PATCH 21/86] Remove WithOptconstParam. --- clippy_lints/src/non_copy_const.rs | 8 +++----- clippy_utils/src/consts.rs | 6 +----- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/clippy_lints/src/non_copy_const.rs b/clippy_lints/src/non_copy_const.rs index 0bedab05eec61..eed0f1f19918b 100644 --- a/clippy_lints/src/non_copy_const.rs +++ b/clippy_lints/src/non_copy_const.rs @@ -196,11 +196,9 @@ fn is_value_unfrozen_poly<'tcx>(cx: &LateContext<'tcx>, body_id: BodyId, ty: Ty< fn is_value_unfrozen_expr<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId, def_id: DefId, ty: Ty<'tcx>) -> bool { let substs = cx.typeck_results().node_substs(hir_id); - let result = cx.tcx.const_eval_resolve( - cx.param_env, - mir::UnevaluatedConst::new(ty::WithOptConstParam::unknown(def_id), substs), - None, - ); + let result = cx + .tcx + .const_eval_resolve(cx.param_env, mir::UnevaluatedConst::new(def_id, substs), None); is_value_unfrozen_raw(cx, result, ty) } diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs index bb8890dcaf988..99bfc4b5717c8 100644 --- a/clippy_utils/src/consts.rs +++ b/clippy_utils/src/consts.rs @@ -450,11 +450,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { let result = self .lcx .tcx - .const_eval_resolve( - self.param_env, - mir::UnevaluatedConst::new(ty::WithOptConstParam::unknown(def_id), substs), - None, - ) + .const_eval_resolve(self.param_env, mir::UnevaluatedConst::new(def_id, substs), None) .ok() .map(|val| rustc_middle::mir::ConstantKind::from_value(val, ty))?; let result = miri_to_const(self.lcx.tcx, result); From afa28e63044649230671635e78b649e8cdfe3b3a Mon Sep 17 00:00:00 2001 From: Kyle Matsuda Date: Mon, 17 Apr 2023 15:57:29 -0600 Subject: [PATCH 22/86] change usages of explicit_item_bounds to bound_explicit_item_bounds --- clippy_lints/src/future_not_send.rs | 7 +++---- clippy_utils/src/ty.rs | 5 +++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/clippy_lints/src/future_not_send.rs b/clippy_lints/src/future_not_send.rs index ed0bd58c770c7..73ae2406f9dbc 100644 --- a/clippy_lints/src/future_not_send.rs +++ b/clippy_lints/src/future_not_send.rs @@ -4,7 +4,7 @@ use rustc_hir::intravisit::FnKind; use rustc_hir::{Body, FnDecl}; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty::{self, AliasTy, Clause, EarlyBinder, PredicateKind}; +use rustc_middle::ty::{self, AliasTy, Clause, PredicateKind}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::def_id::LocalDefId; use rustc_span::{sym, Span}; @@ -64,10 +64,9 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend { } let ret_ty = return_ty(cx, cx.tcx.hir().local_def_id_to_hir_id(fn_def_id).expect_owner()); if let ty::Alias(ty::Opaque, AliasTy { def_id, substs, .. }) = *ret_ty.kind() { - let preds = cx.tcx.explicit_item_bounds(def_id); + let preds = cx.tcx.bound_explicit_item_bounds(def_id); let mut is_future = false; - for &(p, _span) in preds { - let p = EarlyBinder(p).subst(cx.tcx, substs); + for (p, _span) in preds.subst_iter_copied(cx.tcx, substs) { if let Some(trait_pred) = p.to_opt_poly_trait_pred() { if Some(trait_pred.skip_binder().trait_ref.def_id) == cx.tcx.lang_items().future_trait() { is_future = true; diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index 8b996c188161d..058f6b0306dcf 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -90,7 +90,8 @@ pub fn contains_ty_adt_constructor_opaque<'tcx>(cx: &LateContext<'tcx>, ty: Ty<' return false; } - for &(predicate, _span) in cx.tcx.explicit_item_bounds(def_id) { + for bound in cx.tcx.bound_explicit_item_bounds(def_id).transpose_iter() { + let (predicate, _span) = bound.map_bound(|b| *b).subst_identity(); match predicate.kind().skip_binder() { // For `impl Trait`, it will register a predicate of `T: Trait`, so we go through // and check substituions to find `U`. @@ -267,7 +268,7 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { }, ty::Tuple(substs) => substs.iter().any(|ty| is_must_use_ty(cx, ty)), ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) => { - for (predicate, _) in cx.tcx.explicit_item_bounds(*def_id) { + for (predicate, _) in cx.tcx.bound_explicit_item_bounds(*def_id).skip_binder() { if let ty::PredicateKind::Clause(ty::Clause::Trait(trait_predicate)) = predicate.kind().skip_binder() { if cx.tcx.has_attr(trait_predicate.trait_ref.def_id, sym::must_use) { return true; From 097309c10f6bdfa0f8540d063e6e64942fd53204 Mon Sep 17 00:00:00 2001 From: Kyle Matsuda Date: Mon, 17 Apr 2023 16:43:46 -0600 Subject: [PATCH 23/86] add EarlyBinder to output of explicit_item_bounds; replace bound_explicit_item_bounds usages; remove bound_explicit_item_bounds query --- clippy_lints/src/future_not_send.rs | 2 +- clippy_utils/src/ty.rs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/future_not_send.rs b/clippy_lints/src/future_not_send.rs index 73ae2406f9dbc..ff838c2d56e43 100644 --- a/clippy_lints/src/future_not_send.rs +++ b/clippy_lints/src/future_not_send.rs @@ -64,7 +64,7 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend { } let ret_ty = return_ty(cx, cx.tcx.hir().local_def_id_to_hir_id(fn_def_id).expect_owner()); if let ty::Alias(ty::Opaque, AliasTy { def_id, substs, .. }) = *ret_ty.kind() { - let preds = cx.tcx.bound_explicit_item_bounds(def_id); + let preds = cx.tcx.explicit_item_bounds(def_id); let mut is_future = false; for (p, _span) in preds.subst_iter_copied(cx.tcx, substs) { if let Some(trait_pred) = p.to_opt_poly_trait_pred() { diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index 058f6b0306dcf..5f768928adf05 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -90,7 +90,7 @@ pub fn contains_ty_adt_constructor_opaque<'tcx>(cx: &LateContext<'tcx>, ty: Ty<' return false; } - for bound in cx.tcx.bound_explicit_item_bounds(def_id).transpose_iter() { + for bound in cx.tcx.explicit_item_bounds(def_id).transpose_iter() { let (predicate, _span) = bound.map_bound(|b| *b).subst_identity(); match predicate.kind().skip_binder() { // For `impl Trait`, it will register a predicate of `T: Trait`, so we go through @@ -268,7 +268,7 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { }, ty::Tuple(substs) => substs.iter().any(|ty| is_must_use_ty(cx, ty)), ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) => { - for (predicate, _) in cx.tcx.bound_explicit_item_bounds(*def_id).skip_binder() { + for (predicate, _) in cx.tcx.explicit_item_bounds(def_id).skip_binder() { if let ty::PredicateKind::Clause(ty::Clause::Trait(trait_predicate)) = predicate.kind().skip_binder() { if cx.tcx.has_attr(trait_predicate.trait_ref.def_id, sym::must_use) { return true; @@ -744,7 +744,7 @@ fn sig_for_projection<'tcx>(cx: &LateContext<'tcx>, ty: AliasTy<'tcx>) -> Option for (pred, _) in cx .tcx - .bound_explicit_item_bounds(ty.def_id) + .explicit_item_bounds(ty.def_id) .subst_iter_copied(cx.tcx, ty.substs) { match pred.kind().skip_binder() { From 55d814633423c801034fca46f4f391d0c5fd3899 Mon Sep 17 00:00:00 2001 From: Kyle Matsuda Date: Mon, 17 Apr 2023 17:19:08 -0600 Subject: [PATCH 24/86] add subst_identity_iter and subst_identity_iter_copied methods on EarlyBinder; use this to simplify some EarlyBinder noise around explicit_item_bounds calls --- clippy_utils/src/ty.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index 5f768928adf05..cb700126c2bd5 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -90,8 +90,7 @@ pub fn contains_ty_adt_constructor_opaque<'tcx>(cx: &LateContext<'tcx>, ty: Ty<' return false; } - for bound in cx.tcx.explicit_item_bounds(def_id).transpose_iter() { - let (predicate, _span) = bound.map_bound(|b| *b).subst_identity(); + for (predicate, _span) in cx.tcx.explicit_item_bounds(def_id).subst_identity_iter_copied() { match predicate.kind().skip_binder() { // For `impl Trait`, it will register a predicate of `T: Trait`, so we go through // and check substituions to find `U`. From 654d12ff8930a332a4cdcfccc6c1c34700e2f3b7 Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Thu, 20 Apr 2023 22:43:59 +0200 Subject: [PATCH 25/86] use is_inside_const_context query for in_constant --- clippy_utils/src/lib.rs | 32 ++++------------------------- tests/ui/bool_to_int_with_if.fixed | 9 +++++++- tests/ui/bool_to_int_with_if.rs | 9 +++++++- tests/ui/bool_to_int_with_if.stderr | 2 +- 4 files changed, 21 insertions(+), 31 deletions(-) diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index f1d2ae220f81d..98d6f29765f4d 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -86,10 +86,10 @@ use rustc_hir::hir_id::{HirIdMap, HirIdSet}; use rustc_hir::intravisit::{walk_expr, FnKind, Visitor}; use rustc_hir::LangItem::{OptionNone, ResultErr, ResultOk}; use rustc_hir::{ - self as hir, def, Arm, ArrayLen, BindingAnnotation, Block, BlockCheckMode, Body, Closure, Constness, Destination, - Expr, ExprKind, FnDecl, HirId, Impl, ImplItem, ImplItemKind, ImplItemRef, IsAsync, Item, ItemKind, LangItem, Local, + self as hir, def, Arm, ArrayLen, BindingAnnotation, Block, BlockCheckMode, Body, Closure, Destination, Expr, + ExprKind, FnDecl, HirId, Impl, ImplItem, ImplItemKind, ImplItemRef, IsAsync, Item, ItemKind, LangItem, Local, MatchSource, Mutability, Node, OwnerId, Param, Pat, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, - TraitItem, TraitItemKind, TraitItemRef, TraitRef, TyKind, UnOp, + TraitItem, TraitItemRef, TraitRef, TyKind, UnOp, }; use rustc_lexer::{tokenize, TokenKind}; use rustc_lint::{LateContext, Level, Lint, LintContext}; @@ -197,31 +197,7 @@ pub fn find_binding_init<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option< /// } /// ``` pub fn in_constant(cx: &LateContext<'_>, id: HirId) -> bool { - let parent_id = cx.tcx.hir().get_parent_item(id).def_id; - match cx.tcx.hir().get_by_def_id(parent_id) { - Node::Item(&Item { - kind: ItemKind::Const(..) | ItemKind::Static(..) | ItemKind::Enum(..), - .. - }) - | Node::TraitItem(&TraitItem { - kind: TraitItemKind::Const(..), - .. - }) - | Node::ImplItem(&ImplItem { - kind: ImplItemKind::Const(..), - .. - }) - | Node::AnonConst(_) => true, - Node::Item(&Item { - kind: ItemKind::Fn(ref sig, ..), - .. - }) - | Node::ImplItem(&ImplItem { - kind: ImplItemKind::Fn(ref sig, _), - .. - }) => sig.header.constness == Constness::Const, - _ => false, - } + cx.tcx.hir().is_inside_const_context(id) } /// Checks if a `Res` refers to a constructor of a `LangItem` diff --git a/tests/ui/bool_to_int_with_if.fixed b/tests/ui/bool_to_int_with_if.fixed index 9831c3373d455..fbb10a133e2b0 100644 --- a/tests/ui/bool_to_int_with_if.fixed +++ b/tests/ui/bool_to_int_with_if.fixed @@ -1,6 +1,6 @@ //@run-rustfix -#![feature(let_chains)] +#![feature(let_chains, inline_const)] #![warn(clippy::bool_to_int_with_if)] #![allow(unused, dead_code, clippy::unnecessary_operation, clippy::no_effect)] @@ -79,6 +79,13 @@ fn main() { pub const SHOULD_NOT_LINT: usize = if true { 1 } else { 0 }; + // https://github.com/rust-lang/rust-clippy/issues/10452 + let should_not_lint = [(); if true { 1 } else { 0 }]; + + let should_not_lint = const { + if true { 1 } else { 0 } + }; + some_fn(a); } diff --git a/tests/ui/bool_to_int_with_if.rs b/tests/ui/bool_to_int_with_if.rs index 5e3047bb32c62..709a18d63e401 100644 --- a/tests/ui/bool_to_int_with_if.rs +++ b/tests/ui/bool_to_int_with_if.rs @@ -1,6 +1,6 @@ //@run-rustfix -#![feature(let_chains)] +#![feature(let_chains, inline_const)] #![warn(clippy::bool_to_int_with_if)] #![allow(unused, dead_code, clippy::unnecessary_operation, clippy::no_effect)] @@ -111,6 +111,13 @@ fn main() { pub const SHOULD_NOT_LINT: usize = if true { 1 } else { 0 }; + // https://github.com/rust-lang/rust-clippy/issues/10452 + let should_not_lint = [(); if true { 1 } else { 0 }]; + + let should_not_lint = const { + if true { 1 } else { 0 } + }; + some_fn(a); } diff --git a/tests/ui/bool_to_int_with_if.stderr b/tests/ui/bool_to_int_with_if.stderr index 5cfb75cc0dfcb..3bdae75cad22b 100644 --- a/tests/ui/bool_to_int_with_if.stderr +++ b/tests/ui/bool_to_int_with_if.stderr @@ -98,7 +98,7 @@ LL | | }; = note: `!b as i32` or `(!b).into()` can also be valid options error: boolean to int conversion using if - --> $DIR/bool_to_int_with_if.rs:119:5 + --> $DIR/bool_to_int_with_if.rs:126:5 | LL | if a { 1 } else { 0 } | ^^^^^^^^^^^^^^^^^^^^^ help: replace with from: `u8::from(a)` From 68c4776b4603f453d17b772e4598fee77c48dde8 Mon Sep 17 00:00:00 2001 From: DrMeepster <19316085+DrMeepster@users.noreply.github.com> Date: Sun, 11 Sep 2022 00:37:49 -0700 Subject: [PATCH 26/86] offset_of --- clippy_lints/src/loops/never_loop.rs | 3 ++- .../src/matches/significant_drop_in_scrutinee.rs | 1 + clippy_lints/src/utils/author.rs | 4 ++++ clippy_utils/src/eager_or_lazy.rs | 3 ++- clippy_utils/src/hir_utils.rs | 9 +++++++++ clippy_utils/src/qualify_min_const_fn.rs | 2 +- clippy_utils/src/sugg.rs | 2 ++ clippy_utils/src/visitors.rs | 1 + 8 files changed, 22 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/loops/never_loop.rs b/clippy_lints/src/loops/never_loop.rs index f0a1b1dfe5628..5f1fdf00be8c3 100644 --- a/clippy_lints/src/loops/never_loop.rs +++ b/clippy_lints/src/loops/never_loop.rs @@ -226,7 +226,8 @@ fn never_loop_expr(expr: &Expr<'_>, ignore_ids: &mut Vec, main_loop_id: H | InlineAsmOperand::SymStatic { .. } => NeverLoopResult::Otherwise, }) .fold(NeverLoopResult::Otherwise, combine_seq), - ExprKind::Yield(_, _) + ExprKind::OffsetOf(_, _) + | ExprKind::Yield(_, _) | ExprKind::Closure { .. } | ExprKind::Path(_) | ExprKind::ConstBlock(_) diff --git a/clippy_lints/src/matches/significant_drop_in_scrutinee.rs b/clippy_lints/src/matches/significant_drop_in_scrutinee.rs index 04225beeb704b..7945275393c04 100644 --- a/clippy_lints/src/matches/significant_drop_in_scrutinee.rs +++ b/clippy_lints/src/matches/significant_drop_in_scrutinee.rs @@ -342,6 +342,7 @@ impl<'a, 'tcx> Visitor<'tcx> for SigDropHelper<'a, 'tcx> { ExprKind::DropTemps(_) | ExprKind::Err(_) | ExprKind::InlineAsm(_) | + ExprKind::OffsetOf(_, _) | ExprKind::Let(_) | ExprKind::Lit(_) | ExprKind::Loop(_, _, _, _) | diff --git a/clippy_lints/src/utils/author.rs b/clippy_lints/src/utils/author.rs index 2dac807c420e3..01927b6b5f10d 100644 --- a/clippy_lints/src/utils/author.rs +++ b/clippy_lints/src/utils/author.rs @@ -558,6 +558,10 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { kind!("InlineAsm(_)"); out!("// unimplemented: `ExprKind::InlineAsm` is not further destructured at the moment"); }, + ExprKind::OffsetOf(container, ref fields) => { + bind!(self, container, fields); + kind!("OffsetOf({container}, {fields})"); + } ExprKind::Struct(qpath, fields, base) => { bind!(self, qpath, fields); opt_bind!(self, base); diff --git a/clippy_utils/src/eager_or_lazy.rs b/clippy_utils/src/eager_or_lazy.rs index 28c8571706135..3df40942e7b5a 100644 --- a/clippy_utils/src/eager_or_lazy.rs +++ b/clippy_utils/src/eager_or_lazy.rs @@ -218,7 +218,8 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS | ExprKind::AddrOf(..) | ExprKind::Struct(..) | ExprKind::Repeat(..) - | ExprKind::Block(Block { stmts: [], .. }, _) => (), + | ExprKind::Block(Block { stmts: [], .. }, _) + | ExprKind::OffsetOf(..) => (), // Assignment might be to a local defined earlier, so don't eagerly evaluate. // Blocks with multiple statements might be expensive, so don't eagerly evaluate. diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs index 3ee7147828bd5..d972ed82c258b 100644 --- a/clippy_utils/src/hir_utils.rs +++ b/clippy_utils/src/hir_utils.rs @@ -301,6 +301,9 @@ impl HirEqInterExpr<'_, '_, '_> { (&ExprKind::Unary(l_op, le), &ExprKind::Unary(r_op, re)) => l_op == r_op && self.eq_expr(le, re), (&ExprKind::Array(l), &ExprKind::Array(r)) => self.eq_exprs(l, r), (&ExprKind::DropTemps(le), &ExprKind::DropTemps(re)) => self.eq_expr(le, re), + (&ExprKind::OffsetOf(l_container, ref l_fields), &ExprKind::OffsetOf(r_container, ref r_fields)) => { + self.eq_ty(l_container, r_container) && over(l_fields, r_fields, |l, r| l.name == r.name) + }, _ => false, }; (is_eq && (!self.should_ignore(left) || !self.should_ignore(right))) @@ -701,6 +704,12 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { } } }, + ExprKind::OffsetOf(container, fields) => { + self.hash_ty(container); + for field in fields { + self.hash_name(field.name); + } + }, ExprKind::Let(Let { pat, init, ty, .. }) => { self.hash_expr(init); if let Some(ty) = ty { diff --git a/clippy_utils/src/qualify_min_const_fn.rs b/clippy_utils/src/qualify_min_const_fn.rs index 354b6d71aa466..ecd712f32dc1f 100644 --- a/clippy_utils/src/qualify_min_const_fn.rs +++ b/clippy_utils/src/qualify_min_const_fn.rs @@ -194,7 +194,7 @@ fn check_rvalue<'tcx>( )) } }, - Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _) | Rvalue::ShallowInitBox(_, _) => Ok(()), + Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(_), _) | Rvalue::ShallowInitBox(_, _) => Ok(()), Rvalue::UnaryOp(_, operand) => { let ty = operand.ty(body, tcx); if ty.is_integral() || ty.is_bool() { diff --git a/clippy_utils/src/sugg.rs b/clippy_utils/src/sugg.rs index a5a4a921d94ec..e81eadceec0aa 100644 --- a/clippy_utils/src/sugg.rs +++ b/clippy_utils/src/sugg.rs @@ -139,6 +139,7 @@ impl<'a> Sugg<'a> { | hir::ExprKind::Field(..) | hir::ExprKind::Index(..) | hir::ExprKind::InlineAsm(..) + | hir::ExprKind::OffsetOf(..) | hir::ExprKind::ConstBlock(..) | hir::ExprKind::Lit(..) | hir::ExprKind::Loop(..) @@ -197,6 +198,7 @@ impl<'a> Sugg<'a> { | ast::ExprKind::ForLoop(..) | ast::ExprKind::Index(..) | ast::ExprKind::InlineAsm(..) + | ast::ExprKind::OffsetOf(..) | ast::ExprKind::ConstBlock(..) | ast::ExprKind::Lit(..) | ast::ExprKind::IncludedBytes(..) diff --git a/clippy_utils/src/visitors.rs b/clippy_utils/src/visitors.rs index 1dc19bac98444..5dcd71cef127e 100644 --- a/clippy_utils/src/visitors.rs +++ b/clippy_utils/src/visitors.rs @@ -662,6 +662,7 @@ pub fn for_each_unconsumed_temporary<'tcx, B>( | ExprKind::Path(_) | ExprKind::Continue(_) | ExprKind::InlineAsm(_) + | ExprKind::OffsetOf(..) | ExprKind::Err(_) => (), } ControlFlow::Continue(()) From 85d7de25a987b72ffb6552e852a4c8f661dfb1c8 Mon Sep 17 00:00:00 2001 From: Centri3 <114838443+Centri3@users.noreply.github.com> Date: Fri, 21 Apr 2023 05:12:14 -0500 Subject: [PATCH 27/86] fix false positive --- clippy_lints/src/allow_attributes.rs | 4 +++- tests/ui/allow_attributes_false_positive.rs | 6 ++++++ 2 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 tests/ui/allow_attributes_false_positive.rs diff --git a/clippy_lints/src/allow_attributes.rs b/clippy_lints/src/allow_attributes.rs index b984132acf5bb..add73d0aeeed3 100644 --- a/clippy_lints/src/allow_attributes.rs +++ b/clippy_lints/src/allow_attributes.rs @@ -2,7 +2,8 @@ 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_lint::{LateContext, LateLintPass, LintContext}; +use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { @@ -51,6 +52,7 @@ impl LateLintPass<'_> for AllowAttribute { // Separate each crate's features. fn check_attribute(&mut self, cx: &LateContext<'_>, attr: &ast::Attribute) { if_chain! { + if !in_external_macro(cx.sess(), attr.span); if cx.tcx.features().lint_reasons; if let AttrStyle::Outer = attr.style; if let Some(ident) = attr.ident(); diff --git a/tests/ui/allow_attributes_false_positive.rs b/tests/ui/allow_attributes_false_positive.rs new file mode 100644 index 0000000000000..a34a5d91ef5a1 --- /dev/null +++ b/tests/ui/allow_attributes_false_positive.rs @@ -0,0 +1,6 @@ +#![allow(unused)] +#![warn(clippy::allow_attributes)] +#![feature(lint_reasons)] +#![crate_type = "proc-macro"] + +fn main() {} From cb3e0fbb5999429f4f4c30e505c4904c9999cdf8 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Thu, 24 Nov 2022 19:09:27 +0000 Subject: [PATCH 28/86] Evaluate place expression in `PlaceMention`. --- tests/ui/option_if_let_else.fixed | 4 ++-- tests/ui/option_if_let_else.rs | 4 ++-- tests/ui/option_if_let_else.stderr | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/ui/option_if_let_else.fixed b/tests/ui/option_if_let_else.fixed index 0456005dce496..35ce89c798649 100644 --- a/tests/ui/option_if_let_else.fixed +++ b/tests/ui/option_if_let_else.fixed @@ -25,7 +25,7 @@ fn else_if_option(string: Option<&str>) -> Option<(bool, &str)> { fn unop_bad(string: &Option<&str>, mut num: Option) { let _ = string.map_or(0, |s| s.len()); let _ = num.as_ref().map_or(&0, |s| s); - let _ = num.as_mut().map_or(&mut 0, |s| { + let _ = num.as_mut().map_or(&0, |s| { *s += 1; s }); @@ -34,7 +34,7 @@ fn unop_bad(string: &Option<&str>, mut num: Option) { s += 1; s }); - let _ = num.as_mut().map_or(&mut 0, |s| { + let _ = num.as_mut().map_or(&0, |s| { *s += 1; s }); diff --git a/tests/ui/option_if_let_else.rs b/tests/ui/option_if_let_else.rs index 23b148752cbfa..c8683e5aae2d0 100644 --- a/tests/ui/option_if_let_else.rs +++ b/tests/ui/option_if_let_else.rs @@ -33,7 +33,7 @@ fn unop_bad(string: &Option<&str>, mut num: Option) { *s += 1; s } else { - &mut 0 + &0 }; let _ = if let Some(ref s) = num { s } else { &0 }; let _ = if let Some(mut s) = num { @@ -46,7 +46,7 @@ fn unop_bad(string: &Option<&str>, mut num: Option) { *s += 1; s } else { - &mut 0 + &0 }; } diff --git a/tests/ui/option_if_let_else.stderr b/tests/ui/option_if_let_else.stderr index a5dbf6e1f2218..f5e4affb67229 100644 --- a/tests/ui/option_if_let_else.stderr +++ b/tests/ui/option_if_let_else.stderr @@ -30,13 +30,13 @@ LL | let _ = if let Some(s) = &mut num { LL | | *s += 1; LL | | s LL | | } else { -LL | | &mut 0 +LL | | &0 LL | | }; | |_____^ | help: try | -LL ~ let _ = num.as_mut().map_or(&mut 0, |s| { +LL ~ let _ = num.as_mut().map_or(&0, |s| { LL + *s += 1; LL + s LL ~ }); @@ -76,13 +76,13 @@ LL | let _ = if let Some(ref mut s) = num { LL | | *s += 1; LL | | s LL | | } else { -LL | | &mut 0 +LL | | &0 LL | | }; | |_____^ | help: try | -LL ~ let _ = num.as_mut().map_or(&mut 0, |s| { +LL ~ let _ = num.as_mut().map_or(&0, |s| { LL + *s += 1; LL + s LL ~ }); From 7f13e6d8a54f58d51f159ddb97eb94b14a72ac79 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 16 Feb 2023 09:25:11 +0000 Subject: [PATCH 29/86] Allow `LocalDefId` as the argument to `def_path_str` --- clippy_lints/src/default_union_representation.rs | 2 +- clippy_lints/src/trailing_empty_array.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/default_union_representation.rs b/clippy_lints/src/default_union_representation.rs index dec357ab75c36..03b5a2d6d0829 100644 --- a/clippy_lints/src/default_union_representation.rs +++ b/clippy_lints/src/default_union_representation.rs @@ -61,7 +61,7 @@ impl<'tcx> LateLintPass<'tcx> for DefaultUnionRepresentation { None, &format!( "consider annotating `{}` with `#[repr(C)]` to explicitly specify memory layout", - cx.tcx.def_path_str(item.owner_id.to_def_id()) + cx.tcx.def_path_str(item.owner_id) ), ); } diff --git a/clippy_lints/src/trailing_empty_array.rs b/clippy_lints/src/trailing_empty_array.rs index 1382c1a40da24..98f5b47f7a0e4 100644 --- a/clippy_lints/src/trailing_empty_array.rs +++ b/clippy_lints/src/trailing_empty_array.rs @@ -46,7 +46,7 @@ impl<'tcx> LateLintPass<'tcx> for TrailingEmptyArray { None, &format!( "consider annotating `{}` with `#[repr(C)]` or another `repr` attribute", - cx.tcx.def_path_str(item.owner_id.to_def_id()) + cx.tcx.def_path_str(item.owner_id) ), ); } From 628605e07a2a9a546ba698f1a50311b16832f227 Mon Sep 17 00:00:00 2001 From: Renato Lochetti Date: Sat, 22 Apr 2023 20:28:08 +0100 Subject: [PATCH 30/86] Ignore `shadow` warns in code from macro expansions --- clippy_lints/src/shadow.rs | 2 +- tests/ui/shadow.rs | 12 +++++ tests/ui/shadow.stderr | 92 +++++++++++++++++++------------------- 3 files changed, 59 insertions(+), 47 deletions(-) diff --git a/clippy_lints/src/shadow.rs b/clippy_lints/src/shadow.rs index ae7d19624ba61..993f9373d85d3 100644 --- a/clippy_lints/src/shadow.rs +++ b/clippy_lints/src/shadow.rs @@ -108,7 +108,7 @@ impl<'tcx> LateLintPass<'tcx> for Shadow { fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) { let PatKind::Binding(_, id, ident, _) = pat.kind else { return }; - if pat.span.desugaring_kind().is_some() { + if pat.span.desugaring_kind().is_some() || pat.span.from_expansion() { return; } diff --git a/tests/ui/shadow.rs b/tests/ui/shadow.rs index 03337ec35643c..2c0fc3e3fd83f 100644 --- a/tests/ui/shadow.rs +++ b/tests/ui/shadow.rs @@ -8,6 +8,12 @@ extern crate proc_macro_derive; #[derive(proc_macro_derive::ShadowDerive)] pub struct Nothing; +macro_rules! reuse { + ($v:ident) => { + let $v = $v + 1; + }; +} + fn shadow_same() { let x = 1; let x = x; @@ -33,6 +39,12 @@ fn shadow_reuse() -> Option<()> { None } +fn shadow_reuse_macro() { + let x = 1; + // this should not warn + reuse!(x); +} + fn shadow_unrelated() { let x = 1; let x = 2; diff --git a/tests/ui/shadow.stderr b/tests/ui/shadow.stderr index 92bb937d08680..8321f6df224cf 100644 --- a/tests/ui/shadow.stderr +++ b/tests/ui/shadow.stderr @@ -1,278 +1,278 @@ error: `x` is shadowed by itself in `x` - --> $DIR/shadow.rs:13:9 + --> $DIR/shadow.rs:19:9 | LL | let x = x; | ^ | note: previous binding is here - --> $DIR/shadow.rs:12:9 + --> $DIR/shadow.rs:18:9 | LL | let x = 1; | ^ = note: `-D clippy::shadow-same` implied by `-D warnings` error: `mut x` is shadowed by itself in `&x` - --> $DIR/shadow.rs:14:13 + --> $DIR/shadow.rs:20:13 | LL | let mut x = &x; | ^ | note: previous binding is here - --> $DIR/shadow.rs:13:9 + --> $DIR/shadow.rs:19:9 | LL | let x = x; | ^ error: `x` is shadowed by itself in `&mut x` - --> $DIR/shadow.rs:15:9 + --> $DIR/shadow.rs:21:9 | LL | let x = &mut x; | ^ | note: previous binding is here - --> $DIR/shadow.rs:14:9 + --> $DIR/shadow.rs:20:9 | LL | let mut x = &x; | ^^^^^ error: `x` is shadowed by itself in `*x` - --> $DIR/shadow.rs:16:9 + --> $DIR/shadow.rs:22:9 | LL | let x = *x; | ^ | note: previous binding is here - --> $DIR/shadow.rs:15:9 + --> $DIR/shadow.rs:21:9 | LL | let x = &mut x; | ^ error: `x` is shadowed - --> $DIR/shadow.rs:21:9 + --> $DIR/shadow.rs:27:9 | LL | let x = x.0; | ^ | note: previous binding is here - --> $DIR/shadow.rs:20:9 + --> $DIR/shadow.rs:26:9 | LL | let x = ([[0]], ()); | ^ = note: `-D clippy::shadow-reuse` implied by `-D warnings` error: `x` is shadowed - --> $DIR/shadow.rs:22:9 + --> $DIR/shadow.rs:28:9 | LL | let x = x[0]; | ^ | note: previous binding is here - --> $DIR/shadow.rs:21:9 + --> $DIR/shadow.rs:27:9 | LL | let x = x.0; | ^ error: `x` is shadowed - --> $DIR/shadow.rs:23:10 + --> $DIR/shadow.rs:29:10 | LL | let [x] = x; | ^ | note: previous binding is here - --> $DIR/shadow.rs:22:9 + --> $DIR/shadow.rs:28:9 | LL | let x = x[0]; | ^ error: `x` is shadowed - --> $DIR/shadow.rs:24:9 + --> $DIR/shadow.rs:30:9 | LL | let x = Some(x); | ^ | note: previous binding is here - --> $DIR/shadow.rs:23:10 + --> $DIR/shadow.rs:29:10 | LL | let [x] = x; | ^ error: `x` is shadowed - --> $DIR/shadow.rs:25:9 + --> $DIR/shadow.rs:31:9 | LL | let x = foo(x); | ^ | note: previous binding is here - --> $DIR/shadow.rs:24:9 + --> $DIR/shadow.rs:30:9 | LL | let x = Some(x); | ^ error: `x` is shadowed - --> $DIR/shadow.rs:26:9 + --> $DIR/shadow.rs:32:9 | LL | let x = || x; | ^ | note: previous binding is here - --> $DIR/shadow.rs:25:9 + --> $DIR/shadow.rs:31:9 | LL | let x = foo(x); | ^ error: `x` is shadowed - --> $DIR/shadow.rs:27:9 + --> $DIR/shadow.rs:33:9 | LL | let x = Some(1).map(|_| x)?; | ^ | note: previous binding is here - --> $DIR/shadow.rs:26:9 + --> $DIR/shadow.rs:32:9 | LL | let x = || x; | ^ error: `y` is shadowed - --> $DIR/shadow.rs:29:9 + --> $DIR/shadow.rs:35:9 | LL | let y = match y { | ^ | note: previous binding is here - --> $DIR/shadow.rs:28:9 + --> $DIR/shadow.rs:34:9 | LL | let y = 1; | ^ error: `x` shadows a previous, unrelated binding - --> $DIR/shadow.rs:38:9 + --> $DIR/shadow.rs:50:9 | LL | let x = 2; | ^ | note: previous binding is here - --> $DIR/shadow.rs:37:9 + --> $DIR/shadow.rs:49:9 | LL | let x = 1; | ^ = note: `-D clippy::shadow-unrelated` implied by `-D warnings` error: `x` shadows a previous, unrelated binding - --> $DIR/shadow.rs:43:13 + --> $DIR/shadow.rs:55:13 | LL | let x = 1; | ^ | note: previous binding is here - --> $DIR/shadow.rs:42:10 + --> $DIR/shadow.rs:54:10 | LL | fn f(x: u32) { | ^ error: `x` shadows a previous, unrelated binding - --> $DIR/shadow.rs:48:14 + --> $DIR/shadow.rs:60:14 | LL | Some(x) => { | ^ | note: previous binding is here - --> $DIR/shadow.rs:45:9 + --> $DIR/shadow.rs:57:9 | LL | let x = 1; | ^ error: `x` shadows a previous, unrelated binding - --> $DIR/shadow.rs:49:17 + --> $DIR/shadow.rs:61:17 | LL | let x = 1; | ^ | note: previous binding is here - --> $DIR/shadow.rs:48:14 + --> $DIR/shadow.rs:60:14 | LL | Some(x) => { | ^ error: `x` shadows a previous, unrelated binding - --> $DIR/shadow.rs:53:17 + --> $DIR/shadow.rs:65:17 | LL | if let Some(x) = Some(1) {} | ^ | note: previous binding is here - --> $DIR/shadow.rs:45:9 + --> $DIR/shadow.rs:57:9 | LL | let x = 1; | ^ error: `x` shadows a previous, unrelated binding - --> $DIR/shadow.rs:54:20 + --> $DIR/shadow.rs:66:20 | LL | while let Some(x) = Some(1) {} | ^ | note: previous binding is here - --> $DIR/shadow.rs:45:9 + --> $DIR/shadow.rs:57:9 | LL | let x = 1; | ^ error: `x` shadows a previous, unrelated binding - --> $DIR/shadow.rs:55:15 + --> $DIR/shadow.rs:67:15 | LL | let _ = |[x]: [u32; 1]| { | ^ | note: previous binding is here - --> $DIR/shadow.rs:45:9 + --> $DIR/shadow.rs:57:9 | LL | let x = 1; | ^ error: `x` shadows a previous, unrelated binding - --> $DIR/shadow.rs:56:13 + --> $DIR/shadow.rs:68:13 | LL | let x = 1; | ^ | note: previous binding is here - --> $DIR/shadow.rs:55:15 + --> $DIR/shadow.rs:67:15 | LL | let _ = |[x]: [u32; 1]| { | ^ error: `y` is shadowed - --> $DIR/shadow.rs:59:17 + --> $DIR/shadow.rs:71:17 | LL | if let Some(y) = y {} | ^ | note: previous binding is here - --> $DIR/shadow.rs:58:9 + --> $DIR/shadow.rs:70:9 | LL | let y = Some(1); | ^ error: `_b` shadows a previous, unrelated binding - --> $DIR/shadow.rs:95:9 + --> $DIR/shadow.rs:107:9 | LL | let _b = _a; | ^^ | note: previous binding is here - --> $DIR/shadow.rs:94:28 + --> $DIR/shadow.rs:106:28 | LL | pub async fn foo2(_a: i32, _b: i64) { | ^^ error: `x` shadows a previous, unrelated binding - --> $DIR/shadow.rs:101:21 + --> $DIR/shadow.rs:113:21 | LL | if let Some(x) = Some(1) { x } else { 1 } | ^ | note: previous binding is here - --> $DIR/shadow.rs:100:13 + --> $DIR/shadow.rs:112:13 | LL | let x = 1; | ^ From 0add5bb0f1c5535a508155e6065d24bf0a8c1dbe Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Sun, 23 Apr 2023 03:39:19 -0700 Subject: [PATCH 31/86] Bump Clippy version -> 0.1.71 --- Cargo.toml | 2 +- clippy_lints/Cargo.toml | 2 +- clippy_utils/Cargo.toml | 2 +- declare_clippy_lint/Cargo.toml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 4db15ddb2835c..3c72bb62ed19e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy" -version = "0.1.70" +version = "0.1.71" description = "A bunch of helpful lints to avoid common pitfalls in Rust" repository = "https://github.com/rust-lang/rust-clippy" readme = "README.md" diff --git a/clippy_lints/Cargo.toml b/clippy_lints/Cargo.toml index 5c6040f63f50f..a0db69b652db0 100644 --- a/clippy_lints/Cargo.toml +++ b/clippy_lints/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy_lints" -version = "0.1.70" +version = "0.1.71" description = "A bunch of helpful lints to avoid common pitfalls in Rust" repository = "https://github.com/rust-lang/rust-clippy" readme = "README.md" diff --git a/clippy_utils/Cargo.toml b/clippy_utils/Cargo.toml index 124ebd164e6b5..66a5079fa85ef 100644 --- a/clippy_utils/Cargo.toml +++ b/clippy_utils/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy_utils" -version = "0.1.70" +version = "0.1.71" edition = "2021" publish = false diff --git a/declare_clippy_lint/Cargo.toml b/declare_clippy_lint/Cargo.toml index bd26f4fc91395..139102798c42a 100644 --- a/declare_clippy_lint/Cargo.toml +++ b/declare_clippy_lint/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "declare_clippy_lint" -version = "0.1.70" +version = "0.1.71" edition = "2021" publish = false From d5a2c2ba713985d01d2105c43891ba829331ee22 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Sun, 23 Apr 2023 03:39:29 -0700 Subject: [PATCH 32/86] Bump nightly version -> 2023-04-23 --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index 91e8ccea1f434..7a6d85f4147bb 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2023-04-06" +channel = "nightly-2023-04-23" components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] From 36bf3ef0042397f0d9d21f9de695f551e4e9d3b5 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Sun, 23 Apr 2023 03:44:24 -0700 Subject: [PATCH 33/86] Fix dogfood test --- tests/dogfood.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/dogfood.rs b/tests/dogfood.rs index 68a878e9a3d31..afde31face113 100644 --- a/tests/dogfood.rs +++ b/tests/dogfood.rs @@ -39,7 +39,7 @@ fn dogfood_clippy() { assert!( failed_packages.is_empty(), "Dogfood failed for packages `{}`", - failed_packages.iter().format(", "), + failed_packages.iter().join(", "), ); } From acf50a7dc685ad5267e2fcff5a1545d5e56f5c44 Mon Sep 17 00:00:00 2001 From: blyxyas Date: Sun, 23 Apr 2023 12:52:45 +0200 Subject: [PATCH 34/86] Improve the help message + add a help span --- clippy_lints/src/let_underscore.rs | 10 +++++++-- tests/ui/let_underscore_untyped.stderr | 30 +++++++++++++++++++++----- 2 files changed, 33 insertions(+), 7 deletions(-) diff --git a/clippy_lints/src/let_underscore.rs b/clippy_lints/src/let_underscore.rs index 637b7de920e79..16772a9d5987b 100644 --- a/clippy_lints/src/let_underscore.rs +++ b/clippy_lints/src/let_underscore.rs @@ -6,6 +6,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::subst::GenericArgKind; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::{BytePos, Span}; declare_clippy_lint! { /// ### What it does @@ -205,8 +206,13 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { LET_UNDERSCORE_UNTYPED, local.span, "non-binding `let` without a type annotation", - None, - "consider adding a type annotation or removing the `let` keyword", + Some( + Span::new(local.pat.span.hi(), + local.pat.span.hi() + BytePos(1), + local.pat.span.ctxt(), + local.pat.span.parent() + )), + "consider adding a type annotation", ); } } diff --git a/tests/ui/let_underscore_untyped.stderr b/tests/ui/let_underscore_untyped.stderr index 47e76ea1d04e9..6844cb998f72a 100644 --- a/tests/ui/let_underscore_untyped.stderr +++ b/tests/ui/let_underscore_untyped.stderr @@ -4,7 +4,11 @@ error: non-binding `let` without a type annotation LL | let _ = a(); | ^^^^^^^^^^^^ | - = help: consider adding a type annotation or removing the `let` keyword +help: consider adding a type annotation + --> $DIR/let_underscore_untyped.rs:36:10 + | +LL | let _ = a(); + | ^ = note: `-D clippy::let-underscore-untyped` implied by `-D warnings` error: non-binding `let` without a type annotation @@ -13,7 +17,11 @@ error: non-binding `let` without a type annotation LL | let _ = b(1); | ^^^^^^^^^^^^^ | - = help: consider adding a type annotation or removing the `let` keyword +help: consider adding a type annotation + --> $DIR/let_underscore_untyped.rs:37:10 + | +LL | let _ = b(1); + | ^ error: non-binding `let` without a type annotation --> $DIR/let_underscore_untyped.rs:39:5 @@ -21,7 +29,11 @@ error: non-binding `let` without a type annotation LL | let _ = d(&1); | ^^^^^^^^^^^^^^ | - = help: consider adding a type annotation or removing the `let` keyword +help: consider adding a type annotation + --> $DIR/let_underscore_untyped.rs:39:10 + | +LL | let _ = d(&1); + | ^ error: non-binding `let` without a type annotation --> $DIR/let_underscore_untyped.rs:40:5 @@ -29,7 +41,11 @@ error: non-binding `let` without a type annotation LL | let _ = e(); | ^^^^^^^^^^^^ | - = help: consider adding a type annotation or removing the `let` keyword +help: consider adding a type annotation + --> $DIR/let_underscore_untyped.rs:40:10 + | +LL | let _ = e(); + | ^ error: non-binding `let` without a type annotation --> $DIR/let_underscore_untyped.rs:41:5 @@ -37,7 +53,11 @@ error: non-binding `let` without a type annotation LL | let _ = f(); | ^^^^^^^^^^^^ | - = help: consider adding a type annotation or removing the `let` keyword +help: consider adding a type annotation + --> $DIR/let_underscore_untyped.rs:41:10 + | +LL | let _ = f(); + | ^ error: aborting due to 5 previous errors From a1b75c5108514504c8382ac70d56f9a2a9aee7c4 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Sun, 23 Apr 2023 13:03:09 +0200 Subject: [PATCH 35/86] Merge commit 'a3ed905928a03b6e433d0b429190bf3a847128b3' into clippyup --- CHANGELOG.md | 120 +++++++- Cargo.toml | 5 +- book/src/SUMMARY.md | 2 + book/src/development/README.md | 22 ++ book/src/development/adding_lints.md | 2 +- book/src/development/lint_passes.md | 114 ++++++++ book/src/development/macro_expansions.md | 158 +++++++++++ book/src/development/type_checking.md | 25 +- book/src/lint_configuration.md | 9 + clippy_dev/src/update_lints.rs | 2 +- clippy_lints/src/allow_attributes.rs | 2 +- clippy_lints/src/casts/mod.rs | 10 +- clippy_lints/src/crate_in_macro_def.rs | 2 +- clippy_lints/src/declared_lints.rs | 1 + clippy_lints/src/entry.rs | 2 +- clippy_lints/src/enum_variants.rs | 8 +- clippy_lints/src/format_impl.rs | 2 +- clippy_lints/src/formatting.rs | 2 +- clippy_lints/src/functions/mod.rs | 2 +- clippy_lints/src/items_after_test_module.rs | 83 ++++++ clippy_lints/src/len_zero.rs | 22 +- clippy_lints/src/let_underscore.rs | 15 +- clippy_lints/src/lib.rs | 4 + clippy_lints/src/lines_filter_map_ok.rs | 2 +- clippy_lints/src/manual_bits.rs | 2 +- .../src/manual_slice_size_calculation.rs | 28 +- clippy_lints/src/matches/mod.rs | 6 +- clippy_lints/src/methods/mod.rs | 34 +-- .../src/methods/obfuscated_if_else.rs | 2 - .../src/multiple_unsafe_ops_per_block.rs | 2 +- clippy_lints/src/mutex_atomic.rs | 6 +- clippy_lints/src/non_copy_const.rs | 2 +- clippy_lints/src/octal_escapes.rs | 94 +++--- .../src/operators/arithmetic_side_effects.rs | 42 ++- clippy_lints/src/operators/mod.rs | 2 +- .../src/operators/numeric_arithmetic.rs | 10 +- clippy_lints/src/question_mark_used.rs | 2 +- .../src/significant_drop_tightening.rs | 4 +- clippy_lints/src/types/mod.rs | 10 +- clippy_lints/src/unnecessary_box_returns.rs | 15 +- clippy_lints/src/utils/conf.rs | 4 + .../internal_lints/unnecessary_def_path.rs | 2 +- clippy_lints/src/write.rs | 2 +- declare_clippy_lint/Cargo.toml | 2 +- declare_clippy_lint/src/lib.rs | 8 +- tests/compile-test.rs | 3 +- .../cargo_common_metadata/fail/src/main.rs | 2 +- .../fail_publish/src/main.rs | 2 +- .../fail_publish_true/src/main.rs | 2 +- .../cargo_common_metadata/pass/src/main.rs | 2 +- .../pass_publish_empty/src/main.rs | 2 +- .../pass_publish_false/src/main.rs | 2 +- tests/ui-cargo/feature_name/fail/src/main.rs | 2 +- tests/ui-cargo/feature_name/pass/src/main.rs | 2 +- .../module_style/fail_mod_remap/src/main.rs | 2 +- .../5041_allow_dev_build/src/main.rs | 2 +- .../multiple_crate_versions/fail/src/main.rs | 2 +- .../multiple_crate_versions/pass/src/main.rs | 2 +- .../wildcard_dependencies/fail/src/main.rs | 2 +- .../wildcard_dependencies/pass/src/main.rs | 2 +- .../collapsible_span_lint_calls.fixed | 2 +- .../collapsible_span_lint_calls.rs | 2 +- tests/ui-internal/custom_ice_message.rs | 12 +- .../interning_defined_symbol.fixed | 2 +- tests/ui-internal/interning_defined_symbol.rs | 2 +- .../ui-internal/invalid_msrv_attr_impl.fixed | 2 +- tests/ui-internal/invalid_msrv_attr_impl.rs | 2 +- tests/ui-internal/outer_expn_data.fixed | 2 +- tests/ui-internal/outer_expn_data.rs | 2 +- tests/ui-internal/unnecessary_def_path.fixed | 4 +- tests/ui-internal/unnecessary_def_path.rs | 4 +- .../ui-internal/unnecessary_symbol_str.fixed | 2 +- tests/ui-internal/unnecessary_symbol_str.rs | 2 +- .../uninlined_format_args.fixed | 2 +- .../uninlined_format_args.rs | 2 +- tests/ui-toml/dbg_macro/dbg_macro.rs | 2 +- .../disallowed_macros/disallowed_macros.rs | 2 +- tests/ui-toml/expect_used/expect_used.rs | 2 +- tests/ui-toml/mut_key/mut_key.rs | 2 +- .../auxiliary/proc_macro_derive.rs | 4 +- .../conf_nonstandard_macro_braces.fixed | 4 +- .../conf_nonstandard_macro_braces.rs | 4 +- tests/ui-toml/print_macro/print_macro.rs | 2 +- .../conf_disallowed_methods.rs | 2 +- tests/ui-toml/toml_trivially_copy/test.rs | 4 +- .../toml_unknown_key/conf_unknown_key.rs | 2 + .../toml_unknown_key/conf_unknown_key.stderr | 1 + tests/ui-toml/unwrap_used/unwrap_used.rs | 2 +- tests/ui/allow_attributes.fixed | 2 +- tests/ui/allow_attributes.rs | 2 +- tests/ui/almost_complete_range.fixed | 6 +- tests/ui/almost_complete_range.rs | 6 +- tests/ui/arithmetic_side_effects.rs | 29 ++ tests/ui/arithmetic_side_effects.stderr | 268 +++++++++++------- tests/ui/as_conversions.rs | 2 +- tests/ui/as_underscore.fixed | 2 +- tests/ui/as_underscore.rs | 2 +- tests/ui/asm_syntax.rs | 4 +- tests/ui/assertions_on_result_states.fixed | 2 +- tests/ui/assertions_on_result_states.rs | 2 +- tests/ui/assign_ops.fixed | 2 +- tests/ui/assign_ops.rs | 2 +- tests/ui/async_yields_async.fixed | 2 +- tests/ui/async_yields_async.rs | 2 +- tests/ui/author/blocks.rs | 2 +- tests/ui/auxiliary/proc_macro_attr.rs | 8 +- tests/ui/auxiliary/proc_macro_derive.rs | 77 ++++- .../proc_macro_suspicious_else_formatting.rs | 4 +- tests/ui/auxiliary/proc_macro_unsafe.rs | 4 +- tests/ui/auxiliary/proc_macros.rs | 4 +- tests/ui/bind_instead_of_map.fixed | 2 +- tests/ui/bind_instead_of_map.rs | 2 +- tests/ui/bind_instead_of_map_multipart.fixed | 2 +- tests/ui/bind_instead_of_map_multipart.rs | 2 +- tests/ui/blanket_clippy_restriction_lints.rs | 2 +- tests/ui/blocks_in_if_conditions.fixed | 2 +- tests/ui/blocks_in_if_conditions.rs | 2 +- tests/ui/bool_assert_comparison.fixed | 2 +- tests/ui/bool_assert_comparison.rs | 2 +- tests/ui/bool_comparison.fixed | 2 +- tests/ui/bool_comparison.rs | 2 +- tests/ui/bool_to_int_with_if.fixed | 2 +- tests/ui/bool_to_int_with_if.rs | 2 +- tests/ui/borrow_as_ptr.fixed | 2 +- tests/ui/borrow_as_ptr.rs | 2 +- tests/ui/borrow_as_ptr_no_std.fixed | 2 +- tests/ui/borrow_as_ptr_no_std.rs | 2 +- tests/ui/borrow_deref_ref.fixed | 2 +- tests/ui/borrow_deref_ref.rs | 2 +- .../ui/borrow_interior_mutable_const/enums.rs | 2 +- tests/ui/box_default.fixed | 2 +- tests/ui/box_default.rs | 2 +- tests/ui/bytes_count_to_len.fixed | 2 +- tests/ui/bytes_count_to_len.rs | 2 +- tests/ui/bytes_nth.fixed | 2 +- tests/ui/bytes_nth.rs | 2 +- ...sensitive_file_extension_comparisons.fixed | 2 +- ...se_sensitive_file_extension_comparisons.rs | 2 +- tests/ui/cast_abs_to_unsigned.fixed | 2 +- tests/ui/cast_abs_to_unsigned.rs | 2 +- tests/ui/cast_lossless_bool.fixed | 2 +- tests/ui/cast_lossless_bool.rs | 2 +- tests/ui/cast_lossless_float.fixed | 2 +- tests/ui/cast_lossless_float.rs | 2 +- tests/ui/cast_lossless_integer.fixed | 2 +- tests/ui/cast_lossless_integer.rs | 2 +- tests/ui/cast_raw_slice_pointer_cast.fixed | 2 +- tests/ui/cast_raw_slice_pointer_cast.rs | 2 +- tests/ui/cast_size.rs | 2 +- tests/ui/cast_size_32bit.rs | 2 +- tests/ui/cast_size_32bit.stderr | 53 ++++ tests/ui/cfg_attr_rustfmt.fixed | 2 +- tests/ui/cfg_attr_rustfmt.rs | 2 +- tests/ui/char_lit_as_u8_suggestions.fixed | 2 +- tests/ui/char_lit_as_u8_suggestions.rs | 2 +- tests/ui/checked_conversions.fixed | 2 +- tests/ui/checked_conversions.rs | 2 +- tests/ui/clear_with_drain.fixed | 2 +- tests/ui/clear_with_drain.rs | 2 +- tests/ui/clone_on_copy.fixed | 2 +- tests/ui/clone_on_copy.rs | 2 +- tests/ui/cloned_instead_of_copied.fixed | 2 +- tests/ui/cloned_instead_of_copied.rs | 2 +- .../ui/cmp_owned/asymmetric_partial_eq.fixed | 2 +- tests/ui/cmp_owned/asymmetric_partial_eq.rs | 2 +- tests/ui/cmp_owned/comparison_flip.fixed | 2 +- tests/ui/cmp_owned/comparison_flip.rs | 2 +- tests/ui/cmp_owned/with_suggestion.fixed | 2 +- tests/ui/cmp_owned/with_suggestion.rs | 2 +- tests/ui/collapsible_else_if.fixed | 2 +- tests/ui/collapsible_else_if.rs | 2 +- tests/ui/collapsible_if.fixed | 2 +- tests/ui/collapsible_if.rs | 2 +- tests/ui/collapsible_str_replace.fixed | 2 +- tests/ui/collapsible_str_replace.rs | 2 +- tests/ui/collection_is_never_read.rs | 49 ++-- tests/ui/collection_is_never_read.stderr | 62 +++- tests/ui/comparison_to_empty.fixed | 2 +- tests/ui/comparison_to_empty.rs | 2 +- .../ui/crashes/auxiliary/proc_macro_crash.rs | 4 +- tests/ui/crashes/ice-10148.rs | 2 +- tests/ui/crashes/ice-3741.rs | 2 +- tests/ui/crashes/ice-4968.rs | 2 +- tests/ui/crashes/ice-5207.stderr | 4 +- tests/ui/crashes/ice-7272.rs | 2 +- tests/ui/crashes/ice-7410.rs | 6 +- tests/ui/crashes/ice-8681.rs | 2 +- tests/ui/crate_in_macro_def.fixed | 2 +- tests/ui/crate_in_macro_def.rs | 2 +- .../entrypoint_recursion.rs | 2 +- .../no_std_main_recursion.rs | 4 +- tests/ui/create_dir.fixed | 2 +- tests/ui/create_dir.rs | 2 +- tests/ui/dbg_macro.rs | 2 +- tests/ui/decimal_literal_representation.fixed | 2 +- tests/ui/decimal_literal_representation.rs | 2 +- tests/ui/def_id_nocore.rs | 2 +- tests/ui/default_instead_of_iter_empty.fixed | 2 +- tests/ui/default_instead_of_iter_empty.rs | 2 +- tests/ui/default_numeric_fallback_f64.fixed | 4 +- tests/ui/default_numeric_fallback_f64.rs | 4 +- tests/ui/default_numeric_fallback_i32.fixed | 4 +- tests/ui/default_numeric_fallback_i32.rs | 4 +- tests/ui/default_trait_access.fixed | 4 +- tests/ui/default_trait_access.rs | 4 +- tests/ui/deref_addrof.fixed | 4 +- tests/ui/deref_addrof.rs | 4 +- tests/ui/deref_addrof_macro.rs | 2 +- tests/ui/deref_by_slicing.fixed | 2 +- tests/ui/deref_by_slicing.rs | 2 +- tests/ui/derivable_impls.fixed | 2 +- tests/ui/derivable_impls.rs | 2 +- tests/ui/derive_partial_eq_without_eq.fixed | 2 +- tests/ui/derive_partial_eq_without_eq.rs | 2 +- tests/ui/doc/doc-fixable.fixed | 2 +- tests/ui/doc/doc-fixable.rs | 2 +- tests/ui/doc_unsafe.rs | 2 +- tests/ui/double_comparison.fixed | 2 +- tests/ui/double_comparison.rs | 2 +- tests/ui/duration_subsec.fixed | 2 +- tests/ui/duration_subsec.rs | 2 +- tests/ui/empty_drop.fixed | 2 +- tests/ui/empty_drop.rs | 2 +- tests/ui/empty_line_after_outer_attribute.rs | 2 +- tests/ui/empty_loop.rs | 2 +- tests/ui/empty_loop_no_std.rs | 4 +- tests/ui/empty_structs_with_brackets.fixed | 2 +- tests/ui/empty_structs_with_brackets.rs | 2 +- tests/ui/entry.fixed | 4 +- tests/ui/entry.rs | 4 +- tests/ui/entry_btree.fixed | 2 +- tests/ui/entry_btree.rs | 2 +- tests/ui/entry_with_else.fixed | 2 +- tests/ui/entry_with_else.rs | 2 +- tests/ui/enum_clike_unportable_variant.rs | 2 +- tests/ui/enum_glob_use.fixed | 2 +- tests/ui/enum_glob_use.rs | 2 +- tests/ui/enum_variants.rs | 10 + tests/ui/eq_op.rs | 2 +- tests/ui/equatable_if_let.fixed | 4 +- tests/ui/equatable_if_let.rs | 4 +- tests/ui/err_expect.fixed | 2 +- tests/ui/err_expect.rs | 2 +- tests/ui/eta.fixed | 2 +- tests/ui/eta.rs | 2 +- tests/ui/excessive_precision.fixed | 2 +- tests/ui/excessive_precision.rs | 2 +- tests/ui/exhaustive_items.fixed | 2 +- tests/ui/exhaustive_items.rs | 2 +- tests/ui/expect_fun_call.fixed | 2 +- tests/ui/expect_fun_call.rs | 2 +- tests/ui/explicit_auto_deref.fixed | 2 +- tests/ui/explicit_auto_deref.rs | 2 +- tests/ui/explicit_deref_methods.fixed | 2 +- tests/ui/explicit_deref_methods.rs | 2 +- tests/ui/explicit_write.fixed | 2 +- tests/ui/explicit_write.rs | 2 +- tests/ui/extend_with_drain.fixed | 2 +- tests/ui/extend_with_drain.rs | 2 +- tests/ui/extra_unused_lifetimes.rs | 2 +- tests/ui/extra_unused_type_parameters.fixed | 2 +- tests/ui/extra_unused_type_parameters.rs | 2 +- tests/ui/field_reassign_with_default.rs | 4 +- tests/ui/filter_map_identity.fixed | 2 +- tests/ui/filter_map_identity.rs | 2 +- tests/ui/filter_map_next_fixable.fixed | 2 +- tests/ui/filter_map_next_fixable.rs | 2 +- tests/ui/flat_map_identity.fixed | 2 +- tests/ui/flat_map_identity.rs | 2 +- tests/ui/flat_map_option.fixed | 2 +- tests/ui/flat_map_option.rs | 2 +- tests/ui/floating_point_abs.fixed | 2 +- tests/ui/floating_point_abs.rs | 2 +- tests/ui/floating_point_exp.fixed | 2 +- tests/ui/floating_point_exp.rs | 2 +- tests/ui/floating_point_hypot.fixed | 2 +- tests/ui/floating_point_hypot.rs | 2 +- tests/ui/floating_point_log.fixed | 2 +- tests/ui/floating_point_log.rs | 2 +- tests/ui/floating_point_logbase.fixed | 2 +- tests/ui/floating_point_logbase.rs | 2 +- tests/ui/floating_point_mul_add.fixed | 2 +- tests/ui/floating_point_mul_add.rs | 2 +- tests/ui/floating_point_powf.fixed | 2 +- tests/ui/floating_point_powf.rs | 2 +- tests/ui/floating_point_powi.fixed | 2 +- tests/ui/floating_point_powi.rs | 2 +- tests/ui/floating_point_rad.fixed | 2 +- tests/ui/floating_point_rad.rs | 2 +- tests/ui/fn_to_numeric_cast.rs | 2 +- tests/ui/fn_to_numeric_cast_32bit.rs | 2 +- tests/ui/fn_to_numeric_cast_32bit.stderr | 14 +- tests/ui/for_loop_fixable.fixed | 2 +- tests/ui/for_loop_fixable.rs | 2 +- tests/ui/format.fixed | 2 +- tests/ui/format.rs | 2 +- tests/ui/format_args.fixed | 2 +- tests/ui/format_args.rs | 2 +- tests/ui/from_iter_instead_of_collect.fixed | 2 +- tests/ui/from_iter_instead_of_collect.rs | 2 +- tests/ui/from_over_into.fixed | 2 +- tests/ui/from_over_into.rs | 2 +- tests/ui/get_first.fixed | 2 +- tests/ui/get_first.rs | 2 +- tests/ui/get_last_with_len.fixed | 2 +- tests/ui/get_last_with_len.rs | 2 +- tests/ui/get_unwrap.fixed | 2 +- tests/ui/get_unwrap.rs | 2 +- tests/ui/identity_op.fixed | 2 +- tests/ui/identity_op.rs | 2 +- tests/ui/implicit_clone.fixed | 2 +- tests/ui/implicit_clone.rs | 2 +- tests/ui/implicit_hasher.rs | 2 +- tests/ui/implicit_return.fixed | 2 +- tests/ui/implicit_return.rs | 2 +- tests/ui/implicit_saturating_add.fixed | 2 +- tests/ui/implicit_saturating_add.rs | 2 +- tests/ui/implicit_saturating_sub.fixed | 2 +- tests/ui/implicit_saturating_sub.rs | 2 +- tests/ui/inconsistent_digit_grouping.fixed | 2 +- tests/ui/inconsistent_digit_grouping.rs | 2 +- .../ui/inconsistent_struct_constructor.fixed | 4 +- tests/ui/inconsistent_struct_constructor.rs | 4 +- tests/ui/inefficient_to_string.fixed | 2 +- tests/ui/inefficient_to_string.rs | 2 +- tests/ui/infallible_destructuring_match.fixed | 2 +- tests/ui/infallible_destructuring_match.rs | 2 +- tests/ui/inline_fn_without_body.fixed | 2 +- tests/ui/inline_fn_without_body.rs | 2 +- tests/ui/int_plus_one.fixed | 2 +- tests/ui/int_plus_one.rs | 2 +- tests/ui/integer_arithmetic.rs | 7 + tests/ui/integer_arithmetic.stderr | 54 ++-- tests/ui/into_iter_on_ref.fixed | 2 +- tests/ui/into_iter_on_ref.rs | 2 +- tests/ui/invalid_null_ptr_usage.fixed | 2 +- tests/ui/invalid_null_ptr_usage.rs | 2 +- tests/ui/is_digit_ascii_radix.fixed | 2 +- tests/ui/is_digit_ascii_radix.rs | 2 +- tests/ui/issue_2356.fixed | 2 +- tests/ui/issue_2356.rs | 2 +- tests/ui/items_after_test_module.rs | 23 ++ tests/ui/items_after_test_module.stderr | 17 ++ tests/ui/iter_cloned_collect.fixed | 2 +- tests/ui/iter_cloned_collect.rs | 2 +- tests/ui/iter_count.fixed | 4 +- tests/ui/iter_count.rs | 4 +- tests/ui/iter_kv_map.fixed | 2 +- tests/ui/iter_kv_map.rs | 2 +- tests/ui/iter_next_slice.fixed | 2 +- tests/ui/iter_next_slice.rs | 2 +- tests/ui/iter_nth.rs | 2 +- tests/ui/iter_nth_zero.fixed | 2 +- tests/ui/iter_nth_zero.rs | 2 +- tests/ui/iter_on_empty_collections.fixed | 2 +- tests/ui/iter_on_empty_collections.rs | 2 +- tests/ui/iter_on_single_items.fixed | 2 +- tests/ui/iter_on_single_items.rs | 2 +- tests/ui/iter_overeager_cloned.fixed | 2 +- tests/ui/iter_overeager_cloned.rs | 2 +- tests/ui/iter_skip_next.fixed | 4 +- tests/ui/iter_skip_next.rs | 4 +- tests/ui/iter_with_drain.fixed | 2 +- tests/ui/iter_with_drain.rs | 2 +- tests/ui/large_const_arrays.fixed | 2 +- tests/ui/large_const_arrays.rs | 2 +- tests/ui/large_digit_groups.fixed | 2 +- tests/ui/large_digit_groups.rs | 2 +- tests/ui/large_enum_variant.rs | 2 +- tests/ui/large_types_passed_by_value.rs | 4 +- tests/ui/len_zero.fixed | 6 +- tests/ui/len_zero.rs | 6 +- tests/ui/len_zero.stderr | 16 +- tests/ui/len_zero_ranges.fixed | 2 +- tests/ui/len_zero_ranges.rs | 2 +- tests/ui/let_underscore_untyped.rs | 5 + tests/ui/let_underscore_untyped.stderr | 20 +- tests/ui/let_unit.fixed | 2 +- tests/ui/let_unit.rs | 2 +- tests/ui/lines_filter_map_ok.fixed | 2 +- tests/ui/lines_filter_map_ok.rs | 2 +- tests/ui/lossy_float_literal.fixed | 2 +- tests/ui/lossy_float_literal.rs | 2 +- tests/ui/macro_use_imports.fixed | 10 +- tests/ui/macro_use_imports.rs | 10 +- tests/ui/macro_use_imports_expect.rs | 8 +- tests/ui/manual_assert.edition2018.fixed | 8 +- tests/ui/manual_assert.edition2021.fixed | 8 +- tests/ui/manual_assert.rs | 8 +- tests/ui/manual_async_fn.fixed | 2 +- tests/ui/manual_async_fn.rs | 2 +- tests/ui/manual_bits.fixed | 2 +- tests/ui/manual_bits.rs | 2 +- tests/ui/manual_filter.fixed | 2 +- tests/ui/manual_filter.rs | 2 +- tests/ui/manual_filter_map.fixed | 2 +- tests/ui/manual_filter_map.rs | 2 +- tests/ui/manual_find_fixable.fixed | 2 +- tests/ui/manual_find_fixable.rs | 2 +- tests/ui/manual_find_map.fixed | 2 +- tests/ui/manual_find_map.rs | 2 +- tests/ui/manual_instant_elapsed.fixed | 2 +- tests/ui/manual_instant_elapsed.rs | 2 +- tests/ui/manual_is_ascii_check.fixed | 2 +- tests/ui/manual_is_ascii_check.rs | 2 +- tests/ui/manual_main_separator_str.fixed | 2 +- tests/ui/manual_main_separator_str.rs | 2 +- tests/ui/manual_map_option.fixed | 2 +- tests/ui/manual_map_option.rs | 2 +- tests/ui/manual_map_option_2.fixed | 2 +- tests/ui/manual_map_option_2.rs | 2 +- tests/ui/manual_ok_or.fixed | 2 +- tests/ui/manual_ok_or.rs | 2 +- tests/ui/manual_rem_euclid.fixed | 4 +- tests/ui/manual_rem_euclid.rs | 4 +- tests/ui/manual_retain.fixed | 2 +- tests/ui/manual_retain.rs | 2 +- tests/ui/manual_saturating_arithmetic.fixed | 2 +- tests/ui/manual_saturating_arithmetic.rs | 2 +- tests/ui/manual_slice_size_calculation.fixed | 46 +++ tests/ui/manual_slice_size_calculation.rs | 10 + tests/ui/manual_slice_size_calculation.stderr | 41 ++- tests/ui/manual_split_once.fixed | 2 +- tests/ui/manual_split_once.rs | 2 +- tests/ui/manual_str_repeat.fixed | 2 +- tests/ui/manual_str_repeat.rs | 2 +- tests/ui/manual_string_new.fixed | 2 +- tests/ui/manual_string_new.rs | 2 +- tests/ui/manual_unwrap_or.fixed | 2 +- tests/ui/manual_unwrap_or.rs | 2 +- tests/ui/map_clone.fixed | 2 +- tests/ui/map_clone.rs | 2 +- tests/ui/map_collect_result_unit.fixed | 2 +- tests/ui/map_collect_result_unit.rs | 2 +- tests/ui/map_flatten_fixable.fixed | 2 +- tests/ui/map_flatten_fixable.rs | 2 +- tests/ui/map_identity.fixed | 2 +- tests/ui/map_identity.rs | 2 +- tests/ui/map_unwrap_or.rs | 2 +- tests/ui/map_unwrap_or_fixable.fixed | 4 +- tests/ui/map_unwrap_or_fixable.rs | 4 +- tests/ui/match_as_ref.fixed | 2 +- tests/ui/match_as_ref.rs | 2 +- tests/ui/match_expr_like_matches_macro.fixed | 2 +- tests/ui/match_expr_like_matches_macro.rs | 2 +- tests/ui/match_ref_pats.fixed | 2 +- tests/ui/match_ref_pats.rs | 2 +- tests/ui/match_result_ok.fixed | 2 +- tests/ui/match_result_ok.rs | 2 +- tests/ui/match_single_binding.fixed | 2 +- tests/ui/match_single_binding.rs | 2 +- tests/ui/match_single_binding2.fixed | 2 +- tests/ui/match_single_binding2.rs | 2 +- tests/ui/match_str_case_mismatch.fixed | 2 +- tests/ui/match_str_case_mismatch.rs | 2 +- .../match_wildcard_for_single_variants.fixed | 2 +- .../ui/match_wildcard_for_single_variants.rs | 2 +- tests/ui/mem_replace.fixed | 2 +- tests/ui/mem_replace.rs | 2 +- tests/ui/mem_replace_macro.rs | 2 +- tests/ui/methods.rs | 2 +- tests/ui/methods_fixable.fixed | 2 +- tests/ui/methods_fixable.rs | 2 +- tests/ui/mismatched_target_os_non_unix.fixed | 2 +- tests/ui/mismatched_target_os_non_unix.rs | 2 +- tests/ui/mismatched_target_os_unix.fixed | 2 +- tests/ui/mismatched_target_os_unix.rs | 2 +- .../ui/missing_const_for_fn/cant_be_const.rs | 4 +- tests/ui/missing_doc.rs | 4 +- tests/ui/missing_doc_impl.rs | 2 +- tests/ui/missing_spin_loop.fixed | 2 +- tests/ui/missing_spin_loop.rs | 2 +- tests/ui/missing_spin_loop_no_std.fixed | 2 +- tests/ui/missing_spin_loop_no_std.rs | 2 +- tests/ui/mistyped_literal_suffix.fixed | 4 +- tests/ui/mistyped_literal_suffix.rs | 4 +- tests/ui/module_name_repetitions.rs | 2 +- tests/ui/multiple_unsafe_ops_per_block.rs | 2 +- tests/ui/must_use_candidates.fixed | 2 +- tests/ui/must_use_candidates.rs | 2 +- tests/ui/must_use_unit.fixed | 4 +- tests/ui/must_use_unit.rs | 4 +- tests/ui/mut_mut.rs | 2 +- tests/ui/mut_mutex_lock.fixed | 2 +- tests/ui/mut_mutex_lock.rs | 2 +- tests/ui/needless_arbitrary_self_type.fixed | 2 +- tests/ui/needless_arbitrary_self_type.rs | 2 +- .../needless_arbitrary_self_type_unfixable.rs | 2 +- ...dless_arbitrary_self_type_unfixable.stderr | 2 +- tests/ui/needless_bitwise_bool.fixed | 2 +- tests/ui/needless_bitwise_bool.rs | 2 +- tests/ui/needless_bool/fixable.fixed | 2 +- tests/ui/needless_bool/fixable.rs | 2 +- tests/ui/needless_borrow.fixed | 2 +- tests/ui/needless_borrow.rs | 2 +- tests/ui/needless_borrowed_ref.fixed | 2 +- tests/ui/needless_borrowed_ref.rs | 2 +- tests/ui/needless_collect.fixed | 2 +- tests/ui/needless_collect.rs | 2 +- tests/ui/needless_for_each_fixable.fixed | 2 +- tests/ui/needless_for_each_fixable.rs | 2 +- tests/ui/needless_late_init.fixed | 4 +- tests/ui/needless_late_init.rs | 4 +- tests/ui/needless_lifetimes.fixed | 4 +- tests/ui/needless_lifetimes.rs | 4 +- tests/ui/needless_match.fixed | 2 +- tests/ui/needless_match.rs | 2 +- tests/ui/needless_option_as_deref.fixed | 2 +- tests/ui/needless_option_as_deref.rs | 2 +- tests/ui/needless_option_take.fixed | 2 +- tests/ui/needless_option_take.rs | 2 +- .../needless_parens_on_range_literals.fixed | 4 +- tests/ui/needless_parens_on_range_literals.rs | 4 +- tests/ui/needless_question_mark.fixed | 2 +- tests/ui/needless_question_mark.rs | 2 +- tests/ui/needless_return.fixed | 2 +- tests/ui/needless_return.rs | 2 +- tests/ui/needless_splitn.fixed | 4 +- tests/ui/needless_splitn.rs | 4 +- tests/ui/neg_multiply.fixed | 2 +- tests/ui/neg_multiply.rs | 2 +- tests/ui/non_octal_unix_permissions.fixed | 4 +- tests/ui/non_octal_unix_permissions.rs | 4 +- tests/ui/nonminimal_bool_methods.fixed | 2 +- tests/ui/nonminimal_bool_methods.rs | 2 +- tests/ui/numbered_fields.fixed | 2 +- tests/ui/numbered_fields.rs | 2 +- tests/ui/obfuscated_if_else.fixed | 2 +- tests/ui/obfuscated_if_else.rs | 2 +- tests/ui/octal_escapes.rs | 1 + tests/ui/octal_escapes.stderr | 18 +- tests/ui/option_as_ref_deref.fixed | 2 +- tests/ui/option_as_ref_deref.rs | 2 +- tests/ui/option_env_unwrap.rs | 2 +- tests/ui/option_filter_map.fixed | 2 +- tests/ui/option_filter_map.rs | 2 +- tests/ui/option_if_let_else.fixed | 2 +- tests/ui/option_if_let_else.rs | 2 +- tests/ui/option_map_or_none.fixed | 2 +- tests/ui/option_map_or_none.rs | 2 +- tests/ui/option_map_unit_fn_fixable.fixed | 2 +- tests/ui/option_map_unit_fn_fixable.rs | 2 +- tests/ui/or_fun_call.fixed | 2 +- tests/ui/or_fun_call.rs | 2 +- tests/ui/or_then_unwrap.fixed | 2 +- tests/ui/or_then_unwrap.rs | 2 +- tests/ui/partialeq_to_none.fixed | 2 +- tests/ui/partialeq_to_none.rs | 2 +- tests/ui/path_buf_push_overwrite.fixed | 2 +- tests/ui/path_buf_push_overwrite.rs | 2 +- tests/ui/patterns.fixed | 2 +- tests/ui/patterns.rs | 2 +- tests/ui/precedence.fixed | 2 +- tests/ui/precedence.rs | 2 +- tests/ui/print_stdout_build_script.rs | 2 +- tests/ui/print_with_newline.rs | 2 +- tests/ui/println_empty_string.fixed | 2 +- tests/ui/println_empty_string.rs | 2 +- tests/ui/ptr_as_ptr.fixed | 4 +- tests/ui/ptr_as_ptr.rs | 4 +- tests/ui/ptr_eq.fixed | 2 +- tests/ui/ptr_eq.rs | 2 +- tests/ui/ptr_offset_with_cast.fixed | 2 +- tests/ui/ptr_offset_with_cast.rs | 2 +- tests/ui/question_mark.fixed | 2 +- tests/ui/question_mark.rs | 2 +- tests/ui/range_contains.fixed | 2 +- tests/ui/range_contains.rs | 2 +- tests/ui/range_plus_minus_one.fixed | 2 +- tests/ui/range_plus_minus_one.rs | 2 +- tests/ui/rc_buffer.fixed | 2 +- tests/ui/rc_buffer.rs | 2 +- tests/ui/rc_buffer_arc.fixed | 2 +- tests/ui/rc_buffer_arc.rs | 2 +- tests/ui/redundant_allocation_fixable.fixed | 2 +- tests/ui/redundant_allocation_fixable.rs | 2 +- tests/ui/redundant_async_block.fixed | 2 +- tests/ui/redundant_async_block.rs | 2 +- tests/ui/redundant_clone.fixed | 2 +- tests/ui/redundant_clone.rs | 2 +- tests/ui/redundant_closure_call_fixable.fixed | 2 +- tests/ui/redundant_closure_call_fixable.rs | 2 +- tests/ui/redundant_field_names.fixed | 2 +- tests/ui/redundant_field_names.rs | 2 +- ...edundant_pattern_matching_drop_order.fixed | 2 +- .../redundant_pattern_matching_drop_order.rs | 2 +- .../redundant_pattern_matching_ipaddr.fixed | 2 +- tests/ui/redundant_pattern_matching_ipaddr.rs | 2 +- .../redundant_pattern_matching_option.fixed | 2 +- tests/ui/redundant_pattern_matching_option.rs | 2 +- .../ui/redundant_pattern_matching_poll.fixed | 2 +- tests/ui/redundant_pattern_matching_poll.rs | 2 +- .../redundant_pattern_matching_result.fixed | 2 +- tests/ui/redundant_pattern_matching_result.rs | 2 +- tests/ui/redundant_pub_crate.fixed | 2 +- tests/ui/redundant_pub_crate.rs | 2 +- tests/ui/redundant_slicing.fixed | 2 +- tests/ui/redundant_slicing.rs | 2 +- tests/ui/redundant_static_lifetimes.fixed | 2 +- tests/ui/redundant_static_lifetimes.rs | 2 +- tests/ui/rename.fixed | 2 +- tests/ui/rename.rs | 2 +- tests/ui/renamed_builtin_attr.fixed | 2 +- tests/ui/renamed_builtin_attr.rs | 2 +- tests/ui/repeat_once.fixed | 2 +- tests/ui/repeat_once.rs | 2 +- tests/ui/result_map_or_into_option.fixed | 2 +- tests/ui/result_map_or_into_option.rs | 2 +- tests/ui/result_map_unit_fn_fixable.fixed | 2 +- tests/ui/result_map_unit_fn_fixable.rs | 2 +- tests/ui/reversed_empty_ranges_fixable.fixed | 2 +- tests/ui/reversed_empty_ranges_fixable.rs | 2 +- .../reversed_empty_ranges_loops_fixable.fixed | 2 +- .../ui/reversed_empty_ranges_loops_fixable.rs | 2 +- tests/ui/same_functions_in_if_condition.rs | 2 +- .../ui/same_functions_in_if_condition.stderr | 6 +- tests/ui/search_is_some.rs | 2 +- tests/ui/search_is_some_fixable_none.fixed | 2 +- tests/ui/search_is_some_fixable_none.rs | 2 +- tests/ui/search_is_some_fixable_some.fixed | 2 +- tests/ui/search_is_some_fixable_some.rs | 2 +- tests/ui/seek_from_current.fixed | 2 +- tests/ui/seek_from_current.rs | 2 +- .../ui/seek_to_start_instead_of_rewind.fixed | 2 +- tests/ui/seek_to_start_instead_of_rewind.rs | 2 +- tests/ui/semicolon_inside_block.fixed | 2 +- tests/ui/semicolon_inside_block.rs | 2 +- tests/ui/semicolon_outside_block.fixed | 2 +- tests/ui/semicolon_outside_block.rs | 2 +- tests/ui/shadow.rs | 7 + tests/ui/shadow.stderr | 92 +++--- tests/ui/short_circuit_statement.fixed | 2 +- tests/ui/short_circuit_statement.rs | 2 +- tests/ui/significant_drop_in_scrutinee.rs | 2 +- tests/ui/significant_drop_tightening.fixed | 2 +- tests/ui/significant_drop_tightening.rs | 2 +- tests/ui/single_char_add_str.fixed | 2 +- tests/ui/single_char_add_str.rs | 2 +- tests/ui/single_char_pattern.fixed | 2 +- tests/ui/single_char_pattern.rs | 2 +- tests/ui/single_component_path_imports.fixed | 2 +- tests/ui/single_component_path_imports.rs | 2 +- tests/ui/single_element_loop.fixed | 2 +- tests/ui/single_element_loop.rs | 2 +- tests/ui/single_match_else.rs | 2 +- tests/ui/skip_while_next.rs | 2 +- tests/ui/stable_sort_primitive.fixed | 2 +- tests/ui/stable_sort_primitive.rs | 2 +- tests/ui/starts_ends_with.fixed | 2 +- tests/ui/starts_ends_with.rs | 2 +- tests/ui/string_add.rs | 2 +- tests/ui/string_add_assign.fixed | 2 +- tests/ui/string_add_assign.rs | 2 +- tests/ui/string_extend.fixed | 2 +- tests/ui/string_extend.rs | 2 +- tests/ui/string_from_utf8_as_bytes.fixed | 2 +- tests/ui/string_from_utf8_as_bytes.rs | 2 +- tests/ui/string_lit_as_bytes.fixed | 2 +- tests/ui/string_lit_as_bytes.rs | 2 +- tests/ui/strlen_on_c_strings.fixed | 2 +- tests/ui/strlen_on_c_strings.rs | 2 +- tests/ui/suspicious_doc_comments.fixed | 2 +- tests/ui/suspicious_doc_comments.rs | 2 +- tests/ui/suspicious_else_formatting.rs | 2 +- tests/ui/suspicious_operation_groupings.fixed | 2 +- tests/ui/suspicious_operation_groupings.rs | 2 +- tests/ui/swap.fixed | 4 +- tests/ui/swap.rs | 4 +- tests/ui/swap_ptr_to_ref.fixed | 2 +- tests/ui/swap_ptr_to_ref.rs | 2 +- tests/ui/tabs_in_doc_comments.fixed | 2 +- tests/ui/tabs_in_doc_comments.rs | 2 +- tests/ui/tests_outside_test_module.rs | 2 +- tests/ui/to_digit_is_some.fixed | 2 +- tests/ui/to_digit_is_some.rs | 2 +- tests/ui/toplevel_ref_arg.fixed | 4 +- tests/ui/toplevel_ref_arg.rs | 4 +- tests/ui/toplevel_ref_arg_non_rustfix.rs | 2 +- tests/ui/track-diagnostics.rs | 5 +- tests/ui/trait_duplication_in_bounds.fixed | 2 +- tests/ui/trait_duplication_in_bounds.rs | 2 +- tests/ui/transmute_32bit.rs | 2 +- tests/ui/transmute_32bit.stderr | 29 +- tests/ui/transmute_64bit.rs | 2 +- tests/ui/transmute_ptr_to_ref.fixed | 2 +- tests/ui/transmute_ptr_to_ref.rs | 2 +- .../transmutes_expressible_as_ptr_casts.fixed | 2 +- .../ui/transmutes_expressible_as_ptr_casts.rs | 2 +- tests/ui/trim_split_whitespace.fixed | 2 +- tests/ui/trim_split_whitespace.rs | 2 +- tests/ui/trivially_copy_pass_by_ref.rs | 4 +- tests/ui/try_err.fixed | 4 +- tests/ui/try_err.rs | 4 +- tests/ui/types.fixed | 2 +- tests/ui/types.rs | 2 +- tests/ui/unchecked_duration_subtraction.fixed | 2 +- tests/ui/unchecked_duration_subtraction.rs | 2 +- tests/ui/undocumented_unsafe_blocks.rs | 2 +- tests/ui/unicode.fixed | 4 +- tests/ui/unicode.rs | 4 +- tests/ui/uninlined_format_args.fixed | 4 +- tests/ui/uninlined_format_args.rs | 4 +- ...nlined_format_args_panic.edition2018.fixed | 8 +- ...nlined_format_args_panic.edition2021.fixed | 8 +- tests/ui/uninlined_format_args_panic.rs | 8 +- tests/ui/unit_arg.rs | 2 +- tests/ui/unit_arg_empty_blocks.fixed | 2 +- tests/ui/unit_arg_empty_blocks.rs | 2 +- tests/ui/unknown_clippy_lints.fixed | 2 +- tests/ui/unknown_clippy_lints.rs | 2 +- tests/ui/unnecessary_box_returns.rs | 10 + tests/ui/unnecessary_cast.fixed | 2 +- tests/ui/unnecessary_cast.rs | 2 +- tests/ui/unnecessary_fold.fixed | 2 +- tests/ui/unnecessary_fold.rs | 2 +- tests/ui/unnecessary_iter_cloned.fixed | 2 +- tests/ui/unnecessary_iter_cloned.rs | 2 +- tests/ui/unnecessary_join.fixed | 2 +- tests/ui/unnecessary_join.rs | 2 +- tests/ui/unnecessary_lazy_eval.fixed | 4 +- tests/ui/unnecessary_lazy_eval.rs | 4 +- tests/ui/unnecessary_operation.fixed | 2 +- tests/ui/unnecessary_operation.rs | 2 +- .../ui/unnecessary_owned_empty_strings.fixed | 2 +- tests/ui/unnecessary_owned_empty_strings.rs | 2 +- tests/ui/unnecessary_self_imports.fixed | 2 +- tests/ui/unnecessary_self_imports.rs | 2 +- tests/ui/unnecessary_sort_by.fixed | 2 +- tests/ui/unnecessary_sort_by.rs | 2 +- .../unnecessary_struct_initialization.fixed | 2 +- tests/ui/unnecessary_struct_initialization.rs | 2 +- tests/ui/unnecessary_to_owned.fixed | 2 +- tests/ui/unnecessary_to_owned.rs | 2 +- tests/ui/unnecessary_unsafety_doc.rs | 2 +- tests/ui/unneeded_wildcard_pattern.fixed | 2 +- tests/ui/unneeded_wildcard_pattern.rs | 2 +- tests/ui/unnested_or_patterns.fixed | 2 +- tests/ui/unnested_or_patterns.rs | 2 +- tests/ui/unnested_or_patterns2.fixed | 2 +- tests/ui/unnested_or_patterns2.rs | 2 +- tests/ui/unreadable_literal.fixed | 2 +- tests/ui/unreadable_literal.rs | 2 +- tests/ui/unseparated_prefix_literals.fixed | 4 +- tests/ui/unseparated_prefix_literals.rs | 4 +- tests/ui/unused_rounding.fixed | 2 +- tests/ui/unused_rounding.rs | 2 +- tests/ui/unused_unit.fixed | 2 +- tests/ui/unused_unit.rs | 2 +- tests/ui/unwrap_or_else_default.fixed | 2 +- tests/ui/unwrap_or_else_default.rs | 2 +- tests/ui/use_self.fixed | 4 +- tests/ui/use_self.rs | 4 +- tests/ui/use_self_trait.fixed | 2 +- tests/ui/use_self_trait.rs | 2 +- tests/ui/used_underscore_binding.rs | 2 +- tests/ui/useless_asref.fixed | 2 +- tests/ui/useless_asref.rs | 2 +- tests/ui/useless_attribute.fixed | 4 +- tests/ui/useless_attribute.rs | 4 +- tests/ui/useless_conversion.fixed | 2 +- tests/ui/useless_conversion.rs | 2 +- tests/ui/vec.fixed | 2 +- tests/ui/vec.rs | 2 +- tests/ui/vec_box_sized.fixed | 2 +- tests/ui/vec_box_sized.rs | 2 +- tests/ui/while_let_on_iterator.fixed | 2 +- tests/ui/while_let_on_iterator.rs | 2 +- tests/ui/wildcard_enum_match_arm.fixed | 4 +- tests/ui/wildcard_enum_match_arm.rs | 4 +- tests/ui/wildcard_imports.fixed | 6 +- tests/ui/wildcard_imports.rs | 6 +- .../wildcard_imports_2021.edition2018.fixed | 10 +- .../wildcard_imports_2021.edition2021.fixed | 10 +- tests/ui/wildcard_imports_2021.rs | 10 +- tests/ui/wildcard_imports_2021.stderr | 132 --------- tests/ui/write_with_newline.rs | 4 +- tests/ui/write_with_newline.stderr | 6 +- tests/ui/writeln_empty_string.fixed | 2 +- tests/ui/writeln_empty_string.rs | 2 +- tests/ui/zero_ptr.fixed | 2 +- tests/ui/zero_ptr.rs | 2 +- tests/ui/zero_ptr_no_std.fixed | 2 +- tests/ui/zero_ptr_no_std.rs | 2 +- 783 files changed, 2304 insertions(+), 1400 deletions(-) create mode 100644 book/src/development/lint_passes.md create mode 100644 book/src/development/macro_expansions.md create mode 100644 clippy_lints/src/items_after_test_module.rs create mode 100644 tests/ui/items_after_test_module.rs create mode 100644 tests/ui/items_after_test_module.stderr create mode 100644 tests/ui/manual_slice_size_calculation.fixed delete mode 100644 tests/ui/wildcard_imports_2021.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 559b560dde4ba..d7102d2474ef4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,11 +6,126 @@ document. ## Unreleased / Beta / In Rust Nightly -[7f27e2e7...master](https://github.com/rust-lang/rust-clippy/compare/7f27e2e7...master) +[149392b0...master](https://github.com/rust-lang/rust-clippy/compare/149392b0...master) + +## Rust 1.69 + +Current stable, released 2023-04-20 + +[7f27e2e7...149392b0](https://github.com/rust-lang/rust-clippy/compare/7f27e2e7...149392b0) + +### New Lints + +* [`no_mangle_with_rust_abi`] + [#10369](https://github.com/rust-lang/rust-clippy/pull/10369) +* [`significant_drop_tightening`] + [#10163](https://github.com/rust-lang/rust-clippy/pull/10163) +* [`suspicious_command_arg_space`] + [#10317](https://github.com/rust-lang/rust-clippy/pull/10317) +* [`let_underscore_untyped`] + [#10356](https://github.com/rust-lang/rust-clippy/pull/10356) +* [`question_mark_used`] + [#10342](https://github.com/rust-lang/rust-clippy/pull/10342) +* [`extra_unused_type_parameters`] + [#10028](https://github.com/rust-lang/rust-clippy/pull/10028) +* [`impl_trait_in_params`] + [10197](https://github.com/rust-lang/rust-clippy/pull/10197) +* [`transmute_int_to_non_zero`] + [#10360](https://github.com/rust-lang/rust-clippy/pull/10360) +* [`multiple_unsafe_ops_per_block`] + [#10206](https://github.com/rust-lang/rust-clippy/pull/10206) + +### Moves and Deprecations + +* Moved [`uninlined_format_args`] to `pedantic` (Now allow-by-default) + [#10265](https://github.com/rust-lang/rust-clippy/pull/10265) +* Moved [`unchecked_duration_subtraction`] to `pedantic` (Now allow-by-default) + [#10194](https://github.com/rust-lang/rust-clippy/pull/10194) + +### Enhancements + +* [`arithmetic_side_effects`]: No longer lints, if safe constant values are used. + [#10310](https://github.com/rust-lang/rust-clippy/pull/10310) +* [`needless_lifetimes`]: Now works in local macros + [#10257](https://github.com/rust-lang/rust-clippy/pull/10257) +* [`unused_io_amount`]: Now detects usages of `is_ok` and `is_err` + [#10225](https://github.com/rust-lang/rust-clippy/pull/10225) +* [`missing_docs_in_private_items`]: Added new configuration `missing-docs-in-crate-items` to lint + on items visible within the current crate. For example, `pub(crate)` items. + [#10303](https://github.com/rust-lang/rust-clippy/pull/10303) +* [`almost_swapped`]: Now detects almost swaps using `let` statements + [#10177](https://github.com/rust-lang/rust-clippy/pull/10177) +* [`wildcard_enum_match_arm`]: Now lints missing private variants, for local enums + [#10250](https://github.com/rust-lang/rust-clippy/pull/10250) + +### False Positive Fixes + +* [`explicit_auto_deref`]: Now considers projections, when determining if auto deref is applicable + [#10386](https://github.com/rust-lang/rust-clippy/pull/10386) +* [`manual_let_else`]: Now considers side effects of branches, before linting + [#10336](https://github.com/rust-lang/rust-clippy/pull/10336) +* [`uninlined_format_args`]: No longer lints for arguments with generic parameters + [#10343](https://github.com/rust-lang/rust-clippy/pull/10343) +* [`needless_lifetimes`]: No longer lints signatures in macros, if the lifetime is a metavariable + [#10380](https://github.com/rust-lang/rust-clippy/pull/10380) +* [`len_without_is_empty`]: No longer lints, if `len` as a non-default signature + [#10255](https://github.com/rust-lang/rust-clippy/pull/10255) +* [`unusual_byte_groupings`]: Relaxed the required restrictions for specific sizes, to reduce false + positives + [#10353](https://github.com/rust-lang/rust-clippy/pull/10353) +* [`manual_let_else`]: No longer lints `if-else` blocks if they can divergent + [#10332](https://github.com/rust-lang/rust-clippy/pull/10332) +* [`expect_used`], [`unwrap_used`], [`dbg_macro`], [`print_stdout`], [`print_stderr`]: No longer lint + in test functions, if `allow-expect-in-tests` is set + [#10391](https://github.com/rust-lang/rust-clippy/pull/10391) +* [`unnecessary_safety_comment`]: No longer lints code inside macros + [#10106](https://github.com/rust-lang/rust-clippy/pull/10106) +* [`never_loop`]: No longer lints, for statements following break statements for outer blocks. + [#10311](https://github.com/rust-lang/rust-clippy/pull/10311) + +### Suggestion Fixes/Improvements + +* [`box_default`]: The suggestion now includes the type for trait objects, when needed + [#10382](https://github.com/rust-lang/rust-clippy/pull/10382) +* [`cast_possible_truncation`]: Now suggests using `try_from` or allowing the lint + [#10038](https://github.com/rust-lang/rust-clippy/pull/10038) +* [`invalid_regex`]: Regex errors for non-literals or regular strings containing escape sequences will + now show the complete error + [#10231](https://github.com/rust-lang/rust-clippy/pull/10231) +* [`transmutes_expressible_as_ptr_casts`]: The suggestion now works, if the base type is borrowed + [#10193](https://github.com/rust-lang/rust-clippy/pull/10193) +* [`needless_return`]: Now removes all semicolons on the same line + [#10187](https://github.com/rust-lang/rust-clippy/pull/10187) +* [`suspicious_to_owned`]: The suggestion now shows all options clearly + [#10295](https://github.com/rust-lang/rust-clippy/pull/10295) +* [`bytes_nth`]: Now suggests the correct replacement based on the context + [#10361](https://github.com/rust-lang/rust-clippy/pull/10361) +* [`bool_assert_comparison`]: The suggestion is now machine applicable + [#10218](https://github.com/rust-lang/rust-clippy/pull/10218) +* [`cast_possible_truncation`]: Corrected the lint name in the help message + [#10330](https://github.com/rust-lang/rust-clippy/pull/10330) +* [`needless_return`]: The suggestion now works on if sequences + [#10345](https://github.com/rust-lang/rust-clippy/pull/10345) +* [`needless_lifetimes`]: The suggestion is now machine applicable + [#10222](https://github.com/rust-lang/rust-clippy/pull/10222) +* [`map_entry`]: The suggestion no longer expands macros + [#10346](https://github.com/rust-lang/rust-clippy/pull/10346) + +### ICE Fixes + +* [`needless_pass_by_value`]: Fixed an ICE, caused by how late bounds were handled + [#10328](https://github.com/rust-lang/rust-clippy/pull/10328) +* [`needless_borrow`]: No longer panics on ambiguous projections + [#10403](https://github.com/rust-lang/rust-clippy/pull/10403) + +### Documentation Improvements + +* All configurations are now documented in the Clippy Book + [#10199](https://github.com/rust-lang/rust-clippy/pull/10199) ## Rust 1.68 -Current stable, released 2023-03-09 +Released 2023-03-09 [d822110d...7f27e2e7](https://github.com/rust-lang/rust-clippy/compare/d822110d...7f27e2e7) @@ -4615,6 +4730,7 @@ Released 2018-09-13 [`invisible_characters`]: https://rust-lang.github.io/rust-clippy/master/index.html#invisible_characters [`is_digit_ascii_radix`]: https://rust-lang.github.io/rust-clippy/master/index.html#is_digit_ascii_radix [`items_after_statements`]: https://rust-lang.github.io/rust-clippy/master/index.html#items_after_statements +[`items_after_test_module`]: https://rust-lang.github.io/rust-clippy/master/index.html#items_after_test_module [`iter_cloned_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_cloned_collect [`iter_count`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_count [`iter_kv_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_kv_map diff --git a/Cargo.toml b/Cargo.toml index c35dfcbd8c445..4db15ddb2835c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,13 +22,12 @@ path = "src/driver.rs" [dependencies] clippy_lints = { path = "clippy_lints" } -semver = "1.0" rustc_tools_util = "0.3.0" tempfile = { version = "3.2", optional = true } termize = "0.1" [dev-dependencies] -compiletest_rs = { version = "0.9", features = ["tmp"] } +compiletest_rs = { version = "0.10", features = ["tmp"] } tester = "0.9" regex = "1.5" toml = "0.5" @@ -49,7 +48,7 @@ if_chain = "1.0" itertools = "0.10.1" quote = "1.0" serde = { version = "1.0.125", features = ["derive"] } -syn = { version = "1.0", features = ["full"] } +syn = { version = "2.0", features = ["full"] } futures = "0.3" parking_lot = "0.12" tokio = { version = "1", features = ["io-util"] } diff --git a/book/src/SUMMARY.md b/book/src/SUMMARY.md index cbd73376dfa07..22fbdce75e8f8 100644 --- a/book/src/SUMMARY.md +++ b/book/src/SUMMARY.md @@ -13,7 +13,9 @@ - [Development](development/README.md) - [Basics](development/basics.md) - [Adding Lints](development/adding_lints.md) + - [Lint Passes](development/lint_passes.md) - [Type Checking](development/type_checking.md) + - [Macro Expansions](development/macro_expansions.md) - [Common Tools](development/common_tools_writing_lints.md) - [Infrastructure](development/infrastructure/README.md) - [Syncing changes between Clippy and rust-lang/rust](development/infrastructure/sync.md) diff --git a/book/src/development/README.md b/book/src/development/README.md index 616e6d182b729..8f09f66f59586 100644 --- a/book/src/development/README.md +++ b/book/src/development/README.md @@ -13,6 +13,24 @@ If this is your first time contributing to Clippy, you should first read the [Basics docs](basics.md). This will explain the basics on how to get the source code and how to compile and test the code. +## Additional Readings for Beginners + +If a dear reader of this documentation has never taken a class on compilers +and interpreters, it might be confusing as to why AST level deals with only +the language's syntax. And some readers might not even understand what lexing, +parsing, and AST mean. + +This documentation serves by no means as a crash course on compilers or language design. +And for details specifically related to Rust, the [Rustc Development Guide][rustc_dev_guide] +is a far better choice to peruse. + +The [Syntax and AST][ast] chapter and the [High-Level IR][hir] chapter are +great introduction to the concepts mentioned in this chapter. + +Some readers might also find the [introductory chapter][map_of_territory] of +Robert Nystrom's _Crafting Interpreters_ a helpful overview of compiled and +interpreted languages before jumping back to the Rustc guide. + ## Writing code If you have done the basic setup, it's time to start hacking. @@ -37,6 +55,10 @@ book](../lints.md). > - Triage procedure > - Bors and Homu +[ast]: https://rustc-dev-guide.rust-lang.org/syntax-intro.html +[hir]: https://rustc-dev-guide.rust-lang.org/hir.html +[rustc_dev_guide]: https://rustc-dev-guide.rust-lang.org/ +[map_of_territory]: https://craftinginterpreters.com/a-map-of-the-territory.html [clippy_rfc]: https://github.com/rust-lang/rfcs/blob/master/text/2476-clippy-uno.md [rfc_stability]: https://github.com/rust-lang/rfcs/blob/master/text/2476-clippy-uno.md#stability-guarantees [rfc_lint_cats]: https://github.com/rust-lang/rfcs/blob/master/text/2476-clippy-uno.md#lint-audit-and-categories diff --git a/book/src/development/adding_lints.md b/book/src/development/adding_lints.md index 9dacaaaae5c92..ccae8d3742018 100644 --- a/book/src/development/adding_lints.md +++ b/book/src/development/adding_lints.md @@ -164,7 +164,7 @@ The process of generating the `.stderr` file is the same, and prepending the ## Rustfix tests If the lint you are working on is making use of structured suggestions, the test -file should include a `// run-rustfix` comment at the top. This will +file should include a `//@run-rustfix` comment at the top. This will additionally run [rustfix] for that test. Rustfix will apply the suggestions from the lint to the code of the test file and compare that to the contents of a `.fixed` file. diff --git a/book/src/development/lint_passes.md b/book/src/development/lint_passes.md new file mode 100644 index 0000000000000..c41b6ea0de8fe --- /dev/null +++ b/book/src/development/lint_passes.md @@ -0,0 +1,114 @@ +# Lint passes + +Before working on the logic of a new lint, there is an important decision +that every Clippy developer must make: to use +[`EarlyLintPass`][early_lint_pass] or [`LateLintPass`][late_lint_pass]. + +In short, the `LateLintPass` has access to type and symbol information while the +`EarlyLintPass` doesn't. If you don't need access to type information, use the +`EarlyLintPass`. + +Let us expand on these two traits more below. + +## `EarlyLintPass` + +If you examine the documentation on [`EarlyLintPass`][early_lint_pass] closely, +you'll see that every method defined for this trait utilizes a +[`EarlyContext`][early_context]. In `EarlyContext`'s documentation, it states: + +> Context for lint checking of the AST, after expansion, before lowering to HIR. + +Voilà. `EarlyLintPass` works only on the Abstract Syntax Tree (AST) level. +And AST is generated during the [lexing and parsing][lexing_and_parsing] phase +of code compilation. Therefore, it doesn't know what a symbol means or information about types, and it should +be our trait choice for a new lint if the lint only deals with syntax-related issues. + +While linting speed has not been a concern for Clippy, +the `EarlyLintPass` is faster, and it should be your choice +if you know for sure a lint does not need type information. + +As a reminder, run the following command to generate boilerplate for lints +that use `EarlyLintPass`: + +```sh +$ cargo dev new_lint --name= --pass=early --category= +``` + +### Example for `EarlyLintPass` + +Take a look at the following code: + +```rust +let x = OurUndefinedType; +x.non_existing_method(); +``` + +From the AST perspective, both lines are "grammatically" correct. +The assignment uses a `let` and ends with a semicolon. The invocation +of a method looks fine, too. As programmers, we might raise a few +questions already, but the parser is okay with it. This is what we +mean when we say `EarlyLintPass` deals with only syntax on the AST level. + +Alternatively, think of the `foo_functions` lint we mentioned in +[define new lints](define_lints.md#name-the-lint) chapter. + +We want the `foo_functions` lint to detect functions with `foo` as their name. +Writing a lint that only checks for the name of a function means that we only +work with the AST and don't have to access the type system at all (the type system is where +`LateLintPass` comes into the picture). + +## `LateLintPass` + +In contrast to `EarlyLintPass`, `LateLintPass` contains type information. + +If you examine the documentation on [`LateLintPass`][late_lint_pass] closely, +you see that every method defined in this trait utilizes a +[`LateContext`][late_context]. + +In `LateContext`'s documentation we will find methods that +deal with type-checking, which do not exist in `EarlyContext`, such as: + +- [`maybe_typeck_results`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/context/struct.LateContext.html#method.maybe_typeck_results) +- [`typeck_results`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/context/struct.LateContext.html#method.typeck_results) + +### Example for `LateLintPass` + +Let us take a look with the following example: + +```rust +let x = OurUndefinedType; +x.non_existing_method(); +``` + +These two lines of code are syntactically correct code from the perspective +of the AST. We have an assignment and invoke a method on the variable that +is of a type. Grammatically, everything is in order for the parser. + +However, going down a level and looking at the type information, +the compiler will notice that both `OurUndefinedType` and `non_existing_method()` +**are undefined**. + +As Clippy developers, to access such type information, we must implement +`LateLintPass` on our lint. +When you browse through Clippy's lints, you will notice that almost every lint +is implemented in a `LateLintPass`, specifically because we often need to check +not only for syntactic issues but also type information. + +Another limitation of the `EarlyLintPass` is that the nodes are only identified +by their position in the AST. This means that you can't just get an `id` and +request a certain node. For most lints that is fine, but we have some lints +that require the inspection of other nodes, which is easier at the HIR level. +In these cases, `LateLintPass` is the better choice. + +As a reminder, run the following command to generate boilerplate for lints +that use `LateLintPass`: + +```sh +$ cargo dev new_lint --name= --pass=late --category= +``` + +[early_context]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/context/struct.EarlyContext.html +[early_lint_pass]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/trait.EarlyLintPass.html +[late_context]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/context/struct.LateContext.html +[late_lint_pass]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/trait.LateLintPass.html +[lexing_and_parsing]: https://rustc-dev-guide.rust-lang.org/overview.html#lexing-and-parsing diff --git a/book/src/development/macro_expansions.md b/book/src/development/macro_expansions.md new file mode 100644 index 0000000000000..c5eb000272d39 --- /dev/null +++ b/book/src/development/macro_expansions.md @@ -0,0 +1,158 @@ +# Dealing with macros and expansions + +Sometimes we might encounter Rust macro expansions while working with Clippy. +While macro expansions are not as dramatic and profound as the expansion +of our universe, they can certainly bring chaos to the orderly world +of code and logic. + +The general rule of thumb is that we should ignore code with macro +expansions when working with Clippy because the code can be dynamic +in ways that are difficult or impossible for us to foresee. + +## False Positives + +What exactly do we mean by _dynamic in ways that are difficult to foresee_? + +Macros are [expanded][expansion] in the `EarlyLintPass` level, +so the Abstract Syntax Tree (AST) is generated in place of macros. +This means the code which we work with in Clippy is already expanded. + +If we wrote a new lint, there is a possibility that the lint is +triggered in macro-generated code. Since this expanded macro code +is not written by the macro's user but really by the macro's author, +the user cannot and should not be responsible for fixing the issue +that triggers the lint. + +Besides, a [Span] in a macro can be changed by the macro author. +Therefore, any lint check related to lines or columns should be +avoided since they might be changed at any time and become unreliable +or incorrect information. + +Because of these unforeseeable or unstable behaviors, macro expansion +should often not be regarded as a part of the stable API. +This is also why most lints check if they are inside a macro or not +before emitting suggestions to the end user to avoid false positives. + +## How to Work with Macros + +Several functions are available for working with macros. + +### The `Span.from_expansion` method + +We could utilize a `span`'s [`from_expansion`] method, which +detects if the `span` is from a macro expansion / desugaring. +This is a very common first step in a lint: + +```rust +if expr.span.from_expansion() { + // We most likely want to ignore it. + return; +} +``` + +### `Span.ctxt` method + +The `span`'s context, given by the method [`ctxt`] and returning [SpanContext], +represents if the span is from a macro expansion and, if it is, which +macro call expanded this span. + +Sometimes, it is useful to check if the context of two spans are equal. +For instance, suppose we have the following line of code that would +expand into `1 + 0`: + +```rust +// The following code expands to `1 + 0` for both `EarlyLintPass` and `LateLintPass` +1 + mac!() +``` + +Assuming that we'd collect the `1` expression as a variable `left` and the +`0`/`mac!()` expression as a variable `right`, we can simply compare their +contexts. If the context is different, then we most likely are dealing with a +macro expansion and should just ignore it: + +```rust +if left.span.ctxt() != right.span.ctxt() { + // The code author most likely cannot modify this expression + return; +} +``` + +> **Note**: Code that is not from expansion is in the "root" context. +> So any spans whose `from_expansion` returns `false` can be assumed +> to have the same context. Because of this, using `span.from_expansion()` +> is often sufficient. + +Going a bit deeper, in a simple expression such as `a == b`, +`a` and `b` have the same context. +However, in a `macro_rules!` with `a == $b`, `$b` is expanded to +an expression that contains a different context from `a`. + +Take a look at the following macro `m`: + +```rust +macro_rules! m { + ($a:expr, $b:expr) => { + if $a.is_some() { + $b; + } + } +} + +let x: Option = Some(42); +m!(x, x.unwrap()); +``` + +If the `m!(x, x.unwrapp());` line is expanded, we would get two expanded +expressions: + +- `x.is_some()` (from the `$a.is_some()` line in the `m` macro) +- `x.unwrap()` (corresponding to `$b` in the `m` macro) + +Suppose `x.is_some()` expression's span is associated with the `x_is_some_span` variable +and `x.unwrap()` expression's span is associated with `x_unwrap_span` variable, +we could assume that these two spans do not share the same context: + +```rust +// x.is_some() is from inside the macro +// x.unwrap() is from outside the macro +assert_ne!(x_is_some_span.ctxt(), x_unwrap_span.ctxt()); +``` + +### The `in_external_macro` function + +`rustc_middle::lint` provides a function ([`in_external_macro`]) that can +detect if the given span is from a macro defined in a foreign crate. + +Therefore, if we really want a new lint to work with macro-generated code, +this is the next line of defense to avoid macros not defined inside +the current crate since it is unfair to the user if Clippy lints code +which the user cannot change. + +For example, assume we have the following code that is being examined +by Clippy: + +```rust +#[macro_use] +extern crate a_foreign_crate_with_macros; + +// `foo` macro is defined in `a_foreign_crate_with_macros` +foo!("bar"); +``` + +Also assume that we get the corresponding variable `foo_span` for the +`foo` macro call, we could decide not to lint if `in_external_macro` +results in `true` (note that `cx` can be `EarlyContext` or `LateContext`): + +```rust +if in_external_macro(cx.sess(), foo_span) { + // We should ignore macro from a foreign crate. + return; +} +``` + +[`ctxt`]: https://doc.rust-lang.org/stable/nightly-rustc/rustc_span/struct.Span.html#method.ctxt +[expansion]: https://rustc-dev-guide.rust-lang.org/macro-expansion.html#expansion-and-ast-integration +[`from_expansion`]: https://doc.rust-lang.org/stable/nightly-rustc/rustc_span/struct.Span.html#method.from_expansion +[`in_external_macro`]: https://doc.rust-lang.org/stable/nightly-rustc/rustc_middle/lint/fn.in_external_macro.html +[Span]: https://doc.rust-lang.org/stable/nightly-rustc/rustc_span/struct.Span.html +[SpanContext]: https://doc.rust-lang.org/stable/nightly-rustc/rustc_span/hygiene/struct.SyntaxContext.html diff --git a/book/src/development/type_checking.md b/book/src/development/type_checking.md index 5ce434b99a1a6..225de84956625 100644 --- a/book/src/development/type_checking.md +++ b/book/src/development/type_checking.md @@ -51,7 +51,7 @@ impl LateLintPass<'_> for MyStructLint { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { // Get type of `expr` let ty = cx.typeck_results().expr_ty(expr); - + // Check if the `Ty` of this expression is of character type if ty.is_char() { println!("Our expression is a char!"); @@ -70,18 +70,18 @@ pub fn is_char(self) -> bool { } ``` -Indeed, we just discovered `Ty`'s [`kind` method][kind], which provides us +Indeed, we just discovered `Ty`'s [`kind()` method][kind], which provides us with [`TyKind`][TyKind] of a `Ty`. ## `TyKind` `TyKind` defines the kinds of types in Rust's type system. Peeking into [`TyKind` documentation][TyKind], we will see that it is an -enum of 27 variants, including items such as `Bool`, `Int`, `Ref`, etc. +enum of over 25 variants, including items such as `Bool`, `Int`, `Ref`, etc. ### `kind` Usage -The `TyKind` of `Ty` can be returned by calling [`Ty.kind` method][kind]. +The `TyKind` of `Ty` can be returned by calling [`Ty.kind()` method][kind]. We often use this method to perform pattern matching in Clippy. For instance, if we want to check for a `struct`, we could examine if the @@ -107,15 +107,21 @@ impl LateLintPass<'_> for MyStructLint { We've been talking about [`ty::Ty`][middle_ty] this whole time without addressing [`hir::Ty`][hir_ty], but the latter is also important to understand. -`hir::Ty` would represent *what* an user wrote, while `ty::Ty` would understand the meaning of it (because it has more -information). +`hir::Ty` would represent *what* the user wrote, while `ty::Ty` is how the compiler sees the type and has more +information. Example: -**Example: `fn foo(x: u32) -> u32 { x }`** +```rust +fn foo(x: u32) -> u32 { x } +``` Here the HIR sees the types without "thinking" about them, it knows that the function takes an `u32` and returns -an `u32`. But at the `ty::Ty` level the compiler understands that they're the same type, in-depth lifetimes, etc... +an `u32`. As far as `hir::Ty` is concerned those might be different types. But at the `ty::Ty` level the compiler +understands that they're the same type, in-depth lifetimes, etc... + +To get from a `hir::Ty` to a `ty::Ty`, you can use the [`hir_ty_to_ty`][hir_ty_to_ty] function outside of bodies or +outside of bodies the [`TypeckResults::node_type()`][node_type] method. -you can use the [`hir_ty_to_ty`][hir_ty_to_ty] function to convert from a `hir::Ty` to a `ty::Ty` +> **Warning**: Don't use `hir_ty_to_ty` inside of bodies, because this can cause ICEs. ## Useful Links @@ -130,6 +136,7 @@ in this chapter: [Adt]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/enum.TyKind.html#variant.Adt [AdtDef]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/adt/struct.AdtDef.html [expr_ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TypeckResults.html#method.expr_ty +[node_type]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TypeckResults.html#method.node_type [is_char]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.Ty.html#method.is_char [is_char_source]: https://doc.rust-lang.org/nightly/nightly-rustc/src/rustc_middle/ty/sty.rs.html#1831-1834 [kind]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.Ty.html#method.kind diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md index 78e1a55cff32e..a702226e86103 100644 --- a/book/src/lint_configuration.md +++ b/book/src/lint_configuration.md @@ -55,6 +55,7 @@ Please use that command to update the file and do not edit it by hand. | [suppress-restriction-lint-in-const](#suppress-restriction-lint-in-const) | `false` | | [missing-docs-in-crate-items](#missing-docs-in-crate-items) | `false` | | [future-size-threshold](#future-size-threshold) | `16384` | +| [unnecessary-box-size](#unnecessary-box-size) | `128` | ### arithmetic-side-effects-allowed Suppress checking of the passed type names in all types of operations. @@ -561,4 +562,12 @@ The maximum byte size a `Future` can have, before it triggers the `clippy::large * [large_futures](https://rust-lang.github.io/rust-clippy/master/index.html#large_futures) +### unnecessary-box-size +The byte size a `T` in `Box` can have, below which it triggers the `clippy::unnecessary_box` lint + +**Default Value:** `128` (`u64`) + +* [unnecessary_box_returns](https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_box_returns) + + diff --git a/clippy_dev/src/update_lints.rs b/clippy_dev/src/update_lints.rs index 95222a9acdfc5..dd90a38f7572d 100644 --- a/clippy_dev/src/update_lints.rs +++ b/clippy_dev/src/update_lints.rs @@ -741,7 +741,7 @@ fn gen_deprecated_lints_test(lints: &[DeprecatedLint]) -> String { fn gen_renamed_lints_test(lints: &[RenamedLint]) -> String { let mut seen_lints = HashSet::new(); let mut res: String = GENERATED_FILE_COMMENT.into(); - res.push_str("// run-rustfix\n\n"); + res.push_str("//@run-rustfix\n\n"); for lint in lints { if seen_lints.insert(&lint.new_name) { writeln!(res, "#![allow({})]", lint.new_name).unwrap(); diff --git a/clippy_lints/src/allow_attributes.rs b/clippy_lints/src/allow_attributes.rs index 15d46e954a9a5..b984132acf5bb 100644 --- a/clippy_lints/src/allow_attributes.rs +++ b/clippy_lints/src/allow_attributes.rs @@ -6,7 +6,7 @@ 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 + /// Checks for usage of the `#[allow]` attribute and suggests replacing it with /// the `#[expect]` (See [RFC 2383](https://rust-lang.github.io/rfcs/2383-lint-reasons.html)) /// /// The expect attribute is still unstable and requires the `lint_reasons` diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs index 362f70d12d185..d74bd57fe45eb 100644 --- a/clippy_lints/src/casts/mod.rs +++ b/clippy_lints/src/casts/mod.rs @@ -506,7 +506,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for uses of the `abs()` method that cast the result to unsigned. + /// Checks for usage of the `abs()` method that cast the result to unsigned. /// /// ### Why is this bad? /// The `unsigned_abs()` method avoids panic when called on the MIN value. @@ -625,14 +625,14 @@ declare_clippy_lint! { /// /// ### Example /// ```rust - /// let string = String::with_capacity(1); - /// let ptr = string.as_ptr() as *mut u8; + /// let mut vec = Vec::::with_capacity(1); + /// let ptr = vec.as_ptr() as *mut u8; /// unsafe { ptr.write(4) }; // UNDEFINED BEHAVIOUR /// ``` /// Use instead: /// ```rust - /// let mut string = String::with_capacity(1); - /// let ptr = string.as_mut_ptr(); + /// let mut vec = Vec::::with_capacity(1); + /// let ptr = vec.as_mut_ptr(); /// unsafe { ptr.write(4) }; /// ``` #[clippy::version = "1.66.0"] diff --git a/clippy_lints/src/crate_in_macro_def.rs b/clippy_lints/src/crate_in_macro_def.rs index b2fe0386f945d..7436e9ce811b1 100644 --- a/clippy_lints/src/crate_in_macro_def.rs +++ b/clippy_lints/src/crate_in_macro_def.rs @@ -9,7 +9,7 @@ use rustc_span::{symbol::sym, Span}; declare_clippy_lint! { /// ### What it does - /// Checks for use of `crate` as opposed to `$crate` in a macro definition. + /// Checks for usage of `crate` as opposed to `$crate` in a macro definition. /// /// ### Why is this bad? /// `crate` refers to the macro call's crate, whereas `$crate` refers to the macro definition's diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index f24dab6278095..0c66d36a1d630 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -215,6 +215,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::invalid_upcast_comparisons::INVALID_UPCAST_COMPARISONS_INFO, crate::invalid_utf8_in_unchecked::INVALID_UTF8_IN_UNCHECKED_INFO, crate::items_after_statements::ITEMS_AFTER_STATEMENTS_INFO, + crate::items_after_test_module::ITEMS_AFTER_TEST_MODULE_INFO, crate::iter_not_returning_iterator::ITER_NOT_RETURNING_ITERATOR_INFO, crate::large_const_arrays::LARGE_CONST_ARRAYS_INFO, crate::large_enum_variant::LARGE_ENUM_VARIANT_INFO, diff --git a/clippy_lints/src/entry.rs b/clippy_lints/src/entry.rs index 48a54f60253c8..ee5a875ade7b5 100644 --- a/clippy_lints/src/entry.rs +++ b/clippy_lints/src/entry.rs @@ -19,7 +19,7 @@ use rustc_span::{Span, SyntaxContext, DUMMY_SP}; declare_clippy_lint! { /// ### What it does - /// Checks for uses of `contains_key` + `insert` on `HashMap` + /// Checks for usage of `contains_key` + `insert` on `HashMap` /// or `BTreeMap`. /// /// ### Why is this bad? diff --git a/clippy_lints/src/enum_variants.rs b/clippy_lints/src/enum_variants.rs index 4c69dacf381ad..faac63404199c 100644 --- a/clippy_lints/src/enum_variants.rs +++ b/clippy_lints/src/enum_variants.rs @@ -1,6 +1,6 @@ //! lint on enum variants that are prefixed or suffixed by the same characters -use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; +use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_hir}; use clippy_utils::source::is_present_in_source; use clippy_utils::str_utils::{camel_case_split, count_match_end, count_match_start}; use rustc_hir::{EnumDef, Item, ItemKind, Variant}; @@ -135,9 +135,10 @@ fn check_enum_start(cx: &LateContext<'_>, item_name: &str, variant: &Variant<'_> && name.chars().nth(item_name_chars).map_or(false, |c| !c.is_lowercase()) && name.chars().nth(item_name_chars + 1).map_or(false, |c| !c.is_numeric()) { - span_lint( + span_lint_hir( cx, ENUM_VARIANT_NAMES, + variant.hir_id, variant.span, "variant name starts with the enum's name", ); @@ -149,9 +150,10 @@ fn check_enum_end(cx: &LateContext<'_>, item_name: &str, variant: &Variant<'_>) let item_name_chars = item_name.chars().count(); if count_match_end(item_name, name).char_count == item_name_chars { - span_lint( + span_lint_hir( cx, ENUM_VARIANT_NAMES, + variant.hir_id, variant.span, "variant name ends with the enum's name", ); diff --git a/clippy_lints/src/format_impl.rs b/clippy_lints/src/format_impl.rs index e3ddbfb5981f8..3ddee1842a30c 100644 --- a/clippy_lints/src/format_impl.rs +++ b/clippy_lints/src/format_impl.rs @@ -51,7 +51,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for use of `println`, `print`, `eprintln` or `eprint` in an + /// Checks for usage of `println`, `print`, `eprintln` or `eprint` in an /// implementation of a formatting trait. /// /// ### Why is this bad? diff --git a/clippy_lints/src/formatting.rs b/clippy_lints/src/formatting.rs index a866a68987d02..4762b354392b8 100644 --- a/clippy_lints/src/formatting.rs +++ b/clippy_lints/src/formatting.rs @@ -10,7 +10,7 @@ use rustc_span::source_map::Span; declare_clippy_lint! { /// ### What it does - /// Checks for use of the non-existent `=*`, `=!` and `=-` + /// Checks for usage of the non-existent `=*`, `=!` and `=-` /// operators. /// /// ### Why is this bad? diff --git a/clippy_lints/src/functions/mod.rs b/clippy_lints/src/functions/mod.rs index 7c5e44bb7dcad..ac2d253fe8340 100644 --- a/clippy_lints/src/functions/mod.rs +++ b/clippy_lints/src/functions/mod.rs @@ -348,7 +348,7 @@ declare_clippy_lint! { /// // [...] /// } /// ``` - #[clippy::version = "1.68.0"] + #[clippy::version = "1.69.0"] pub IMPL_TRAIT_IN_PARAMS, restriction, "`impl Trait` is used in the function's parameters" diff --git a/clippy_lints/src/items_after_test_module.rs b/clippy_lints/src/items_after_test_module.rs new file mode 100644 index 0000000000000..52d716feea02f --- /dev/null +++ b/clippy_lints/src/items_after_test_module.rs @@ -0,0 +1,83 @@ +use clippy_utils::{diagnostics::span_lint_and_help, is_in_cfg_test}; +use rustc_hir::{HirId, ItemId, ItemKind, Mod}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_middle::lint::in_external_macro; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::{sym, Span}; + +declare_clippy_lint! { + /// ### What it does + /// Triggers if an item is declared after the testing module marked with `#[cfg(test)]`. + /// ### Why is this bad? + /// Having items declared after the testing module is confusing and may lead to bad test coverage. + /// ### Example + /// ```rust + /// #[cfg(test)] + /// mod tests { + /// // [...] + /// } + /// + /// fn my_function() { + /// // [...] + /// } + /// ``` + /// Use instead: + /// ```rust + /// fn my_function() { + /// // [...] + /// } + /// + /// #[cfg(test)] + /// mod tests { + /// // [...] + /// } + /// ``` + #[clippy::version = "1.70.0"] + pub ITEMS_AFTER_TEST_MODULE, + style, + "An item was found after the testing module `tests`" +} + +declare_lint_pass!(ItemsAfterTestModule => [ITEMS_AFTER_TEST_MODULE]); + +impl LateLintPass<'_> for ItemsAfterTestModule { + fn check_mod(&mut self, cx: &LateContext<'_>, _: &Mod<'_>, _: HirId) { + let mut was_test_mod_visited = false; + let mut test_mod_span: Option = None; + + let hir = cx.tcx.hir(); + let items = hir.items().collect::>(); + + for (i, itid) in items.iter().enumerate() { + let item = hir.item(*itid); + + if_chain! { + if was_test_mod_visited; + if i == (items.len() - 3 /* Weird magic number (HIR-translation behaviour) */); + if cx.sess().source_map().lookup_char_pos(item.span.lo()).file.name_hash + == cx.sess().source_map().lookup_char_pos(test_mod_span.unwrap().lo()).file.name_hash; // Will never fail + if !matches!(item.kind, ItemKind::Mod(_)); + if !is_in_cfg_test(cx.tcx, itid.hir_id()); // The item isn't in the testing module itself + if !in_external_macro(cx.sess(), item.span); + + then { + span_lint_and_help(cx, ITEMS_AFTER_TEST_MODULE, test_mod_span.unwrap().with_hi(item.span.hi()), "items were found after the testing module", None, "move the items to before the testing module was defined"); + }}; + + if matches!(item.kind, ItemKind::Mod(_)) { + for attr in cx.tcx.get_attrs(item.owner_id.to_def_id(), sym::cfg) { + if_chain! { + if attr.has_name(sym::cfg); + if let Some(mitems) = attr.meta_item_list(); + if let [mitem] = &*mitems; + if mitem.has_name(sym::test); + then { + was_test_mod_visited = true; + test_mod_span = Some(item.span); + } + } + } + } + } + } +} diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index 0805b4b19796e..fec9c6f626c60 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -168,25 +168,27 @@ impl<'tcx> LateLintPass<'tcx> for LenZero { } if let ExprKind::Binary(Spanned { node: cmp, .. }, left, right) = expr.kind { + // expr.span might contains parenthesis, see issue #10529 + let actual_span = left.span.with_hi(right.span.hi()); match cmp { BinOpKind::Eq => { - check_cmp(cx, expr.span, left, right, "", 0); // len == 0 - check_cmp(cx, expr.span, right, left, "", 0); // 0 == len + check_cmp(cx, actual_span, left, right, "", 0); // len == 0 + check_cmp(cx, actual_span, right, left, "", 0); // 0 == len }, BinOpKind::Ne => { - check_cmp(cx, expr.span, left, right, "!", 0); // len != 0 - check_cmp(cx, expr.span, right, left, "!", 0); // 0 != len + check_cmp(cx, actual_span, left, right, "!", 0); // len != 0 + check_cmp(cx, actual_span, right, left, "!", 0); // 0 != len }, BinOpKind::Gt => { - check_cmp(cx, expr.span, left, right, "!", 0); // len > 0 - check_cmp(cx, expr.span, right, left, "", 1); // 1 > len + check_cmp(cx, actual_span, left, right, "!", 0); // len > 0 + check_cmp(cx, actual_span, right, left, "", 1); // 1 > len }, BinOpKind::Lt => { - check_cmp(cx, expr.span, left, right, "", 1); // len < 1 - check_cmp(cx, expr.span, right, left, "!", 0); // 0 < len + check_cmp(cx, actual_span, left, right, "", 1); // len < 1 + check_cmp(cx, actual_span, right, left, "!", 0); // 0 < len }, - BinOpKind::Ge => check_cmp(cx, expr.span, left, right, "!", 1), // len >= 1 - BinOpKind::Le => check_cmp(cx, expr.span, right, left, "!", 1), // 1 <= len + BinOpKind::Ge => check_cmp(cx, actual_span, left, right, "!", 1), // len >= 1 + BinOpKind::Le => check_cmp(cx, actual_span, right, left, "!", 1), // 1 <= len _ => (), } } diff --git a/clippy_lints/src/let_underscore.rs b/clippy_lints/src/let_underscore.rs index 51b5de27de89b..637b7de920e79 100644 --- a/clippy_lints/src/let_underscore.rs +++ b/clippy_lints/src/let_underscore.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::ty::{implements_trait, is_must_use_ty, match_type}; use clippy_utils::{is_must_use_func_call, paths}; -use rustc_hir::{Local, PatKind}; +use rustc_hir::{ExprKind, Local, PatKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::subst::GenericArgKind; @@ -189,7 +189,18 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { if local.pat.default_binding_modes && local.ty.is_none() { // When `default_binding_modes` is true, the `let` keyword is present. - span_lint_and_help( + + // Ignore function calls that return impl traits... + if let Some(init) = local.init && + matches!(init.kind, ExprKind::Call(_, _) | ExprKind::MethodCall(_, _, _, _)) { + let expr_ty = cx.typeck_results().expr_ty(init); + if expr_ty.is_impl_trait() { + return; + } + } + + + span_lint_and_help( cx, LET_UNDERSCORE_UNTYPED, local.span, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index b0ec14855e71b..573ffe349ec23 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -158,6 +158,7 @@ mod int_plus_one; mod invalid_upcast_comparisons; mod invalid_utf8_in_unchecked; mod items_after_statements; +mod items_after_test_module; mod iter_not_returning_iterator; mod large_const_arrays; mod large_enum_variant; @@ -950,15 +951,18 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: 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)); + let unnecessary_box_size = conf.unnecessary_box_size; store.register_late_pass(move |_| { Box::new(unnecessary_box_returns::UnnecessaryBoxReturns::new( avoid_breaking_exported_api, + unnecessary_box_size, )) }); store.register_late_pass(|_| Box::new(lines_filter_map_ok::LinesFilterMapOk)); store.register_late_pass(|_| Box::new(tests_outside_test_module::TestsOutsideTestModule)); store.register_late_pass(|_| Box::new(manual_slice_size_calculation::ManualSliceSizeCalculation)); store.register_early_pass(|| Box::new(suspicious_doc_comments::SuspiciousDocComments)); + store.register_late_pass(|_| Box::new(items_after_test_module::ItemsAfterTestModule)); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/clippy_lints/src/lines_filter_map_ok.rs b/clippy_lints/src/lines_filter_map_ok.rs index b0f9276475d3e..bba9bb445a771 100644 --- a/clippy_lints/src/lines_filter_map_ok.rs +++ b/clippy_lints/src/lines_filter_map_ok.rs @@ -10,7 +10,7 @@ use rustc_span::sym; declare_clippy_lint! { /// ### What it does - /// Detect uses of `lines.filter_map(Result::ok)` or `lines.flat_map(Result::ok)` + /// Checks for usage of `lines.filter_map(Result::ok)` or `lines.flat_map(Result::ok)` /// when `lines` has type `std::io::Lines`. /// /// ### Why is this bad? diff --git a/clippy_lints/src/manual_bits.rs b/clippy_lints/src/manual_bits.rs index bc815dc4a260a..4629b22d1717f 100644 --- a/clippy_lints/src/manual_bits.rs +++ b/clippy_lints/src/manual_bits.rs @@ -13,7 +13,7 @@ use rustc_span::sym; declare_clippy_lint! { /// ### What it does - /// Checks for uses of `std::mem::size_of::() * 8` when + /// Checks for usage of `std::mem::size_of::() * 8` when /// `T::BITS` is available. /// /// ### Why is this bad? diff --git a/clippy_lints/src/manual_slice_size_calculation.rs b/clippy_lints/src/manual_slice_size_calculation.rs index 92ee79453a3b8..703a6b25840b1 100644 --- a/clippy_lints/src/manual_slice_size_calculation.rs +++ b/clippy_lints/src/manual_slice_size_calculation.rs @@ -1,5 +1,7 @@ -use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::{expr_or_init, in_constant}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_with_context; +use clippy_utils::{expr_or_init, in_constant, std_or_core}; +use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; @@ -38,19 +40,27 @@ declare_lint_pass!(ManualSliceSizeCalculation => [MANUAL_SLICE_SIZE_CALCULATION] impl<'tcx> LateLintPass<'tcx> for ManualSliceSizeCalculation { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { - // Does not apply inside const because size_of_value is not cost in stable. + // Does not apply inside const because size_of_val is not cost in stable. if !in_constant(cx, expr.hir_id) && let ExprKind::Binary(ref op, left, right) = expr.kind && BinOpKind::Mul == op.node - && let Some(_receiver) = simplify(cx, left, right) + && !expr.span.from_expansion() + && let Some(receiver) = simplify(cx, left, right) { - span_lint_and_help( + let ctxt = expr.span.ctxt(); + let mut app = Applicability::MachineApplicable; + let val_name = snippet_with_context(cx, receiver.span, ctxt, "slice", &mut app).0; + let Some(sugg) = std_or_core(cx) else { return }; + + span_lint_and_sugg( cx, MANUAL_SLICE_SIZE_CALCULATION, expr.span, "manual slice size calculation", - None, - "consider using std::mem::size_of_value instead"); + "try", + format!("{sugg}::mem::size_of_val({val_name})"), + app, + ); } } } @@ -71,9 +81,9 @@ fn simplify_half<'tcx>( expr1: &'tcx Expr<'tcx>, expr2: &'tcx Expr<'tcx>, ) -> Option<&'tcx Expr<'tcx>> { - if + if !expr1.span.from_expansion() // expr1 is `[T1].len()`? - let ExprKind::MethodCall(method_path, receiver, _, _) = expr1.kind + && let ExprKind::MethodCall(method_path, receiver, _, _) = expr1.kind && method_path.ident.name == sym::len && let receiver_ty = cx.typeck_results().expr_ty(receiver) && let ty::Slice(ty1) = receiver_ty.peel_refs().kind() diff --git a/clippy_lints/src/matches/mod.rs b/clippy_lints/src/matches/mod.rs index 97ecca450fac1..87b63eead253e 100644 --- a/clippy_lints/src/matches/mod.rs +++ b/clippy_lints/src/matches/mod.rs @@ -843,7 +843,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for usages of `Err(x)?`. + /// Checks for usage of `Err(x)?`. /// /// ### Why is this bad? /// The `?` operator is designed to allow calls that @@ -878,7 +878,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for usages of `match` which could be implemented using `map` + /// Checks for usage of `match` which could be implemented using `map` /// /// ### Why is this bad? /// Using the `map` method is clearer and more concise. @@ -902,7 +902,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for usages of `match` which could be implemented using `filter` + /// Checks for usage of `match` which could be implemented using `filter` /// /// ### Why is this bad? /// Using the `filter` method is clearer and more concise. diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 64bf55ba24c98..9cafbc2e5f5a6 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -121,7 +121,7 @@ use rustc_span::{sym, Span}; declare_clippy_lint! { /// ### What it does - /// Checks for usages of `cloned()` on an `Iterator` or `Option` where + /// Checks for usage of `cloned()` on an `Iterator` or `Option` where /// `copied()` could be used instead. /// /// ### Why is this bad? @@ -201,7 +201,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for usages of `Iterator::flat_map()` where `filter_map()` could be + /// Checks for usage of `Iterator::flat_map()` where `filter_map()` could be /// used instead. /// /// ### Why is this bad? @@ -441,7 +441,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for usages of `_.unwrap_or_else(Default::default)` on `Option` and + /// Checks for usage of `_.unwrap_or_else(Default::default)` on `Option` and /// `Result` values. /// /// ### Why is this bad? @@ -1194,7 +1194,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for use of `.iter().nth()` (and the related + /// Checks for usage of `.iter().nth()` (and the related /// `.iter_mut().nth()`) on standard library types with *O*(1) element access. /// /// ### Why is this bad? @@ -1221,7 +1221,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for use of `.skip(x).next()` on iterators. + /// Checks for usage of `.skip(x).next()` on iterators. /// /// ### Why is this bad? /// `.nth(x)` is cleaner @@ -1246,7 +1246,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for use of `.drain(..)` on `Vec` and `VecDeque` for iteration. + /// Checks for usage of `.drain(..)` on `Vec` and `VecDeque` for iteration. /// /// ### Why is this bad? /// `.into_iter()` is simpler with better performance. @@ -1271,7 +1271,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for using `x.get(x.len() - 1)` instead of + /// Checks for usage of `x.get(x.len() - 1)` instead of /// `x.last()`. /// /// ### Why is this bad? @@ -1304,7 +1304,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for use of `.get().unwrap()` (or + /// Checks for usage of `.get().unwrap()` (or /// `.get_mut().unwrap`) on a standard library type which implements `Index` /// /// ### Why is this bad? @@ -1475,7 +1475,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for using `fold` when a more succinct alternative exists. + /// Checks for usage of `fold` when a more succinct alternative exists. /// Specifically, this checks for `fold`s which could be replaced by `any`, `all`, /// `sum` or `product`. /// @@ -2161,7 +2161,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for usages of `str::splitn(2, _)` + /// Checks for usage of `str::splitn(2, _)` /// /// ### Why is this bad? /// `split_once` is both clearer in intent and slightly more efficient. @@ -2197,7 +2197,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for usages of `str::splitn` (or `str::rsplitn`) where using `str::split` would be the same. + /// Checks for usage of `str::splitn` (or `str::rsplitn`) where using `str::split` would be the same. /// ### Why is this bad? /// The function `split` is simpler and there is no performance difference in these cases, considering /// that both functions return a lazy iterator. @@ -2251,7 +2251,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for use of `.collect::>().join("")` on iterators. + /// Checks for usage of `.collect::>().join("")` on iterators. /// /// ### Why is this bad? /// `.collect::()` is more concise and might be more performant @@ -2377,7 +2377,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for usages of `.then_some(..).unwrap_or(..)` + /// Checks for usage of `.then_some(..).unwrap_or(..)` /// /// ### Why is this bad? /// This can be written more clearly with `if .. else ..` @@ -2553,7 +2553,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for using `x.get(0)` instead of + /// Checks for usage of `x.get(0)` instead of /// `x.first()`. /// /// ### Why is this bad? @@ -2957,7 +2957,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Detects uses of `Vec::sort_by` passing in a closure + /// Checks for usage of `Vec::sort_by` passing in a closure /// which compares the two arguments, either directly or indirectly. /// /// ### Why is this bad? @@ -3013,7 +3013,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for use of File::read_to_end and File::read_to_string. + /// Checks for usage of File::read_to_end and File::read_to_string. /// /// ### Why is this bad? /// `fs::{read, read_to_string}` provide the same functionality when `buf` is empty with fewer imports and no intermediate values. @@ -3185,7 +3185,7 @@ declare_clippy_lint! { /// ```rust /// std::process::Command::new("echo").args(["-n", "hello"]).spawn().unwrap(); /// ``` - #[clippy::version = "1.67.0"] + #[clippy::version = "1.69.0"] pub SUSPICIOUS_COMMAND_ARG_SPACE, suspicious, "single command line argument that looks like it should be multiple arguments" diff --git a/clippy_lints/src/methods/obfuscated_if_else.rs b/clippy_lints/src/methods/obfuscated_if_else.rs index 4d7427b266213..eada530d670da 100644 --- a/clippy_lints/src/methods/obfuscated_if_else.rs +++ b/clippy_lints/src/methods/obfuscated_if_else.rs @@ -1,5 +1,3 @@ -// run-rustfix - use super::OBFUSCATED_IF_ELSE; use clippy_utils::{diagnostics::span_lint_and_sugg, source::snippet_with_applicability}; use rustc_errors::Applicability; diff --git a/clippy_lints/src/multiple_unsafe_ops_per_block.rs b/clippy_lints/src/multiple_unsafe_ops_per_block.rs index 5418616ded012..2abdfacd27634 100644 --- a/clippy_lints/src/multiple_unsafe_ops_per_block.rs +++ b/clippy_lints/src/multiple_unsafe_ops_per_block.rs @@ -59,7 +59,7 @@ declare_clippy_lint! { /// unsafe { char::from_u32_unchecked(int_value) } /// } /// ``` - #[clippy::version = "1.68.0"] + #[clippy::version = "1.69.0"] pub MULTIPLE_UNSAFE_OPS_PER_BLOCK, restriction, "more than one unsafe operation per `unsafe` block" diff --git a/clippy_lints/src/mutex_atomic.rs b/clippy_lints/src/mutex_atomic.rs index dc866ab6373bb..99394b9e5fba7 100644 --- a/clippy_lints/src/mutex_atomic.rs +++ b/clippy_lints/src/mutex_atomic.rs @@ -1,4 +1,4 @@ -//! Checks for uses of mutex where an atomic value could be used +//! Checks for usage of mutex where an atomic value could be used //! //! This lint is **allow** by default @@ -12,7 +12,7 @@ use rustc_span::sym; declare_clippy_lint! { /// ### What it does - /// Checks for usages of `Mutex` where an atomic will do. + /// Checks for usage of `Mutex` where an atomic will do. /// /// ### Why is this bad? /// Using a mutex just to make access to a plain bool or @@ -49,7 +49,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for usages of `Mutex` where `X` is an integral + /// Checks for usage of `Mutex` where `X` is an integral /// type. /// /// ### Why is this bad? diff --git a/clippy_lints/src/non_copy_const.rs b/clippy_lints/src/non_copy_const.rs index eed0f1f19918b..58590df1fedf8 100644 --- a/clippy_lints/src/non_copy_const.rs +++ b/clippy_lints/src/non_copy_const.rs @@ -1,4 +1,4 @@ -//! Checks for uses of const which the type is not `Freeze` (`Cell`-free). +//! Checks for usage of const which the type is not `Freeze` (`Cell`-free). //! //! This lint is **warn** by default. diff --git a/clippy_lints/src/octal_escapes.rs b/clippy_lints/src/octal_escapes.rs index 7376ab0c846d9..6d3865080a686 100644 --- a/clippy_lints/src/octal_escapes.rs +++ b/clippy_lints/src/octal_escapes.rs @@ -76,8 +76,8 @@ fn check_lit(cx: &EarlyContext<'_>, lit: &Lit, span: Span, is_string: bool) { if ch == '\\' { if let Some((_, '0')) = iter.next() { // collect up to two further octal digits - if let Some((mut to, '0'..='7')) = iter.next() { - if let Some((_, '0'..='7')) = iter.peek() { + if let Some((mut to, _)) = iter.next_if(|(_, ch)| matches!(ch, '0'..='7')) { + if iter.next_if(|(_, ch)| matches!(ch, '0'..='7')).is_some() { to += 1; } found.push((from, to + 1)); @@ -90,32 +90,6 @@ fn check_lit(cx: &EarlyContext<'_>, lit: &Lit, span: Span, is_string: bool) { return; } - // construct two suggestion strings, one with \x escapes with octal meaning - // as in C, and one with \x00 for null bytes. - let mut suggest_1 = if is_string { "\"" } else { "b\"" }.to_string(); - let mut suggest_2 = suggest_1.clone(); - let mut index = 0; - for (from, to) in found { - suggest_1.push_str(&contents[index..from]); - suggest_2.push_str(&contents[index..from]); - - // construct a replacement escape - // the maximum value is \077, or \x3f, so u8 is sufficient here - if let Ok(n) = u8::from_str_radix(&contents[from + 1..to], 8) { - write!(suggest_1, "\\x{n:02x}").unwrap(); - } - - // append the null byte as \x00 and the following digits literally - suggest_2.push_str("\\x00"); - suggest_2.push_str(&contents[from + 2..to]); - - index = to; - } - suggest_1.push_str(&contents[index..]); - suggest_1.push('"'); - suggest_2.push_str(&contents[index..]); - suggest_2.push('"'); - span_lint_and_then( cx, OCTAL_ESCAPES, @@ -129,23 +103,53 @@ fn check_lit(cx: &EarlyContext<'_>, lit: &Lit, span: Span, is_string: bool) { "octal escapes are not supported, `\\0` is always a null {}", if is_string { "character" } else { "byte" } )); - // suggestion 1: equivalent hex escape - diag.span_suggestion( - span, - "if an octal escape was intended, use the hexadecimal representation instead", - suggest_1, - Applicability::MaybeIncorrect, - ); - // suggestion 2: unambiguous null byte - diag.span_suggestion( - span, - format!( - "if the null {} is intended, disambiguate using", - if is_string { "character" } else { "byte" } - ), - suggest_2, - Applicability::MaybeIncorrect, - ); + + // Generate suggestions if the string is not too long (~ 5 lines) + if contents.len() < 400 { + // construct two suggestion strings, one with \x escapes with octal meaning + // as in C, and one with \x00 for null bytes. + let mut suggest_1 = if is_string { "\"" } else { "b\"" }.to_string(); + let mut suggest_2 = suggest_1.clone(); + let mut index = 0; + for (from, to) in found { + suggest_1.push_str(&contents[index..from]); + suggest_2.push_str(&contents[index..from]); + + // construct a replacement escape + // the maximum value is \077, or \x3f, so u8 is sufficient here + if let Ok(n) = u8::from_str_radix(&contents[from + 1..to], 8) { + write!(suggest_1, "\\x{n:02x}").unwrap(); + } + + // append the null byte as \x00 and the following digits literally + suggest_2.push_str("\\x00"); + suggest_2.push_str(&contents[from + 2..to]); + + index = to; + } + suggest_1.push_str(&contents[index..]); + suggest_2.push_str(&contents[index..]); + + suggest_1.push('"'); + suggest_2.push('"'); + // suggestion 1: equivalent hex escape + diag.span_suggestion( + span, + "if an octal escape was intended, use the hexadecimal representation instead", + suggest_1, + Applicability::MaybeIncorrect, + ); + // suggestion 2: unambiguous null byte + diag.span_suggestion( + span, + format!( + "if the null {} is intended, disambiguate using", + if is_string { "character" } else { "byte" } + ), + suggest_2, + Applicability::MaybeIncorrect, + ); + } }, ); } diff --git a/clippy_lints/src/operators/arithmetic_side_effects.rs b/clippy_lints/src/operators/arithmetic_side_effects.rs index e5713735672da..fafcf25709471 100644 --- a/clippy_lints/src/operators/arithmetic_side_effects.rs +++ b/clippy_lints/src/operators/arithmetic_side_effects.rs @@ -1,4 +1,5 @@ use super::ARITHMETIC_SIDE_EFFECTS; +use clippy_utils::is_from_proc_macro; use clippy_utils::{ consts::{constant, constant_simple, Constant}, diagnostics::span_lint, @@ -10,7 +11,10 @@ use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::Ty; use rustc_session::impl_lint_pass; -use rustc_span::source_map::{Span, Spanned}; +use rustc_span::{ + source_map::{Span, Spanned}, + Symbol, +}; const HARD_CODED_ALLOWED_BINARY: &[[&str; 2]] = &[ ["f32", "f32"], @@ -20,6 +24,7 @@ const HARD_CODED_ALLOWED_BINARY: &[[&str; 2]] = &[ ["std::string::String", "&str"], ]; const HARD_CODED_ALLOWED_UNARY: &[&str] = &["f32", "f64", "std::num::Saturating", "std::num::Wrapping"]; +const INTEGER_METHODS: &[&str] = &["saturating_div", "wrapping_div", "wrapping_rem", "wrapping_rem_euclid"]; #[derive(Debug)] pub struct ArithmeticSideEffects { @@ -28,6 +33,7 @@ pub struct ArithmeticSideEffects { // Used to check whether expressions are constants, such as in enum discriminants and consts const_span: Option, expr_span: Option, + integer_methods: FxHashSet, } impl_lint_pass!(ArithmeticSideEffects => [ARITHMETIC_SIDE_EFFECTS]); @@ -53,6 +59,7 @@ impl ArithmeticSideEffects { allowed_unary, const_span: None, expr_span: None, + integer_methods: INTEGER_METHODS.iter().map(|el| Symbol::intern(el)).collect(), } } @@ -184,6 +191,33 @@ impl ArithmeticSideEffects { } } + /// There are some integer methods like `wrapping_div` that will panic depending on the + /// provided input. + fn manage_method_call<'tcx>( + &mut self, + args: &[hir::Expr<'tcx>], + cx: &LateContext<'tcx>, + ps: &hir::PathSegment<'tcx>, + receiver: &hir::Expr<'tcx>, + ) { + let Some(arg) = args.first() else { return; }; + if constant_simple(cx, cx.typeck_results(), receiver).is_some() { + return; + } + let instance_ty = cx.typeck_results().expr_ty(receiver); + if !Self::is_integral(instance_ty) { + return; + } + if !self.integer_methods.contains(&ps.ident.name) { + return; + } + let (actual_arg, _) = peel_hir_expr_refs(arg); + match Self::literal_integer(cx, actual_arg) { + None | Some(0) => self.issue_lint(cx, arg), + Some(_) => {}, + } + } + fn manage_unary_ops<'tcx>( &mut self, cx: &LateContext<'tcx>, @@ -206,8 +240,9 @@ impl ArithmeticSideEffects { self.issue_lint(cx, expr); } - fn should_skip_expr(&mut self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool { + fn should_skip_expr<'tcx>(&mut self, cx: &LateContext<'tcx>, expr: &hir::Expr<'tcx>) -> bool { is_lint_allowed(cx, ARITHMETIC_SIDE_EFFECTS, expr.hir_id) + || is_from_proc_macro(cx, expr) || self.expr_span.is_some() || self.const_span.map_or(false, |sp| sp.contains(expr.span)) } @@ -222,6 +257,9 @@ impl<'tcx> LateLintPass<'tcx> for ArithmeticSideEffects { hir::ExprKind::AssignOp(op, lhs, rhs) | hir::ExprKind::Binary(op, lhs, rhs) => { self.manage_bin_ops(cx, expr, op, lhs, rhs); }, + hir::ExprKind::MethodCall(ps, receiver, args, _) => { + self.manage_method_call(args, cx, ps, receiver); + }, hir::ExprKind::Unary(un_op, un_expr) => { self.manage_unary_ops(cx, expr, un_expr, *un_op); }, diff --git a/clippy_lints/src/operators/mod.rs b/clippy_lints/src/operators/mod.rs index eba230da6c39b..19599731bd6ef 100644 --- a/clippy_lints/src/operators/mod.rs +++ b/clippy_lints/src/operators/mod.rs @@ -685,7 +685,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for uses of bitwise and/or operators between booleans, where performance may be improved by using + /// Checks for usage of bitwise and/or operators between booleans, where performance may be improved by using /// a lazy and. /// /// ### Why is this bad? diff --git a/clippy_lints/src/operators/numeric_arithmetic.rs b/clippy_lints/src/operators/numeric_arithmetic.rs index 777395f452c92..77fd45b199a11 100644 --- a/clippy_lints/src/operators/numeric_arithmetic.rs +++ b/clippy_lints/src/operators/numeric_arithmetic.rs @@ -1,12 +1,12 @@ +use super::{FLOAT_ARITHMETIC, INTEGER_ARITHMETIC}; use clippy_utils::consts::constant_simple; use clippy_utils::diagnostics::span_lint; +use clippy_utils::is_from_proc_macro; use clippy_utils::is_integer_literal; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_span::source_map::Span; -use super::{FLOAT_ARITHMETIC, INTEGER_ARITHMETIC}; - #[derive(Default)] pub struct Context { expr_id: Option, @@ -47,6 +47,9 @@ impl Context { let (l_ty, r_ty) = (cx.typeck_results().expr_ty(l), cx.typeck_results().expr_ty(r)); if l_ty.peel_refs().is_integral() && r_ty.peel_refs().is_integral() { + if is_from_proc_macro(cx, expr) { + return; + } match op { hir::BinOpKind::Div | hir::BinOpKind::Rem => match &r.kind { hir::ExprKind::Lit(_lit) => (), @@ -79,6 +82,9 @@ impl Context { let ty = cx.typeck_results().expr_ty(arg); if constant_simple(cx, cx.typeck_results(), expr).is_none() { if ty.is_integral() { + if is_from_proc_macro(cx, expr) { + return; + } span_lint(cx, INTEGER_ARITHMETIC, expr.span, "integer arithmetic detected"); self.expr_id = Some(expr.hir_id); } else if ty.is_floating_point() { diff --git a/clippy_lints/src/question_mark_used.rs b/clippy_lints/src/question_mark_used.rs index 9b678e8d753c2..ff66b8a009531 100644 --- a/clippy_lints/src/question_mark_used.rs +++ b/clippy_lints/src/question_mark_used.rs @@ -24,7 +24,7 @@ declare_clippy_lint! { /// ```ignore /// utility_macro!(expr); /// ``` - #[clippy::version = "pre 1.29.0"] + #[clippy::version = "1.69.0"] pub QUESTION_MARK_USED, restriction, "complains if the question mark operator is used" diff --git a/clippy_lints/src/significant_drop_tightening.rs b/clippy_lints/src/significant_drop_tightening.rs index 869358fb1ba70..b930b2c8dd7b8 100644 --- a/clippy_lints/src/significant_drop_tightening.rs +++ b/clippy_lints/src/significant_drop_tightening.rs @@ -17,7 +17,7 @@ use rustc_span::{symbol::Ident, Span, DUMMY_SP}; declare_clippy_lint! { /// ### What it does /// - /// Searches for elements marked with `#[clippy::significant_drop]` that could be early + /// Searches for elements marked with `#[clippy::has_significant_drop]` that could be early /// dropped but are in fact dropped at the end of their scopes. In other words, enforces the /// "tightening" of their possible lifetimes. /// @@ -46,7 +46,7 @@ declare_clippy_lint! { /// do_heavy_computation_that_takes_time(owned_rslt); /// } /// ``` - #[clippy::version = "1.67.0"] + #[clippy::version = "1.69.0"] pub SIGNIFICANT_DROP_TIGHTENING, nursery, "Searches for elements marked with `#[clippy::has_significant_drop]` that could be early dropped but are in fact dropped at the end of their scopes" diff --git a/clippy_lints/src/types/mod.rs b/clippy_lints/src/types/mod.rs index c1f228d5f90a9..c6834a8fdaa24 100644 --- a/clippy_lints/src/types/mod.rs +++ b/clippy_lints/src/types/mod.rs @@ -22,7 +22,7 @@ use rustc_span::source_map::Span; declare_clippy_lint! { /// ### What it does - /// Checks for use of `Box` where T is a collection such as Vec anywhere in the code. + /// Checks for usage of `Box` where T is a collection such as Vec anywhere in the code. /// Check the [Box documentation](https://doc.rust-lang.org/std/boxed/index.html) for more information. /// /// ### Why is this bad? @@ -52,7 +52,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for use of `Vec>` where T: Sized anywhere in the code. + /// Checks for usage of `Vec>` where T: Sized anywhere in the code. /// Check the [Box documentation](https://doc.rust-lang.org/std/boxed/index.html) for more information. /// /// ### Why is this bad? @@ -85,7 +85,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for use of `Option>` in function signatures and type + /// Checks for usage of `Option>` in function signatures and type /// definitions /// /// ### Why is this bad? @@ -164,7 +164,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for use of `&Box` anywhere in the code. + /// Checks for usage of `&Box` anywhere in the code. /// Check the [Box documentation](https://doc.rust-lang.org/std/boxed/index.html) for more information. /// /// ### Why is this bad? @@ -190,7 +190,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for use of redundant allocations anywhere in the code. + /// Checks for usage of redundant allocations anywhere in the code. /// /// ### Why is this bad? /// Expressions such as `Rc<&T>`, `Rc>`, `Rc>`, `Rc>`, `Arc<&T>`, `Arc>`, diff --git a/clippy_lints/src/unnecessary_box_returns.rs b/clippy_lints/src/unnecessary_box_returns.rs index 912bcda630b83..af1c8d83b4fe6 100644 --- a/clippy_lints/src/unnecessary_box_returns.rs +++ b/clippy_lints/src/unnecessary_box_returns.rs @@ -1,4 +1,4 @@ -use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::{diagnostics::span_lint_and_then, ty::approx_ty_size}; use rustc_errors::Applicability; use rustc_hir::{def_id::LocalDefId, FnDecl, FnRetTy, ImplItemKind, Item, ItemKind, Node, TraitItem, TraitItemKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -10,6 +10,9 @@ declare_clippy_lint! { /// /// Checks for a return type containing a `Box` where `T` implements `Sized` /// + /// The lint ignores `Box` where `T` is larger than `unnecessary_box_size`, + /// as returning a large `T` directly may be detrimental to performance. + /// /// ### Why is this bad? /// /// It's better to just return `T` in these cases. The caller may not need @@ -36,14 +39,16 @@ declare_clippy_lint! { pub struct UnnecessaryBoxReturns { avoid_breaking_exported_api: bool, + maximum_size: u64, } impl_lint_pass!(UnnecessaryBoxReturns => [UNNECESSARY_BOX_RETURNS]); impl UnnecessaryBoxReturns { - pub fn new(avoid_breaking_exported_api: bool) -> Self { + pub fn new(avoid_breaking_exported_api: bool, maximum_size: u64) -> Self { Self { avoid_breaking_exported_api, + maximum_size, } } @@ -71,8 +76,10 @@ impl UnnecessaryBoxReturns { let boxed_ty = return_ty.boxed_ty(); - // it's sometimes useful to return Box if T is unsized, so don't lint those - if boxed_ty.is_sized(cx.tcx, cx.param_env) { + // It's sometimes useful to return Box if T is unsized, so don't lint those. + // Also, don't lint if we know that T is very large, in which case returning + // a Box may be beneficial. + if boxed_ty.is_sized(cx.tcx, cx.param_env) && approx_ty_size(cx, boxed_ty) <= self.maximum_size { span_lint_and_then( cx, UNNECESSARY_BOX_RETURNS, diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index 896a01af37d99..67bb499c455a2 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -463,6 +463,10 @@ define_Conf! { /// /// The maximum byte size a `Future` can have, before it triggers the `clippy::large_futures` lint (future_size_threshold: u64 = 16 * 1024), + /// Lint: UNNECESSARY_BOX_RETURNS. + /// + /// The byte size a `T` in `Box` can have, below which it triggers the `clippy::unnecessary_box` lint + (unnecessary_box_size: u64 = 128), } /// Search for the configuration file. diff --git a/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs b/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs index 14ed1368e03ec..00842376628cc 100644 --- a/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs +++ b/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs @@ -20,7 +20,7 @@ use std::str; declare_clippy_lint! { /// ### What it does - /// Checks for usages of def paths when a diagnostic item or a `LangItem` could be used. + /// Checks for usage of def paths when a diagnostic item or a `LangItem` could be used. /// /// ### Why is this bad? /// The path for an item is subject to change and is less efficient to look up than a diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs index d7c94b909bdc5..f194dc5d4b2ef 100644 --- a/clippy_lints/src/write.rs +++ b/clippy_lints/src/write.rs @@ -104,7 +104,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for use of `Debug` formatting. The purpose of this + /// Checks for usage of `Debug` formatting. The purpose of this /// lint is to catch debugging remnants. /// /// ### Why is this bad? diff --git a/declare_clippy_lint/Cargo.toml b/declare_clippy_lint/Cargo.toml index 5c9f76dbbc600..bd26f4fc91395 100644 --- a/declare_clippy_lint/Cargo.toml +++ b/declare_clippy_lint/Cargo.toml @@ -10,7 +10,7 @@ proc-macro = true [dependencies] itertools = "0.10.1" quote = "1.0.21" -syn = "1.0.100" +syn = "2.0" [features] deny-warnings = [] diff --git a/declare_clippy_lint/src/lib.rs b/declare_clippy_lint/src/lib.rs index 26210556d6526..5232e4ab7d754 100644 --- a/declare_clippy_lint/src/lib.rs +++ b/declare_clippy_lint/src/lib.rs @@ -6,16 +6,16 @@ use proc_macro::TokenStream; use quote::{format_ident, quote}; use syn::parse::{Parse, ParseStream}; -use syn::{parse_macro_input, Attribute, Error, Ident, Lit, LitStr, Meta, Result, Token}; +use syn::{parse_macro_input, Attribute, Error, Expr, ExprLit, Ident, Lit, LitStr, Meta, Result, Token}; fn parse_attr(path: [&'static str; LEN], attr: &Attribute) -> Option { - if let Meta::NameValue(name_value) = attr.parse_meta().ok()? { + if let Meta::NameValue(name_value) = &attr.meta { let path_idents = name_value.path.segments.iter().map(|segment| &segment.ident); if itertools::equal(path_idents, path) - && let Lit::Str(lit) = name_value.lit + && let Expr::Lit(ExprLit { lit: Lit::Str(s), .. }) = &name_value.value { - return Some(lit); + return Some(s.clone()); } } diff --git a/tests/compile-test.rs b/tests/compile-test.rs index 57890ff31737b..35d75cc51c210 100644 --- a/tests/compile-test.rs +++ b/tests/compile-test.rs @@ -126,6 +126,7 @@ fn base_config(test_dir: &str) -> compiletest::Config { let mut config = compiletest::Config { edition: Some("2021".into()), mode: TestMode::Ui, + strict_headers: true, ..Default::default() }; @@ -424,7 +425,7 @@ fn check_rustfix_coverage() { .binary_search_by_key(&filename, Path::new) .is_ok(), "`{rs_file}` runs `MachineApplicable` diagnostics but is missing a `run-rustfix` annotation. \ - Please either add `// run-rustfix` at the top of the file or add the file to \ + Please either add `//@run-rustfix` at the top of the file or add the file to \ `RUSTFIX_COVERAGE_KNOWN_EXCEPTIONS` in `tests/compile-test.rs`.", ); } diff --git a/tests/ui-cargo/cargo_common_metadata/fail/src/main.rs b/tests/ui-cargo/cargo_common_metadata/fail/src/main.rs index 27841e18aa9ef..1a69bb24101ea 100644 --- a/tests/ui-cargo/cargo_common_metadata/fail/src/main.rs +++ b/tests/ui-cargo/cargo_common_metadata/fail/src/main.rs @@ -1,4 +1,4 @@ -// compile-flags: --crate-name=cargo_common_metadata +//@compile-flags: --crate-name=cargo_common_metadata #![warn(clippy::cargo_common_metadata)] fn main() {} diff --git a/tests/ui-cargo/cargo_common_metadata/fail_publish/src/main.rs b/tests/ui-cargo/cargo_common_metadata/fail_publish/src/main.rs index 27841e18aa9ef..1a69bb24101ea 100644 --- a/tests/ui-cargo/cargo_common_metadata/fail_publish/src/main.rs +++ b/tests/ui-cargo/cargo_common_metadata/fail_publish/src/main.rs @@ -1,4 +1,4 @@ -// compile-flags: --crate-name=cargo_common_metadata +//@compile-flags: --crate-name=cargo_common_metadata #![warn(clippy::cargo_common_metadata)] fn main() {} diff --git a/tests/ui-cargo/cargo_common_metadata/fail_publish_true/src/main.rs b/tests/ui-cargo/cargo_common_metadata/fail_publish_true/src/main.rs index 27841e18aa9ef..1a69bb24101ea 100644 --- a/tests/ui-cargo/cargo_common_metadata/fail_publish_true/src/main.rs +++ b/tests/ui-cargo/cargo_common_metadata/fail_publish_true/src/main.rs @@ -1,4 +1,4 @@ -// compile-flags: --crate-name=cargo_common_metadata +//@compile-flags: --crate-name=cargo_common_metadata #![warn(clippy::cargo_common_metadata)] fn main() {} diff --git a/tests/ui-cargo/cargo_common_metadata/pass/src/main.rs b/tests/ui-cargo/cargo_common_metadata/pass/src/main.rs index 27841e18aa9ef..1a69bb24101ea 100644 --- a/tests/ui-cargo/cargo_common_metadata/pass/src/main.rs +++ b/tests/ui-cargo/cargo_common_metadata/pass/src/main.rs @@ -1,4 +1,4 @@ -// compile-flags: --crate-name=cargo_common_metadata +//@compile-flags: --crate-name=cargo_common_metadata #![warn(clippy::cargo_common_metadata)] fn main() {} diff --git a/tests/ui-cargo/cargo_common_metadata/pass_publish_empty/src/main.rs b/tests/ui-cargo/cargo_common_metadata/pass_publish_empty/src/main.rs index 27841e18aa9ef..1a69bb24101ea 100644 --- a/tests/ui-cargo/cargo_common_metadata/pass_publish_empty/src/main.rs +++ b/tests/ui-cargo/cargo_common_metadata/pass_publish_empty/src/main.rs @@ -1,4 +1,4 @@ -// compile-flags: --crate-name=cargo_common_metadata +//@compile-flags: --crate-name=cargo_common_metadata #![warn(clippy::cargo_common_metadata)] fn main() {} diff --git a/tests/ui-cargo/cargo_common_metadata/pass_publish_false/src/main.rs b/tests/ui-cargo/cargo_common_metadata/pass_publish_false/src/main.rs index 27841e18aa9ef..1a69bb24101ea 100644 --- a/tests/ui-cargo/cargo_common_metadata/pass_publish_false/src/main.rs +++ b/tests/ui-cargo/cargo_common_metadata/pass_publish_false/src/main.rs @@ -1,4 +1,4 @@ -// compile-flags: --crate-name=cargo_common_metadata +//@compile-flags: --crate-name=cargo_common_metadata #![warn(clippy::cargo_common_metadata)] fn main() {} diff --git a/tests/ui-cargo/feature_name/fail/src/main.rs b/tests/ui-cargo/feature_name/fail/src/main.rs index 64f01a98c90e9..4dd9582aff89c 100644 --- a/tests/ui-cargo/feature_name/fail/src/main.rs +++ b/tests/ui-cargo/feature_name/fail/src/main.rs @@ -1,4 +1,4 @@ -// compile-flags: --crate-name=feature_name +//@compile-flags: --crate-name=feature_name #![warn(clippy::redundant_feature_names)] #![warn(clippy::negative_feature_names)] diff --git a/tests/ui-cargo/feature_name/pass/src/main.rs b/tests/ui-cargo/feature_name/pass/src/main.rs index 64f01a98c90e9..4dd9582aff89c 100644 --- a/tests/ui-cargo/feature_name/pass/src/main.rs +++ b/tests/ui-cargo/feature_name/pass/src/main.rs @@ -1,4 +1,4 @@ -// compile-flags: --crate-name=feature_name +//@compile-flags: --crate-name=feature_name #![warn(clippy::redundant_feature_names)] #![warn(clippy::negative_feature_names)] diff --git a/tests/ui-cargo/module_style/fail_mod_remap/src/main.rs b/tests/ui-cargo/module_style/fail_mod_remap/src/main.rs index ba4c8c873dd55..c70d92e359e44 100644 --- a/tests/ui-cargo/module_style/fail_mod_remap/src/main.rs +++ b/tests/ui-cargo/module_style/fail_mod_remap/src/main.rs @@ -1,4 +1,4 @@ -// compile-flags: --remap-path-prefix {{src-base}}=/remapped +//@compile-flags: --remap-path-prefix {{src-base}}=/remapped #![warn(clippy::self_named_module_files)] diff --git a/tests/ui-cargo/multiple_crate_versions/5041_allow_dev_build/src/main.rs b/tests/ui-cargo/multiple_crate_versions/5041_allow_dev_build/src/main.rs index 1b2d3ec9459f9..ece260b743df8 100644 --- a/tests/ui-cargo/multiple_crate_versions/5041_allow_dev_build/src/main.rs +++ b/tests/ui-cargo/multiple_crate_versions/5041_allow_dev_build/src/main.rs @@ -1,4 +1,4 @@ -// compile-flags: --crate-name=multiple_crate_versions +//@compile-flags: --crate-name=multiple_crate_versions #![warn(clippy::multiple_crate_versions)] fn main() {} diff --git a/tests/ui-cargo/multiple_crate_versions/fail/src/main.rs b/tests/ui-cargo/multiple_crate_versions/fail/src/main.rs index 1b2d3ec9459f9..ece260b743df8 100644 --- a/tests/ui-cargo/multiple_crate_versions/fail/src/main.rs +++ b/tests/ui-cargo/multiple_crate_versions/fail/src/main.rs @@ -1,4 +1,4 @@ -// compile-flags: --crate-name=multiple_crate_versions +//@compile-flags: --crate-name=multiple_crate_versions #![warn(clippy::multiple_crate_versions)] fn main() {} diff --git a/tests/ui-cargo/multiple_crate_versions/pass/src/main.rs b/tests/ui-cargo/multiple_crate_versions/pass/src/main.rs index 1b2d3ec9459f9..ece260b743df8 100644 --- a/tests/ui-cargo/multiple_crate_versions/pass/src/main.rs +++ b/tests/ui-cargo/multiple_crate_versions/pass/src/main.rs @@ -1,4 +1,4 @@ -// compile-flags: --crate-name=multiple_crate_versions +//@compile-flags: --crate-name=multiple_crate_versions #![warn(clippy::multiple_crate_versions)] fn main() {} diff --git a/tests/ui-cargo/wildcard_dependencies/fail/src/main.rs b/tests/ui-cargo/wildcard_dependencies/fail/src/main.rs index 581babfeacbff..bb3a39d0720a9 100644 --- a/tests/ui-cargo/wildcard_dependencies/fail/src/main.rs +++ b/tests/ui-cargo/wildcard_dependencies/fail/src/main.rs @@ -1,4 +1,4 @@ -// compile-flags: --crate-name=wildcard_dependencies +//@compile-flags: --crate-name=wildcard_dependencies #![warn(clippy::wildcard_dependencies)] fn main() {} diff --git a/tests/ui-cargo/wildcard_dependencies/pass/src/main.rs b/tests/ui-cargo/wildcard_dependencies/pass/src/main.rs index 581babfeacbff..bb3a39d0720a9 100644 --- a/tests/ui-cargo/wildcard_dependencies/pass/src/main.rs +++ b/tests/ui-cargo/wildcard_dependencies/pass/src/main.rs @@ -1,4 +1,4 @@ -// compile-flags: --crate-name=wildcard_dependencies +//@compile-flags: --crate-name=wildcard_dependencies #![warn(clippy::wildcard_dependencies)] fn main() {} diff --git a/tests/ui-internal/collapsible_span_lint_calls.fixed b/tests/ui-internal/collapsible_span_lint_calls.fixed index 9f299d7dec720..72c04bf80b6b1 100644 --- a/tests/ui-internal/collapsible_span_lint_calls.fixed +++ b/tests/ui-internal/collapsible_span_lint_calls.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![deny(clippy::internal)] #![allow(clippy::missing_clippy_version_attribute)] #![feature(rustc_private)] diff --git a/tests/ui-internal/collapsible_span_lint_calls.rs b/tests/ui-internal/collapsible_span_lint_calls.rs index 2b113f555e46b..76f7c3ce94d67 100644 --- a/tests/ui-internal/collapsible_span_lint_calls.rs +++ b/tests/ui-internal/collapsible_span_lint_calls.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![deny(clippy::internal)] #![allow(clippy::missing_clippy_version_attribute)] #![feature(rustc_private)] diff --git a/tests/ui-internal/custom_ice_message.rs b/tests/ui-internal/custom_ice_message.rs index 837811bdf1eff..acb98d7ba98e6 100644 --- a/tests/ui-internal/custom_ice_message.rs +++ b/tests/ui-internal/custom_ice_message.rs @@ -1,9 +1,9 @@ -// rustc-env:RUST_BACKTRACE=0 -// normalize-stderr-test: "Clippy version: .*" -> "Clippy version: foo" -// normalize-stderr-test: "produce_ice.rs:\d*:\d*" -> "produce_ice.rs" -// normalize-stderr-test: "', .*clippy_lints" -> "', clippy_lints" -// normalize-stderr-test: "'rustc'" -> "''" -// normalize-stderr-test: "(?ms)query stack during panic:\n.*end of query stack\n" -> "" +//@rustc-env:RUST_BACKTRACE=0 +//@normalize-stderr-test: "Clippy version: .*" -> "Clippy version: foo" +//@normalize-stderr-test: "produce_ice.rs:\d*:\d*" -> "produce_ice.rs" +//@normalize-stderr-test: "', .*clippy_lints" -> "', clippy_lints" +//@normalize-stderr-test: "'rustc'" -> "''" +//@normalize-stderr-test: "(?ms)query stack during panic:\n.*end of query stack\n" -> "" #![deny(clippy::internal)] #![allow(clippy::missing_clippy_version_attribute)] diff --git a/tests/ui-internal/interning_defined_symbol.fixed b/tests/ui-internal/interning_defined_symbol.fixed index eaea218e12888..a1a10c0798e3a 100644 --- a/tests/ui-internal/interning_defined_symbol.fixed +++ b/tests/ui-internal/interning_defined_symbol.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![deny(clippy::internal)] #![allow(clippy::missing_clippy_version_attribute, clippy::let_unit_value)] #![feature(rustc_private)] diff --git a/tests/ui-internal/interning_defined_symbol.rs b/tests/ui-internal/interning_defined_symbol.rs index 7efebb8fae486..32dbfe5dcac22 100644 --- a/tests/ui-internal/interning_defined_symbol.rs +++ b/tests/ui-internal/interning_defined_symbol.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![deny(clippy::internal)] #![allow(clippy::missing_clippy_version_attribute, clippy::let_unit_value)] #![feature(rustc_private)] diff --git a/tests/ui-internal/invalid_msrv_attr_impl.fixed b/tests/ui-internal/invalid_msrv_attr_impl.fixed index 08634063a5754..ac0752774f3f0 100644 --- a/tests/ui-internal/invalid_msrv_attr_impl.fixed +++ b/tests/ui-internal/invalid_msrv_attr_impl.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![deny(clippy::internal)] #![allow(clippy::missing_clippy_version_attribute)] diff --git a/tests/ui-internal/invalid_msrv_attr_impl.rs b/tests/ui-internal/invalid_msrv_attr_impl.rs index f8af77e6d395c..56f778621a449 100644 --- a/tests/ui-internal/invalid_msrv_attr_impl.rs +++ b/tests/ui-internal/invalid_msrv_attr_impl.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![deny(clippy::internal)] #![allow(clippy::missing_clippy_version_attribute)] diff --git a/tests/ui-internal/outer_expn_data.fixed b/tests/ui-internal/outer_expn_data.fixed index bb82faf0c9047..d8a08bc999709 100644 --- a/tests/ui-internal/outer_expn_data.fixed +++ b/tests/ui-internal/outer_expn_data.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![deny(clippy::internal)] #![allow(clippy::missing_clippy_version_attribute)] diff --git a/tests/ui-internal/outer_expn_data.rs b/tests/ui-internal/outer_expn_data.rs index 187d468b39251..f7af0e9d8be2e 100644 --- a/tests/ui-internal/outer_expn_data.rs +++ b/tests/ui-internal/outer_expn_data.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![deny(clippy::internal)] #![allow(clippy::missing_clippy_version_attribute)] diff --git a/tests/ui-internal/unnecessary_def_path.fixed b/tests/ui-internal/unnecessary_def_path.fixed index e474f370a5d17..fce24412f8439 100644 --- a/tests/ui-internal/unnecessary_def_path.fixed +++ b/tests/ui-internal/unnecessary_def_path.fixed @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:paths.rs +//@run-rustfix +//@aux-build:paths.rs #![deny(clippy::internal)] #![feature(rustc_private)] diff --git a/tests/ui-internal/unnecessary_def_path.rs b/tests/ui-internal/unnecessary_def_path.rs index f17fed6c65304..b10bc9e46e2d7 100644 --- a/tests/ui-internal/unnecessary_def_path.rs +++ b/tests/ui-internal/unnecessary_def_path.rs @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:paths.rs +//@run-rustfix +//@aux-build:paths.rs #![deny(clippy::internal)] #![feature(rustc_private)] diff --git a/tests/ui-internal/unnecessary_symbol_str.fixed b/tests/ui-internal/unnecessary_symbol_str.fixed index 6033d06e4f637..b802de1cbc650 100644 --- a/tests/ui-internal/unnecessary_symbol_str.fixed +++ b/tests/ui-internal/unnecessary_symbol_str.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(rustc_private)] #![deny(clippy::internal)] #![allow( diff --git a/tests/ui-internal/unnecessary_symbol_str.rs b/tests/ui-internal/unnecessary_symbol_str.rs index 1bb5d55f0b60c..c1bead5bdc98e 100644 --- a/tests/ui-internal/unnecessary_symbol_str.rs +++ b/tests/ui-internal/unnecessary_symbol_str.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(rustc_private)] #![deny(clippy::internal)] #![allow( diff --git a/tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.fixed b/tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.fixed index aa8b45b5fe7d4..23e7bc16d239a 100644 --- a/tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.fixed +++ b/tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::uninlined_format_args)] fn main() { diff --git a/tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.rs b/tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.rs index ad2e4863ee8ed..d66b2b8ff6a03 100644 --- a/tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.rs +++ b/tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::uninlined_format_args)] fn main() { diff --git a/tests/ui-toml/dbg_macro/dbg_macro.rs b/tests/ui-toml/dbg_macro/dbg_macro.rs index 5d9ce18f631b6..21e4fce26e4e6 100644 --- a/tests/ui-toml/dbg_macro/dbg_macro.rs +++ b/tests/ui-toml/dbg_macro/dbg_macro.rs @@ -1,4 +1,4 @@ -// compile-flags: --test +//@compile-flags: --test #![warn(clippy::dbg_macro)] fn foo(n: u32) -> u32 { diff --git a/tests/ui-toml/disallowed_macros/disallowed_macros.rs b/tests/ui-toml/disallowed_macros/disallowed_macros.rs index 2bb5376076e28..ba919b4878854 100644 --- a/tests/ui-toml/disallowed_macros/disallowed_macros.rs +++ b/tests/ui-toml/disallowed_macros/disallowed_macros.rs @@ -1,4 +1,4 @@ -// aux-build:macros.rs +//@aux-build:macros.rs #![allow(unused)] diff --git a/tests/ui-toml/expect_used/expect_used.rs b/tests/ui-toml/expect_used/expect_used.rs index 89f142a150d95..9e267c893005f 100644 --- a/tests/ui-toml/expect_used/expect_used.rs +++ b/tests/ui-toml/expect_used/expect_used.rs @@ -1,4 +1,4 @@ -// compile-flags: --test +//@compile-flags: --test #![warn(clippy::expect_used)] fn expect_option() { diff --git a/tests/ui-toml/mut_key/mut_key.rs b/tests/ui-toml/mut_key/mut_key.rs index 667c51cb4a3f3..095e0d15448a7 100644 --- a/tests/ui-toml/mut_key/mut_key.rs +++ b/tests/ui-toml/mut_key/mut_key.rs @@ -1,4 +1,4 @@ -// compile-flags: --crate-name mut_key +//@compile-flags: --crate-name mut_key #![warn(clippy::mutable_key_type)] diff --git a/tests/ui-toml/nonstandard_macro_braces/auxiliary/proc_macro_derive.rs b/tests/ui-toml/nonstandard_macro_braces/auxiliary/proc_macro_derive.rs index 6452189a4615b..f5761c6afeb37 100644 --- a/tests/ui-toml/nonstandard_macro_braces/auxiliary/proc_macro_derive.rs +++ b/tests/ui-toml/nonstandard_macro_braces/auxiliary/proc_macro_derive.rs @@ -1,5 +1,5 @@ -// compile-flags: --emit=link -// no-prefer-dynamic +//@compile-flags: --emit=link +//@no-prefer-dynamic #![crate_type = "proc-macro"] diff --git a/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.fixed b/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.fixed index 01d135764dffd..e4747bedddb88 100644 --- a/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.fixed +++ b/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.fixed @@ -1,5 +1,5 @@ -// aux-build:proc_macro_derive.rs -// run-rustfix +//@aux-build:proc_macro_derive.rs +//@run-rustfix #![warn(clippy::nonstandard_macro_braces)] diff --git a/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs b/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs index 72883e8270c3b..54edded99f41b 100644 --- a/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs +++ b/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs @@ -1,5 +1,5 @@ -// aux-build:proc_macro_derive.rs -// run-rustfix +//@aux-build:proc_macro_derive.rs +//@run-rustfix #![warn(clippy::nonstandard_macro_braces)] diff --git a/tests/ui-toml/print_macro/print_macro.rs b/tests/ui-toml/print_macro/print_macro.rs index 5aefb6a6b4d46..3a8b30cca36a6 100644 --- a/tests/ui-toml/print_macro/print_macro.rs +++ b/tests/ui-toml/print_macro/print_macro.rs @@ -1,4 +1,4 @@ -// compile-flags: --test +//@compile-flags: --test #![warn(clippy::print_stdout)] #![warn(clippy::print_stderr)] diff --git a/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs b/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs index 2f3160c833833..8e1a1710a6ce2 100644 --- a/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs +++ b/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs @@ -1,4 +1,4 @@ -// compile-flags: --crate-name conf_disallowed_methods +//@compile-flags: --crate-name conf_disallowed_methods #![warn(clippy::disallowed_methods)] diff --git a/tests/ui-toml/toml_trivially_copy/test.rs b/tests/ui-toml/toml_trivially_copy/test.rs index fb0e226f3aa40..179b1266169ef 100644 --- a/tests/ui-toml/toml_trivially_copy/test.rs +++ b/tests/ui-toml/toml_trivially_copy/test.rs @@ -1,5 +1,5 @@ -// normalize-stderr-test "\(\d+ byte\)" -> "(N byte)" -// normalize-stderr-test "\(limit: \d+ byte\)" -> "(limit: N byte)" +//@normalize-stderr-test: "\(\d+ byte\)" -> "(N byte)" +//@normalize-stderr-test: "\(limit: \d+ byte\)" -> "(limit: N byte)" #![deny(clippy::trivially_copy_pass_by_ref)] diff --git a/tests/ui-toml/toml_unknown_key/conf_unknown_key.rs b/tests/ui-toml/toml_unknown_key/conf_unknown_key.rs index f328e4d9d04c3..569fd2c3553b1 100644 --- a/tests/ui-toml/toml_unknown_key/conf_unknown_key.rs +++ b/tests/ui-toml/toml_unknown_key/conf_unknown_key.rs @@ -1 +1,3 @@ +//@error-pattern: unknown field `foobar`, expected one of + fn main() {} diff --git a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr index 8447c31722dd0..36b372b36f4fa 100644 --- a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr +++ b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr @@ -46,6 +46,7 @@ error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown fie too-many-lines-threshold trivial-copy-size-limit type-complexity-threshold + unnecessary-box-size unreadable-literal-lint-fractions upper-case-acronyms-aggressive vec-box-size-threshold diff --git a/tests/ui-toml/unwrap_used/unwrap_used.rs b/tests/ui-toml/unwrap_used/unwrap_used.rs index 6525ea5bfc3fc..5d3e800caddfe 100644 --- a/tests/ui-toml/unwrap_used/unwrap_used.rs +++ b/tests/ui-toml/unwrap_used/unwrap_used.rs @@ -1,4 +1,4 @@ -// compile-flags: --test +//@compile-flags: --test #![allow(unused_mut, clippy::get_first, clippy::from_iter_instead_of_collect)] #![warn(clippy::unwrap_used)] diff --git a/tests/ui/allow_attributes.fixed b/tests/ui/allow_attributes.fixed index b8dd0619e6d00..f0936b2608e9e 100644 --- a/tests/ui/allow_attributes.fixed +++ b/tests/ui/allow_attributes.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] #![warn(clippy::allow_attributes)] #![feature(lint_reasons)] diff --git a/tests/ui/allow_attributes.rs b/tests/ui/allow_attributes.rs index 295f560906a78..2fb9e86126e55 100644 --- a/tests/ui/allow_attributes.rs +++ b/tests/ui/allow_attributes.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] #![warn(clippy::allow_attributes)] #![feature(lint_reasons)] diff --git a/tests/ui/almost_complete_range.fixed b/tests/ui/almost_complete_range.fixed index a4bf7fe18d5f4..5cd0dcce6f765 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:proc_macros.rs +//@run-rustfix +//@edition:2018 +//@aux-build:proc_macros.rs #![feature(exclusive_range_pattern)] #![feature(stmt_expr_attributes)] diff --git a/tests/ui/almost_complete_range.rs b/tests/ui/almost_complete_range.rs index 8237c3a13611a..db0bfc8afc39a 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:proc_macros.rs +//@run-rustfix +//@edition:2018 +//@aux-build:proc_macros.rs #![feature(exclusive_range_pattern)] #![feature(stmt_expr_attributes)] diff --git a/tests/ui/arithmetic_side_effects.rs b/tests/ui/arithmetic_side_effects.rs index 3c06676d7228a..ab408bdf261ef 100644 --- a/tests/ui/arithmetic_side_effects.rs +++ b/tests/ui/arithmetic_side_effects.rs @@ -1,3 +1,5 @@ +//@aux-build:proc_macro_derive.rs + #![allow( clippy::assign_op_pattern, clippy::erasing_op, @@ -11,6 +13,8 @@ #![feature(const_mut_refs, inline_const, saturating_int_impl)] #![warn(clippy::arithmetic_side_effects)] +extern crate proc_macro_derive; + use core::num::{Saturating, Wrapping}; const ONE: i32 = 1; @@ -19,6 +23,9 @@ const ZERO: i32 = 0; #[derive(Clone, Copy)] pub struct Custom; +#[derive(proc_macro_derive::ShadowDerive)] +pub struct Nothing; + macro_rules! impl_arith { ( $( $_trait:ident, $lhs:ty, $rhs:ty, $method:ident; )* ) => { $( @@ -269,6 +276,17 @@ pub fn non_overflowing_ops_or_ops_already_handled_by_the_compiler_should_not_tri _n = &1 * _n; _n = 23 + 85; + // Method + _n.saturating_div(1); + _n.wrapping_div(1); + _n.wrapping_rem(1); + _n.wrapping_rem_euclid(1); + + _n.saturating_div(1); + _n.checked_div(1); + _n.checked_rem(1); + _n.checked_rem_euclid(1); + // Unary _n = -2147483647; _n = -i32::MAX; @@ -376,6 +394,17 @@ pub fn unknown_ops_or_runtime_ops_that_can_overflow() { _custom = Custom << _custom; _custom = &Custom << _custom; + // Method + _n.saturating_div(0); + _n.wrapping_div(0); + _n.wrapping_rem(0); + _n.wrapping_rem_euclid(0); + + _n.saturating_div(_n); + _n.wrapping_div(_n); + _n.wrapping_rem(_n); + _n.wrapping_rem_euclid(_n); + // Unary _n = -_n; _n = -&_n; diff --git a/tests/ui/arithmetic_side_effects.stderr b/tests/ui/arithmetic_side_effects.stderr index 2c8ee2884e732..e9a626643ff78 100644 --- a/tests/ui/arithmetic_side_effects.stderr +++ b/tests/ui/arithmetic_side_effects.stderr @@ -1,5 +1,5 @@ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:286:5 + --> $DIR/arithmetic_side_effects.rs:304:5 | LL | _n += 1; | ^^^^^^^ @@ -7,652 +7,700 @@ LL | _n += 1; = note: `-D clippy::arithmetic-side-effects` implied by `-D warnings` error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:287:5 + --> $DIR/arithmetic_side_effects.rs:305:5 | LL | _n += &1; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:288:5 + --> $DIR/arithmetic_side_effects.rs:306:5 | LL | _n -= 1; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:289:5 + --> $DIR/arithmetic_side_effects.rs:307:5 | LL | _n -= &1; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:290:5 + --> $DIR/arithmetic_side_effects.rs:308:5 | LL | _n /= 0; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:291:5 + --> $DIR/arithmetic_side_effects.rs:309:5 | LL | _n /= &0; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:292:5 + --> $DIR/arithmetic_side_effects.rs:310:5 | LL | _n %= 0; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:293:5 + --> $DIR/arithmetic_side_effects.rs:311:5 | LL | _n %= &0; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:294:5 + --> $DIR/arithmetic_side_effects.rs:312:5 | LL | _n *= 2; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:295:5 + --> $DIR/arithmetic_side_effects.rs:313:5 | LL | _n *= &2; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:296:5 + --> $DIR/arithmetic_side_effects.rs:314:5 | LL | _n += -1; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:297:5 + --> $DIR/arithmetic_side_effects.rs:315:5 | LL | _n += &-1; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:298:5 + --> $DIR/arithmetic_side_effects.rs:316:5 | LL | _n -= -1; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:299:5 + --> $DIR/arithmetic_side_effects.rs:317:5 | LL | _n -= &-1; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:300:5 + --> $DIR/arithmetic_side_effects.rs:318:5 | LL | _n /= -0; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:301:5 + --> $DIR/arithmetic_side_effects.rs:319:5 | LL | _n /= &-0; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:302:5 + --> $DIR/arithmetic_side_effects.rs:320:5 | LL | _n %= -0; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:303:5 + --> $DIR/arithmetic_side_effects.rs:321:5 | LL | _n %= &-0; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:304:5 + --> $DIR/arithmetic_side_effects.rs:322:5 | LL | _n *= -2; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:305:5 + --> $DIR/arithmetic_side_effects.rs:323:5 | LL | _n *= &-2; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:306:5 + --> $DIR/arithmetic_side_effects.rs:324:5 | LL | _custom += Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:307:5 + --> $DIR/arithmetic_side_effects.rs:325:5 | LL | _custom += &Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:308:5 + --> $DIR/arithmetic_side_effects.rs:326:5 | LL | _custom -= Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:309:5 + --> $DIR/arithmetic_side_effects.rs:327:5 | LL | _custom -= &Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:310:5 + --> $DIR/arithmetic_side_effects.rs:328:5 | LL | _custom /= Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:311:5 + --> $DIR/arithmetic_side_effects.rs:329:5 | LL | _custom /= &Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:312:5 + --> $DIR/arithmetic_side_effects.rs:330:5 | LL | _custom %= Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:313:5 + --> $DIR/arithmetic_side_effects.rs:331:5 | LL | _custom %= &Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:314:5 + --> $DIR/arithmetic_side_effects.rs:332:5 | LL | _custom *= Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:315:5 + --> $DIR/arithmetic_side_effects.rs:333:5 | LL | _custom *= &Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:316:5 + --> $DIR/arithmetic_side_effects.rs:334:5 | LL | _custom >>= Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:317:5 + --> $DIR/arithmetic_side_effects.rs:335:5 | LL | _custom >>= &Custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:318:5 + --> $DIR/arithmetic_side_effects.rs:336:5 | LL | _custom <<= Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:319:5 + --> $DIR/arithmetic_side_effects.rs:337:5 | LL | _custom <<= &Custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:320:5 + --> $DIR/arithmetic_side_effects.rs:338:5 | LL | _custom += -Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:321:5 + --> $DIR/arithmetic_side_effects.rs:339:5 | LL | _custom += &-Custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:322:5 + --> $DIR/arithmetic_side_effects.rs:340:5 | LL | _custom -= -Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:323:5 + --> $DIR/arithmetic_side_effects.rs:341:5 | LL | _custom -= &-Custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:324:5 + --> $DIR/arithmetic_side_effects.rs:342:5 | LL | _custom /= -Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:325:5 + --> $DIR/arithmetic_side_effects.rs:343:5 | LL | _custom /= &-Custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:326:5 + --> $DIR/arithmetic_side_effects.rs:344:5 | LL | _custom %= -Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:327:5 + --> $DIR/arithmetic_side_effects.rs:345:5 | LL | _custom %= &-Custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:328:5 + --> $DIR/arithmetic_side_effects.rs:346:5 | LL | _custom *= -Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:329:5 + --> $DIR/arithmetic_side_effects.rs:347:5 | LL | _custom *= &-Custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:330:5 + --> $DIR/arithmetic_side_effects.rs:348:5 | LL | _custom >>= -Custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:331:5 + --> $DIR/arithmetic_side_effects.rs:349:5 | LL | _custom >>= &-Custom; | ^^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:332:5 + --> $DIR/arithmetic_side_effects.rs:350:5 | LL | _custom <<= -Custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:333:5 + --> $DIR/arithmetic_side_effects.rs:351:5 | LL | _custom <<= &-Custom; | ^^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:336:10 + --> $DIR/arithmetic_side_effects.rs:354:10 | LL | _n = _n + 1; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:337:10 + --> $DIR/arithmetic_side_effects.rs:355:10 | LL | _n = _n + &1; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:338:10 + --> $DIR/arithmetic_side_effects.rs:356:10 | LL | _n = 1 + _n; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:339:10 + --> $DIR/arithmetic_side_effects.rs:357:10 | LL | _n = &1 + _n; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:340:10 + --> $DIR/arithmetic_side_effects.rs:358:10 | LL | _n = _n - 1; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:341:10 + --> $DIR/arithmetic_side_effects.rs:359:10 | LL | _n = _n - &1; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:342:10 + --> $DIR/arithmetic_side_effects.rs:360:10 | LL | _n = 1 - _n; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:343:10 + --> $DIR/arithmetic_side_effects.rs:361:10 | LL | _n = &1 - _n; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:344:10 + --> $DIR/arithmetic_side_effects.rs:362:10 | LL | _n = _n / 0; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:345:10 + --> $DIR/arithmetic_side_effects.rs:363:10 | LL | _n = _n / &0; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:346:10 + --> $DIR/arithmetic_side_effects.rs:364:10 | LL | _n = _n % 0; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:347:10 + --> $DIR/arithmetic_side_effects.rs:365:10 | LL | _n = _n % &0; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:348:10 + --> $DIR/arithmetic_side_effects.rs:366:10 | LL | _n = _n * 2; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:349:10 + --> $DIR/arithmetic_side_effects.rs:367:10 | LL | _n = _n * &2; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:350:10 + --> $DIR/arithmetic_side_effects.rs:368:10 | LL | _n = 2 * _n; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:351:10 + --> $DIR/arithmetic_side_effects.rs:369:10 | LL | _n = &2 * _n; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:352:10 + --> $DIR/arithmetic_side_effects.rs:370:10 | LL | _n = 23 + &85; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:353:10 + --> $DIR/arithmetic_side_effects.rs:371:10 | LL | _n = &23 + 85; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:354:10 + --> $DIR/arithmetic_side_effects.rs:372:10 | LL | _n = &23 + &85; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:355:15 + --> $DIR/arithmetic_side_effects.rs:373:15 | LL | _custom = _custom + _custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:356:15 + --> $DIR/arithmetic_side_effects.rs:374:15 | LL | _custom = _custom + &_custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:357:15 + --> $DIR/arithmetic_side_effects.rs:375:15 | LL | _custom = Custom + _custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:358:15 + --> $DIR/arithmetic_side_effects.rs:376:15 | LL | _custom = &Custom + _custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:359:15 + --> $DIR/arithmetic_side_effects.rs:377:15 | LL | _custom = _custom - Custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:360:15 + --> $DIR/arithmetic_side_effects.rs:378:15 | LL | _custom = _custom - &Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:361:15 + --> $DIR/arithmetic_side_effects.rs:379:15 | LL | _custom = Custom - _custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:362:15 + --> $DIR/arithmetic_side_effects.rs:380:15 | LL | _custom = &Custom - _custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:363:15 + --> $DIR/arithmetic_side_effects.rs:381:15 | LL | _custom = _custom / Custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:364:15 + --> $DIR/arithmetic_side_effects.rs:382:15 | LL | _custom = _custom / &Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:365:15 + --> $DIR/arithmetic_side_effects.rs:383:15 | LL | _custom = _custom % Custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:366:15 + --> $DIR/arithmetic_side_effects.rs:384:15 | LL | _custom = _custom % &Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:367:15 + --> $DIR/arithmetic_side_effects.rs:385:15 | LL | _custom = _custom * Custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:368:15 + --> $DIR/arithmetic_side_effects.rs:386:15 | LL | _custom = _custom * &Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:369:15 + --> $DIR/arithmetic_side_effects.rs:387:15 | LL | _custom = Custom * _custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:370:15 + --> $DIR/arithmetic_side_effects.rs:388:15 | LL | _custom = &Custom * _custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:371:15 + --> $DIR/arithmetic_side_effects.rs:389:15 | LL | _custom = Custom + &Custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:372:15 + --> $DIR/arithmetic_side_effects.rs:390:15 | LL | _custom = &Custom + Custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:373:15 + --> $DIR/arithmetic_side_effects.rs:391:15 | LL | _custom = &Custom + &Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:374:15 + --> $DIR/arithmetic_side_effects.rs:392:15 | LL | _custom = _custom >> _custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:375:15 + --> $DIR/arithmetic_side_effects.rs:393:15 | LL | _custom = _custom >> &_custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:376:15 + --> $DIR/arithmetic_side_effects.rs:394:15 | LL | _custom = Custom << _custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:377:15 + --> $DIR/arithmetic_side_effects.rs:395:15 | LL | _custom = &Custom << _custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:380:10 + --> $DIR/arithmetic_side_effects.rs:398:23 + | +LL | _n.saturating_div(0); + | ^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:399:21 + | +LL | _n.wrapping_div(0); + | ^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:400:21 + | +LL | _n.wrapping_rem(0); + | ^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:401:28 + | +LL | _n.wrapping_rem_euclid(0); + | ^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:403:23 + | +LL | _n.saturating_div(_n); + | ^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:404:21 + | +LL | _n.wrapping_div(_n); + | ^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:405:21 + | +LL | _n.wrapping_rem(_n); + | ^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:406:28 + | +LL | _n.wrapping_rem_euclid(_n); + | ^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:409:10 | LL | _n = -_n; | ^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:381:10 + --> $DIR/arithmetic_side_effects.rs:410:10 | LL | _n = -&_n; | ^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:382:15 + --> $DIR/arithmetic_side_effects.rs:411:15 | LL | _custom = -_custom; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:383:15 + --> $DIR/arithmetic_side_effects.rs:412:15 | LL | _custom = -&_custom; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:392:5 + --> $DIR/arithmetic_side_effects.rs:421:5 | LL | 1 + i; | ^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:393:5 + --> $DIR/arithmetic_side_effects.rs:422:5 | LL | i * 2; | ^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:394:5 + --> $DIR/arithmetic_side_effects.rs:423:5 | LL | 1 % i / 2; | ^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:395:5 + --> $DIR/arithmetic_side_effects.rs:424:5 | LL | i - 2 + 2 - i; | ^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:396:5 + --> $DIR/arithmetic_side_effects.rs:425:5 | LL | -i; | ^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:407:5 + --> $DIR/arithmetic_side_effects.rs:436:5 | LL | i += 1; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:408:5 + --> $DIR/arithmetic_side_effects.rs:437:5 | LL | i -= 1; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:409:5 + --> $DIR/arithmetic_side_effects.rs:438:5 | LL | i *= 2; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:411:5 + --> $DIR/arithmetic_side_effects.rs:440:5 | LL | i /= 0; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:413:5 + --> $DIR/arithmetic_side_effects.rs:442:5 | LL | i /= var1; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:414:5 + --> $DIR/arithmetic_side_effects.rs:443:5 | LL | i /= var2; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:416:5 + --> $DIR/arithmetic_side_effects.rs:445:5 | LL | i %= 0; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:418:5 + --> $DIR/arithmetic_side_effects.rs:447:5 | LL | i %= var1; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:419:5 + --> $DIR/arithmetic_side_effects.rs:448:5 | LL | i %= var2; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:429:5 + --> $DIR/arithmetic_side_effects.rs:458:5 | LL | 10 / a | ^^^^^^ -error: aborting due to 109 previous errors +error: aborting due to 117 previous errors diff --git a/tests/ui/as_conversions.rs b/tests/ui/as_conversions.rs index c50d4088b5ebb..890bf0b0a7eb2 100644 --- a/tests/ui/as_conversions.rs +++ b/tests/ui/as_conversions.rs @@ -1,4 +1,4 @@ -// aux-build:proc_macros.rs +//@aux-build:proc_macros.rs #![warn(clippy::as_conversions)] #![allow(clippy::borrow_as_ptr)] diff --git a/tests/ui/as_underscore.fixed b/tests/ui/as_underscore.fixed index 948f6d8e6b10b..69af84a0eaec5 100644 --- a/tests/ui/as_underscore.fixed +++ b/tests/ui/as_underscore.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::as_underscore)] diff --git a/tests/ui/as_underscore.rs b/tests/ui/as_underscore.rs index 97785ed08a8d0..a8cfb81d9a3f0 100644 --- a/tests/ui/as_underscore.rs +++ b/tests/ui/as_underscore.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::as_underscore)] diff --git a/tests/ui/asm_syntax.rs b/tests/ui/asm_syntax.rs index 0220bf3331f5b..c93995f939acc 100644 --- a/tests/ui/asm_syntax.rs +++ b/tests/ui/asm_syntax.rs @@ -1,5 +1,5 @@ -// only-x86_64 -// ignore-aarch64 +//@only-x86_64 +//@ignore-aarch64 #[warn(clippy::inline_asm_x86_intel_syntax)] mod warn_intel { diff --git a/tests/ui/assertions_on_result_states.fixed b/tests/ui/assertions_on_result_states.fixed index 2bb755290c508..ea8b895664c49 100644 --- a/tests/ui/assertions_on_result_states.fixed +++ b/tests/ui/assertions_on_result_states.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::assertions_on_result_states)] use std::result::Result; diff --git a/tests/ui/assertions_on_result_states.rs b/tests/ui/assertions_on_result_states.rs index d8a9bd2f1c455..6fc20f8598872 100644 --- a/tests/ui/assertions_on_result_states.rs +++ b/tests/ui/assertions_on_result_states.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::assertions_on_result_states)] use std::result::Result; diff --git a/tests/ui/assign_ops.fixed b/tests/ui/assign_ops.fixed index da034b51cfdb9..b50682ea00c44 100644 --- a/tests/ui/assign_ops.fixed +++ b/tests/ui/assign_ops.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix use core::num::Wrapping; diff --git a/tests/ui/assign_ops.rs b/tests/ui/assign_ops.rs index 337bb02c8a612..780d2d040f124 100644 --- a/tests/ui/assign_ops.rs +++ b/tests/ui/assign_ops.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix use core::num::Wrapping; diff --git a/tests/ui/async_yields_async.fixed b/tests/ui/async_yields_async.fixed index 579a63ea47722..8d9b023893f79 100644 --- a/tests/ui/async_yields_async.fixed +++ b/tests/ui/async_yields_async.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(lint_reasons)] #![feature(async_closure)] #![warn(clippy::async_yields_async)] diff --git a/tests/ui/async_yields_async.rs b/tests/ui/async_yields_async.rs index 5aec2fb50f6a1..bed79062f015e 100644 --- a/tests/ui/async_yields_async.rs +++ b/tests/ui/async_yields_async.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(lint_reasons)] #![feature(async_closure)] #![warn(clippy::async_yields_async)] diff --git a/tests/ui/author/blocks.rs b/tests/ui/author/blocks.rs index a7335c01baa39..164f7d0d9d6c5 100644 --- a/tests/ui/author/blocks.rs +++ b/tests/ui/author/blocks.rs @@ -1,4 +1,4 @@ -// edition:2018 +//@edition:2018 #![allow(redundant_semicolons, clippy::no_effect)] #![feature(stmt_expr_attributes)] diff --git a/tests/ui/auxiliary/proc_macro_attr.rs b/tests/ui/auxiliary/proc_macro_attr.rs index 4914f14b58ff7..92c47b41a38f9 100644 --- a/tests/ui/auxiliary/proc_macro_attr.rs +++ b/tests/ui/auxiliary/proc_macro_attr.rs @@ -1,5 +1,5 @@ -// compile-flags: --emit=link -// no-prefer-dynamic +//@compile-flags: --emit=link +//@no-prefer-dynamic #![crate_type = "proc-macro"] #![feature(repr128, proc_macro_hygiene, proc_macro_quote, box_patterns)] @@ -28,7 +28,7 @@ pub fn dummy(_args: TokenStream, input: TokenStream) -> TokenStream { pub fn fake_async_trait(_args: TokenStream, input: TokenStream) -> TokenStream { let mut item = parse_macro_input!(input as ItemTrait); for inner in &mut item.items { - if let TraitItem::Method(method) = inner { + if let TraitItem::Fn(method) = inner { let sig = &method.sig; let block = &mut method.default; if let Some(block) = block { @@ -70,7 +70,7 @@ pub fn rename_my_lifetimes(_args: TokenStream, input: TokenStream) -> TokenStrea // Look for methods having arbitrary self type taken by &mut ref for inner in &mut item.items { - if let ImplItem::Method(method) = inner { + if let ImplItem::Fn(method) = inner { if let Some(FnArg::Typed(pat_type)) = mut_receiver_of(&mut method.sig) { if let box Type::Reference(reference) = &mut pat_type.ty { // Target only unnamed lifetimes diff --git a/tests/ui/auxiliary/proc_macro_derive.rs b/tests/ui/auxiliary/proc_macro_derive.rs index a89a06308d093..5a924ca1830a4 100644 --- a/tests/ui/auxiliary/proc_macro_derive.rs +++ b/tests/ui/auxiliary/proc_macro_derive.rs @@ -1,5 +1,5 @@ -// compile-flags: --emit=link -// no-prefer-dynamic +//@compile-flags: --emit=link +//@no-prefer-dynamic #![crate_type = "proc-macro"] #![feature(repr128, proc_macro_quote)] @@ -9,7 +9,7 @@ extern crate proc_macro; -use proc_macro::{quote, TokenStream}; +use proc_macro::{quote, Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree}; #[proc_macro_derive(DeriveSomething)] pub fn derive(_: TokenStream) -> TokenStream { @@ -86,3 +86,74 @@ pub fn extra_lifetime(_input: TokenStream) -> TokenStream { } ) } + +#[allow(unused)] +#[proc_macro_derive(ArithmeticDerive)] +pub fn arithmetic_derive(_: TokenStream) -> TokenStream { + >::from_iter( + [ + Ident::new("fn", Span::call_site()).into(), + Ident::new("_foo", Span::call_site()).into(), + Group::new(Delimiter::Parenthesis, TokenStream::new()).into(), + Group::new( + Delimiter::Brace, + >::from_iter( + [ + Ident::new("let", Span::call_site()).into(), + Ident::new("mut", Span::call_site()).into(), + Ident::new("_n", Span::call_site()).into(), + Punct::new('=', Spacing::Alone).into(), + Literal::i32_unsuffixed(9).into(), + Punct::new(';', Spacing::Alone).into(), + Ident::new("_n", Span::call_site()).into(), + Punct::new('=', Spacing::Alone).into(), + Literal::i32_unsuffixed(9).into(), + Punct::new('/', Spacing::Alone).into(), + Literal::i32_unsuffixed(2).into(), + Punct::new(';', Spacing::Alone).into(), + Ident::new("_n", Span::call_site()).into(), + Punct::new('=', Spacing::Alone).into(), + Punct::new('-', Spacing::Alone).into(), + Ident::new("_n", Span::call_site()).into(), + Punct::new(';', Spacing::Alone).into(), + ] + .into_iter(), + ), + ) + .into(), + ] + .into_iter(), + ) +} + +#[allow(unused)] +#[proc_macro_derive(ShadowDerive)] +pub fn shadow_derive(_: TokenStream) -> TokenStream { + >::from_iter( + [ + Ident::new("fn", Span::call_site()).into(), + Ident::new("_foo", Span::call_site()).into(), + Group::new(Delimiter::Parenthesis, TokenStream::new()).into(), + Group::new( + Delimiter::Brace, + >::from_iter( + [ + Ident::new("let", Span::call_site()).into(), + Ident::new("_x", Span::call_site()).into(), + Punct::new('=', Spacing::Alone).into(), + Literal::i32_unsuffixed(2).into(), + Punct::new(';', Spacing::Alone).into(), + Ident::new("let", Span::call_site()).into(), + Ident::new("_x", Span::call_site()).into(), + Punct::new('=', Spacing::Alone).into(), + Ident::new("_x", Span::call_site()).into(), + Punct::new(';', Spacing::Alone).into(), + ] + .into_iter(), + ), + ) + .into(), + ] + .into_iter(), + ) +} diff --git a/tests/ui/auxiliary/proc_macro_suspicious_else_formatting.rs b/tests/ui/auxiliary/proc_macro_suspicious_else_formatting.rs index a2ef0fe827c01..f13b76e44b04f 100644 --- a/tests/ui/auxiliary/proc_macro_suspicious_else_formatting.rs +++ b/tests/ui/auxiliary/proc_macro_suspicious_else_formatting.rs @@ -1,5 +1,5 @@ -// compile-flags: --emit=link -// no-prefer-dynamic +//@compile-flags: --emit=link +//@no-prefer-dynamic #![crate_type = "proc-macro"] diff --git a/tests/ui/auxiliary/proc_macro_unsafe.rs b/tests/ui/auxiliary/proc_macro_unsafe.rs index 3c40f77469b82..c2326678d0d52 100644 --- a/tests/ui/auxiliary/proc_macro_unsafe.rs +++ b/tests/ui/auxiliary/proc_macro_unsafe.rs @@ -1,5 +1,5 @@ -// compile-flags: --emit=link -// no-prefer-dynamic +//@compile-flags: --emit=link +//@no-prefer-dynamic #![crate_type = "proc-macro"] diff --git a/tests/ui/auxiliary/proc_macros.rs b/tests/ui/auxiliary/proc_macros.rs index 3d5beab1eff1c..94f075ed09cce 100644 --- a/tests/ui/auxiliary/proc_macros.rs +++ b/tests/ui/auxiliary/proc_macros.rs @@ -1,5 +1,5 @@ -// compile-flags: --emit=link -// no-prefer-dynamic +//@compile-flags: --emit=link +//@no-prefer-dynamic #![crate_type = "proc-macro"] #![feature(let_chains)] diff --git a/tests/ui/bind_instead_of_map.fixed b/tests/ui/bind_instead_of_map.fixed index d94e2ac6072d4..ea2dc2e229327 100644 --- a/tests/ui/bind_instead_of_map.fixed +++ b/tests/ui/bind_instead_of_map.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![deny(clippy::bind_instead_of_map)] #![allow(clippy::uninlined_format_args)] diff --git a/tests/ui/bind_instead_of_map.rs b/tests/ui/bind_instead_of_map.rs index 86f31f58284aa..1db58dae53860 100644 --- a/tests/ui/bind_instead_of_map.rs +++ b/tests/ui/bind_instead_of_map.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![deny(clippy::bind_instead_of_map)] #![allow(clippy::uninlined_format_args)] diff --git a/tests/ui/bind_instead_of_map_multipart.fixed b/tests/ui/bind_instead_of_map_multipart.fixed index e1589843226c4..63c7aafcddb2c 100644 --- a/tests/ui/bind_instead_of_map_multipart.fixed +++ b/tests/ui/bind_instead_of_map_multipart.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![deny(clippy::bind_instead_of_map)] #![allow(clippy::blocks_in_if_conditions)] diff --git a/tests/ui/bind_instead_of_map_multipart.rs b/tests/ui/bind_instead_of_map_multipart.rs index 49944403f6ddd..69b982fa8a21b 100644 --- a/tests/ui/bind_instead_of_map_multipart.rs +++ b/tests/ui/bind_instead_of_map_multipart.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![deny(clippy::bind_instead_of_map)] #![allow(clippy::blocks_in_if_conditions)] diff --git a/tests/ui/blanket_clippy_restriction_lints.rs b/tests/ui/blanket_clippy_restriction_lints.rs index 554745368bca4..e1ff25c54cfcb 100644 --- a/tests/ui/blanket_clippy_restriction_lints.rs +++ b/tests/ui/blanket_clippy_restriction_lints.rs @@ -1,4 +1,4 @@ -// compile-flags: -W clippy::restriction +//@compile-flags: -W clippy::restriction #![warn(clippy::blanket_clippy_restriction_lints)] diff --git a/tests/ui/blocks_in_if_conditions.fixed b/tests/ui/blocks_in_if_conditions.fixed index e6e40a9948c91..a9f18782e58b7 100644 --- a/tests/ui/blocks_in_if_conditions.fixed +++ b/tests/ui/blocks_in_if_conditions.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::blocks_in_if_conditions)] #![allow(unused, clippy::let_and_return)] #![warn(clippy::nonminimal_bool)] diff --git a/tests/ui/blocks_in_if_conditions.rs b/tests/ui/blocks_in_if_conditions.rs index 69387ff5782b3..0a70317c4d408 100644 --- a/tests/ui/blocks_in_if_conditions.rs +++ b/tests/ui/blocks_in_if_conditions.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::blocks_in_if_conditions)] #![allow(unused, clippy::let_and_return)] #![warn(clippy::nonminimal_bool)] diff --git a/tests/ui/bool_assert_comparison.fixed b/tests/ui/bool_assert_comparison.fixed index b8dd92906c8db..53f63444aefe2 100644 --- a/tests/ui/bool_assert_comparison.fixed +++ b/tests/ui/bool_assert_comparison.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused, clippy::assertions_on_constants)] #![warn(clippy::bool_assert_comparison)] diff --git a/tests/ui/bool_assert_comparison.rs b/tests/ui/bool_assert_comparison.rs index 0a8ad34fda52a..151d93a9233b1 100644 --- a/tests/ui/bool_assert_comparison.rs +++ b/tests/ui/bool_assert_comparison.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused, clippy::assertions_on_constants)] #![warn(clippy::bool_assert_comparison)] diff --git a/tests/ui/bool_comparison.fixed b/tests/ui/bool_comparison.fixed index 5a012ff4d27ab..670eef6a21d7e 100644 --- a/tests/ui/bool_comparison.fixed +++ b/tests/ui/bool_comparison.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::bool_comparison)] diff --git a/tests/ui/bool_comparison.rs b/tests/ui/bool_comparison.rs index c534bc25c20f1..72851be635d0e 100644 --- a/tests/ui/bool_comparison.rs +++ b/tests/ui/bool_comparison.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::bool_comparison)] diff --git a/tests/ui/bool_to_int_with_if.fixed b/tests/ui/bool_to_int_with_if.fixed index 37d3e3286a4b8..9831c3373d455 100644 --- a/tests/ui/bool_to_int_with_if.fixed +++ b/tests/ui/bool_to_int_with_if.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(let_chains)] #![warn(clippy::bool_to_int_with_if)] diff --git a/tests/ui/bool_to_int_with_if.rs b/tests/ui/bool_to_int_with_if.rs index ebdf86fd18560..5e3047bb32c62 100644 --- a/tests/ui/bool_to_int_with_if.rs +++ b/tests/ui/bool_to_int_with_if.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(let_chains)] #![warn(clippy::bool_to_int_with_if)] diff --git a/tests/ui/borrow_as_ptr.fixed b/tests/ui/borrow_as_ptr.fixed index ff5c6a8c3774b..3f440ce0045a9 100644 --- a/tests/ui/borrow_as_ptr.fixed +++ b/tests/ui/borrow_as_ptr.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::borrow_as_ptr)] fn main() { diff --git a/tests/ui/borrow_as_ptr.rs b/tests/ui/borrow_as_ptr.rs index 0f62ec6ee58b4..c1ca9180eef42 100644 --- a/tests/ui/borrow_as_ptr.rs +++ b/tests/ui/borrow_as_ptr.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::borrow_as_ptr)] fn main() { diff --git a/tests/ui/borrow_as_ptr_no_std.fixed b/tests/ui/borrow_as_ptr_no_std.fixed index eaba3b1c20c8d..10f2727c793cd 100644 --- a/tests/ui/borrow_as_ptr_no_std.fixed +++ b/tests/ui/borrow_as_ptr_no_std.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::borrow_as_ptr)] #![feature(lang_items, start, libc)] #![no_std] diff --git a/tests/ui/borrow_as_ptr_no_std.rs b/tests/ui/borrow_as_ptr_no_std.rs index d83f9d1f875ba..311e9341aac25 100644 --- a/tests/ui/borrow_as_ptr_no_std.rs +++ b/tests/ui/borrow_as_ptr_no_std.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::borrow_as_ptr)] #![feature(lang_items, start, libc)] #![no_std] diff --git a/tests/ui/borrow_deref_ref.fixed b/tests/ui/borrow_deref_ref.fixed index bf4691c5bc97e..165e4bc827239 100644 --- a/tests/ui/borrow_deref_ref.fixed +++ b/tests/ui/borrow_deref_ref.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code, unused_variables)] diff --git a/tests/ui/borrow_deref_ref.rs b/tests/ui/borrow_deref_ref.rs index 28c005fdbef70..66c8d69bef983 100644 --- a/tests/ui/borrow_deref_ref.rs +++ b/tests/ui/borrow_deref_ref.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code, unused_variables)] diff --git a/tests/ui/borrow_interior_mutable_const/enums.rs b/tests/ui/borrow_interior_mutable_const/enums.rs index 5027db4456179..29b08ab36430d 100644 --- a/tests/ui/borrow_interior_mutable_const/enums.rs +++ b/tests/ui/borrow_interior_mutable_const/enums.rs @@ -1,4 +1,4 @@ -// aux-build:helper.rs +//@aux-build:helper.rs #![warn(clippy::borrow_interior_mutable_const)] #![allow(clippy::declare_interior_mutable_const)] diff --git a/tests/ui/box_default.fixed b/tests/ui/box_default.fixed index 59c0baf8718aa..6afce2087697f 100644 --- a/tests/ui/box_default.fixed +++ b/tests/ui/box_default.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::box_default)] #[derive(Default)] diff --git a/tests/ui/box_default.rs b/tests/ui/box_default.rs index f7d832193a3a1..09365618e6336 100644 --- a/tests/ui/box_default.rs +++ b/tests/ui/box_default.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::box_default)] #[derive(Default)] diff --git a/tests/ui/bytes_count_to_len.fixed b/tests/ui/bytes_count_to_len.fixed index 860642363b5f0..fb3d521badd52 100644 --- a/tests/ui/bytes_count_to_len.fixed +++ b/tests/ui/bytes_count_to_len.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::bytes_count_to_len)] use std::fs::File; use std::io::Read; diff --git a/tests/ui/bytes_count_to_len.rs b/tests/ui/bytes_count_to_len.rs index 162730c2842a1..8e256b8f0b8ab 100644 --- a/tests/ui/bytes_count_to_len.rs +++ b/tests/ui/bytes_count_to_len.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::bytes_count_to_len)] use std::fs::File; use std::io::Read; diff --git a/tests/ui/bytes_nth.fixed b/tests/ui/bytes_nth.fixed index a35c679afb71f..d3e0f676b29f9 100644 --- a/tests/ui/bytes_nth.fixed +++ b/tests/ui/bytes_nth.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(clippy::unnecessary_operation)] #![warn(clippy::bytes_nth)] diff --git a/tests/ui/bytes_nth.rs b/tests/ui/bytes_nth.rs index 1ecffea53035e..b7d813fe296a9 100644 --- a/tests/ui/bytes_nth.rs +++ b/tests/ui/bytes_nth.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(clippy::unnecessary_operation)] #![warn(clippy::bytes_nth)] diff --git a/tests/ui/case_sensitive_file_extension_comparisons.fixed b/tests/ui/case_sensitive_file_extension_comparisons.fixed index 5fbaa64db39ed..d5af22aefe5df 100644 --- a/tests/ui/case_sensitive_file_extension_comparisons.fixed +++ b/tests/ui/case_sensitive_file_extension_comparisons.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::case_sensitive_file_extension_comparisons)] use std::string::String; diff --git a/tests/ui/case_sensitive_file_extension_comparisons.rs b/tests/ui/case_sensitive_file_extension_comparisons.rs index 3c0d4821f9f3a..f5f0a0022a42a 100644 --- a/tests/ui/case_sensitive_file_extension_comparisons.rs +++ b/tests/ui/case_sensitive_file_extension_comparisons.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::case_sensitive_file_extension_comparisons)] use std::string::String; diff --git a/tests/ui/cast_abs_to_unsigned.fixed b/tests/ui/cast_abs_to_unsigned.fixed index 8676b562b4f9e..ef0a93b01d1f6 100644 --- a/tests/ui/cast_abs_to_unsigned.fixed +++ b/tests/ui/cast_abs_to_unsigned.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::cast_abs_to_unsigned)] #![allow(clippy::uninlined_format_args, unused)] diff --git a/tests/ui/cast_abs_to_unsigned.rs b/tests/ui/cast_abs_to_unsigned.rs index 5775af874f8fc..96ced670a0559 100644 --- a/tests/ui/cast_abs_to_unsigned.rs +++ b/tests/ui/cast_abs_to_unsigned.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::cast_abs_to_unsigned)] #![allow(clippy::uninlined_format_args, unused)] diff --git a/tests/ui/cast_lossless_bool.fixed b/tests/ui/cast_lossless_bool.fixed index 13b3cf838c9f0..c321cc6443784 100644 --- a/tests/ui/cast_lossless_bool.fixed +++ b/tests/ui/cast_lossless_bool.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code)] #![warn(clippy::cast_lossless)] diff --git a/tests/ui/cast_lossless_bool.rs b/tests/ui/cast_lossless_bool.rs index 3eed2135562c8..632a718920d41 100644 --- a/tests/ui/cast_lossless_bool.rs +++ b/tests/ui/cast_lossless_bool.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code)] #![warn(clippy::cast_lossless)] diff --git a/tests/ui/cast_lossless_float.fixed b/tests/ui/cast_lossless_float.fixed index 32a9c1c4ae1af..e72a0096acce7 100644 --- a/tests/ui/cast_lossless_float.fixed +++ b/tests/ui/cast_lossless_float.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(clippy::no_effect, clippy::unnecessary_operation, dead_code)] #![warn(clippy::cast_lossless)] diff --git a/tests/ui/cast_lossless_float.rs b/tests/ui/cast_lossless_float.rs index 6f5ddcfe09c8a..dbcbaa9b81500 100644 --- a/tests/ui/cast_lossless_float.rs +++ b/tests/ui/cast_lossless_float.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(clippy::no_effect, clippy::unnecessary_operation, dead_code)] #![warn(clippy::cast_lossless)] diff --git a/tests/ui/cast_lossless_integer.fixed b/tests/ui/cast_lossless_integer.fixed index 925cbf25368fb..7dab02084fc9d 100644 --- a/tests/ui/cast_lossless_integer.fixed +++ b/tests/ui/cast_lossless_integer.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(clippy::no_effect, clippy::unnecessary_operation, dead_code)] #![warn(clippy::cast_lossless)] diff --git a/tests/ui/cast_lossless_integer.rs b/tests/ui/cast_lossless_integer.rs index c82bd9108d23b..c24f73960b03f 100644 --- a/tests/ui/cast_lossless_integer.rs +++ b/tests/ui/cast_lossless_integer.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(clippy::no_effect, clippy::unnecessary_operation, dead_code)] #![warn(clippy::cast_lossless)] diff --git a/tests/ui/cast_raw_slice_pointer_cast.fixed b/tests/ui/cast_raw_slice_pointer_cast.fixed index b70c191295116..9b6fee270ee9b 100644 --- a/tests/ui/cast_raw_slice_pointer_cast.fixed +++ b/tests/ui/cast_raw_slice_pointer_cast.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::cast_slice_from_raw_parts)] #[allow(unused_imports, unused_unsafe)] diff --git a/tests/ui/cast_raw_slice_pointer_cast.rs b/tests/ui/cast_raw_slice_pointer_cast.rs index c1b316765c967..c0bb81379905c 100644 --- a/tests/ui/cast_raw_slice_pointer_cast.rs +++ b/tests/ui/cast_raw_slice_pointer_cast.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::cast_slice_from_raw_parts)] #[allow(unused_imports, unused_unsafe)] diff --git a/tests/ui/cast_size.rs b/tests/ui/cast_size.rs index 595109be46bb8..cd2184aea382a 100644 --- a/tests/ui/cast_size.rs +++ b/tests/ui/cast_size.rs @@ -1,4 +1,4 @@ -// ignore-32bit +//@ignore-32bit #[warn( clippy::cast_precision_loss, clippy::cast_possible_truncation, diff --git a/tests/ui/cast_size_32bit.rs b/tests/ui/cast_size_32bit.rs index 99aac6deca324..7ca20d3ca4a76 100644 --- a/tests/ui/cast_size_32bit.rs +++ b/tests/ui/cast_size_32bit.rs @@ -1,4 +1,4 @@ -// ignore-64bit +//@ignore-64bit #[warn( clippy::cast_precision_loss, clippy::cast_possible_truncation, diff --git a/tests/ui/cast_size_32bit.stderr b/tests/ui/cast_size_32bit.stderr index 8990c3ba739b0..fb51783a48788 100644 --- a/tests/ui/cast_size_32bit.stderr +++ b/tests/ui/cast_size_32bit.stderr @@ -4,7 +4,12 @@ error: casting `isize` to `i8` may truncate the value LL | 1isize as i8; | ^^^^^^^^^^^^ | + = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... = note: `-D clippy::cast-possible-truncation` implied by `-D warnings` +help: ... or use `try_from` and handle the error accordingly + | +LL | i8::try_from(1isize); + | ~~~~~~~~~~~~~~~~~~~~ error: casting `isize` to `f64` causes a loss of precision on targets with 64-bit wide pointers (`isize` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide) --> $DIR/cast_size_32bit.rs:15:5 @@ -37,24 +42,48 @@ error: casting `isize` to `i32` may truncate the value on targets with 64-bit wi | LL | 1isize as i32; | ^^^^^^^^^^^^^ + | + = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... +help: ... or use `try_from` and handle the error accordingly + | +LL | i32::try_from(1isize); + | ~~~~~~~~~~~~~~~~~~~~~ error: casting `isize` to `u32` may truncate the value on targets with 64-bit wide pointers --> $DIR/cast_size_32bit.rs:20:5 | LL | 1isize as u32; | ^^^^^^^^^^^^^ + | + = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... +help: ... or use `try_from` and handle the error accordingly + | +LL | u32::try_from(1isize); + | ~~~~~~~~~~~~~~~~~~~~~ error: casting `usize` to `u32` may truncate the value on targets with 64-bit wide pointers --> $DIR/cast_size_32bit.rs:21:5 | LL | 1usize as u32; | ^^^^^^^^^^^^^ + | + = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... +help: ... or use `try_from` and handle the error accordingly + | +LL | u32::try_from(1usize); + | ~~~~~~~~~~~~~~~~~~~~~ error: casting `usize` to `i32` may truncate the value on targets with 64-bit wide pointers --> $DIR/cast_size_32bit.rs:22:5 | LL | 1usize as i32; | ^^^^^^^^^^^^^ + | + = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... +help: ... or use `try_from` and handle the error accordingly + | +LL | i32::try_from(1usize); + | ~~~~~~~~~~~~~~~~~~~~~ error: casting `usize` to `i32` may wrap around the value on targets with 32-bit wide pointers --> $DIR/cast_size_32bit.rs:22:5 @@ -69,18 +98,36 @@ error: casting `i64` to `isize` may truncate the value on targets with 32-bit wi | LL | 1i64 as isize; | ^^^^^^^^^^^^^ + | + = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... +help: ... or use `try_from` and handle the error accordingly + | +LL | isize::try_from(1i64); + | ~~~~~~~~~~~~~~~~~~~~~ error: casting `i64` to `usize` may truncate the value on targets with 32-bit wide pointers --> $DIR/cast_size_32bit.rs:25:5 | LL | 1i64 as usize; | ^^^^^^^^^^^^^ + | + = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... +help: ... or use `try_from` and handle the error accordingly + | +LL | usize::try_from(1i64); + | ~~~~~~~~~~~~~~~~~~~~~ error: casting `u64` to `isize` may truncate the value on targets with 32-bit wide pointers --> $DIR/cast_size_32bit.rs:26:5 | LL | 1u64 as isize; | ^^^^^^^^^^^^^ + | + = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... +help: ... or use `try_from` and handle the error accordingly + | +LL | isize::try_from(1u64); + | ~~~~~~~~~~~~~~~~~~~~~ error: casting `u64` to `isize` may wrap around the value on targets with 64-bit wide pointers --> $DIR/cast_size_32bit.rs:26:5 @@ -93,6 +140,12 @@ error: casting `u64` to `usize` may truncate the value on targets with 32-bit wi | LL | 1u64 as usize; | ^^^^^^^^^^^^^ + | + = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... +help: ... or use `try_from` and handle the error accordingly + | +LL | usize::try_from(1u64); + | ~~~~~~~~~~~~~~~~~~~~~ error: casting `u32` to `isize` may wrap around the value on targets with 32-bit wide pointers --> $DIR/cast_size_32bit.rs:28:5 diff --git a/tests/ui/cfg_attr_rustfmt.fixed b/tests/ui/cfg_attr_rustfmt.fixed index b970b1209b654..13aadb7d3308f 100644 --- a/tests/ui/cfg_attr_rustfmt.fixed +++ b/tests/ui/cfg_attr_rustfmt.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(stmt_expr_attributes)] #![allow(unused, clippy::no_effect, clippy::unnecessary_operation)] diff --git a/tests/ui/cfg_attr_rustfmt.rs b/tests/ui/cfg_attr_rustfmt.rs index 0a8e6a89d8a0f..769c5d22b9da0 100644 --- a/tests/ui/cfg_attr_rustfmt.rs +++ b/tests/ui/cfg_attr_rustfmt.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(stmt_expr_attributes)] #![allow(unused, clippy::no_effect, clippy::unnecessary_operation)] diff --git a/tests/ui/char_lit_as_u8_suggestions.fixed b/tests/ui/char_lit_as_u8_suggestions.fixed index 3dc3cb4e7573d..ce2f149dc05e4 100644 --- a/tests/ui/char_lit_as_u8_suggestions.fixed +++ b/tests/ui/char_lit_as_u8_suggestions.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::char_lit_as_u8)] diff --git a/tests/ui/char_lit_as_u8_suggestions.rs b/tests/ui/char_lit_as_u8_suggestions.rs index d379a0234942a..ffad12fc6f950 100644 --- a/tests/ui/char_lit_as_u8_suggestions.rs +++ b/tests/ui/char_lit_as_u8_suggestions.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::char_lit_as_u8)] diff --git a/tests/ui/checked_conversions.fixed b/tests/ui/checked_conversions.fixed index e279ba3147bba..188e6d975952e 100644 --- a/tests/ui/checked_conversions.fixed +++ b/tests/ui/checked_conversions.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow( clippy::cast_lossless, diff --git a/tests/ui/checked_conversions.rs b/tests/ui/checked_conversions.rs index 9d7a40995c373..70f0f0975acd9 100644 --- a/tests/ui/checked_conversions.rs +++ b/tests/ui/checked_conversions.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow( clippy::cast_lossless, diff --git a/tests/ui/clear_with_drain.fixed b/tests/ui/clear_with_drain.fixed index 2d9545eeed197..b68c7d867ec65 100644 --- a/tests/ui/clear_with_drain.fixed +++ b/tests/ui/clear_with_drain.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] #![warn(clippy::clear_with_drain)] diff --git a/tests/ui/clear_with_drain.rs b/tests/ui/clear_with_drain.rs index 4d60ee46e1865..0f6562ecad5a2 100644 --- a/tests/ui/clear_with_drain.rs +++ b/tests/ui/clear_with_drain.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] #![warn(clippy::clear_with_drain)] diff --git a/tests/ui/clone_on_copy.fixed b/tests/ui/clone_on_copy.fixed index 72b1222709819..a720711585bbb 100644 --- a/tests/ui/clone_on_copy.fixed +++ b/tests/ui/clone_on_copy.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow( unused, diff --git a/tests/ui/clone_on_copy.rs b/tests/ui/clone_on_copy.rs index 03e210ebad98c..2c5fac8faf56b 100644 --- a/tests/ui/clone_on_copy.rs +++ b/tests/ui/clone_on_copy.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow( unused, diff --git a/tests/ui/cloned_instead_of_copied.fixed b/tests/ui/cloned_instead_of_copied.fixed index ecbfc1feedf62..b6e09ab319086 100644 --- a/tests/ui/cloned_instead_of_copied.fixed +++ b/tests/ui/cloned_instead_of_copied.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::cloned_instead_of_copied)] #![allow(unused)] diff --git a/tests/ui/cloned_instead_of_copied.rs b/tests/ui/cloned_instead_of_copied.rs index 163dc3dddce62..fa9e1a996139d 100644 --- a/tests/ui/cloned_instead_of_copied.rs +++ b/tests/ui/cloned_instead_of_copied.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::cloned_instead_of_copied)] #![allow(unused)] diff --git a/tests/ui/cmp_owned/asymmetric_partial_eq.fixed b/tests/ui/cmp_owned/asymmetric_partial_eq.fixed index abd059c230801..3bf3deb9b9182 100644 --- a/tests/ui/cmp_owned/asymmetric_partial_eq.fixed +++ b/tests/ui/cmp_owned/asymmetric_partial_eq.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused, clippy::redundant_clone, clippy::derive_partial_eq_without_eq)] // See #5700 // Define the types in each module to avoid trait impls leaking between modules. diff --git a/tests/ui/cmp_owned/asymmetric_partial_eq.rs b/tests/ui/cmp_owned/asymmetric_partial_eq.rs index 020ef5f840bd5..10107dc8f86d3 100644 --- a/tests/ui/cmp_owned/asymmetric_partial_eq.rs +++ b/tests/ui/cmp_owned/asymmetric_partial_eq.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused, clippy::redundant_clone, clippy::derive_partial_eq_without_eq)] // See #5700 // Define the types in each module to avoid trait impls leaking between modules. diff --git a/tests/ui/cmp_owned/comparison_flip.fixed b/tests/ui/cmp_owned/comparison_flip.fixed index 44e41bdd11487..b1133f2a59f74 100644 --- a/tests/ui/cmp_owned/comparison_flip.fixed +++ b/tests/ui/cmp_owned/comparison_flip.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix use std::fmt::{self, Display}; diff --git a/tests/ui/cmp_owned/comparison_flip.rs b/tests/ui/cmp_owned/comparison_flip.rs index 662673abb62d9..091a9aa65c0ac 100644 --- a/tests/ui/cmp_owned/comparison_flip.rs +++ b/tests/ui/cmp_owned/comparison_flip.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix use std::fmt::{self, Display}; diff --git a/tests/ui/cmp_owned/with_suggestion.fixed b/tests/ui/cmp_owned/with_suggestion.fixed index b28c4378e33c6..76f90ab2a9d11 100644 --- a/tests/ui/cmp_owned/with_suggestion.fixed +++ b/tests/ui/cmp_owned/with_suggestion.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #[warn(clippy::cmp_owned)] #[allow(clippy::unnecessary_operation, clippy::no_effect, unused_must_use, clippy::eq_op)] diff --git a/tests/ui/cmp_owned/with_suggestion.rs b/tests/ui/cmp_owned/with_suggestion.rs index c1089010fe109..f3f663670eb18 100644 --- a/tests/ui/cmp_owned/with_suggestion.rs +++ b/tests/ui/cmp_owned/with_suggestion.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #[warn(clippy::cmp_owned)] #[allow(clippy::unnecessary_operation, clippy::no_effect, unused_must_use, clippy::eq_op)] diff --git a/tests/ui/collapsible_else_if.fixed b/tests/ui/collapsible_else_if.fixed index d6a5a78506791..8302cec45e781 100644 --- a/tests/ui/collapsible_else_if.fixed +++ b/tests/ui/collapsible_else_if.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(clippy::assertions_on_constants, clippy::equatable_if_let)] #[rustfmt::skip] diff --git a/tests/ui/collapsible_else_if.rs b/tests/ui/collapsible_else_if.rs index 4399fc8b2bd1d..5913dcf41cafc 100644 --- a/tests/ui/collapsible_else_if.rs +++ b/tests/ui/collapsible_else_if.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(clippy::assertions_on_constants, clippy::equatable_if_let)] #[rustfmt::skip] diff --git a/tests/ui/collapsible_if.fixed b/tests/ui/collapsible_if.fixed index 6bb7682bae953..d2aba2ac59b8a 100644 --- a/tests/ui/collapsible_if.fixed +++ b/tests/ui/collapsible_if.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(clippy::assertions_on_constants, clippy::equatable_if_let)] #[rustfmt::skip] diff --git a/tests/ui/collapsible_if.rs b/tests/ui/collapsible_if.rs index e216a9ee54c90..e0bef7f9c970d 100644 --- a/tests/ui/collapsible_if.rs +++ b/tests/ui/collapsible_if.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(clippy::assertions_on_constants, clippy::equatable_if_let)] #[rustfmt::skip] diff --git a/tests/ui/collapsible_str_replace.fixed b/tests/ui/collapsible_str_replace.fixed index 9792ae9ed6b8b..ba6c1769a9a38 100644 --- a/tests/ui/collapsible_str_replace.fixed +++ b/tests/ui/collapsible_str_replace.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] #![warn(clippy::collapsible_str_replace)] diff --git a/tests/ui/collapsible_str_replace.rs b/tests/ui/collapsible_str_replace.rs index baee185b79ea3..f5871be65be12 100644 --- a/tests/ui/collapsible_str_replace.rs +++ b/tests/ui/collapsible_str_replace.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] #![warn(clippy::collapsible_str_replace)] diff --git a/tests/ui/collection_is_never_read.rs b/tests/ui/collection_is_never_read.rs index 01259a983ab6f..2c1a42a72c149 100644 --- a/tests/ui/collection_is_never_read.rs +++ b/tests/ui/collection_is_never_read.rs @@ -169,22 +169,35 @@ fn function_argument() { foo(&x); } -fn string() { - // Do lint (write without read) - let mut s = String::new(); - s.push_str("Hello, World!"); - - // Do not lint (read without write) - let mut s = String::from("Hello, World!"); - let _ = s.len(); - - // Do not lint (write and read) - let mut s = String::from("Hello, World!"); - s.push_str("foo, bar"); - let _ = s.len(); - - // Do lint the first line, but not the second - let mut s = String::from("Hello, World!"); - let t = String::from("foo, bar"); - s = t; +fn supported_types() { + let mut x = std::collections::BTreeMap::new(); // WARNING + x.insert(true, 1); + + let mut x = std::collections::BTreeSet::new(); // WARNING + x.insert(1); + + let mut x = std::collections::BinaryHeap::new(); // WARNING + x.push(1); + + let mut x = std::collections::HashMap::new(); // WARNING + x.insert(1, 2); + + let mut x = std::collections::HashSet::new(); // WARNING + x.insert(1); + + let mut x = std::collections::LinkedList::new(); // WARNING + x.push_front(1); + + let mut x = Some(true); // WARNING + x.insert(false); + + let mut x = String::from("hello"); // WARNING + x.push('!'); + + let mut x = Vec::new(); // WARNING + x.clear(); + x.push(1); + + let mut x = std::collections::VecDeque::new(); // WARNING + x.push_front(1); } diff --git a/tests/ui/collection_is_never_read.stderr b/tests/ui/collection_is_never_read.stderr index cf51a53686f2d..982cb445534a2 100644 --- a/tests/ui/collection_is_never_read.stderr +++ b/tests/ui/collection_is_never_read.stderr @@ -61,16 +61,64 @@ LL | let x = vec![1, 2, 3]; // WARNING | ^^^^^^^^^^^^^^^^^^^^^^ error: collection is never read - --> $DIR/collection_is_never_read.rs:174:5 + --> $DIR/collection_is_never_read.rs:173:5 | -LL | let mut s = String::new(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | let mut x = std::collections::BTreeMap::new(); // WARNING + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: collection is never read + --> $DIR/collection_is_never_read.rs:176:5 + | +LL | let mut x = std::collections::BTreeSet::new(); // WARNING + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: collection is never read + --> $DIR/collection_is_never_read.rs:179:5 + | +LL | let mut x = std::collections::BinaryHeap::new(); // WARNING + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: collection is never read + --> $DIR/collection_is_never_read.rs:182:5 + | +LL | let mut x = std::collections::HashMap::new(); // WARNING + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: collection is never read + --> $DIR/collection_is_never_read.rs:185:5 + | +LL | let mut x = std::collections::HashSet::new(); // WARNING + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: collection is never read + --> $DIR/collection_is_never_read.rs:188:5 + | +LL | let mut x = std::collections::LinkedList::new(); // WARNING + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: collection is never read + --> $DIR/collection_is_never_read.rs:191:5 + | +LL | let mut x = Some(true); // WARNING + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error: collection is never read + --> $DIR/collection_is_never_read.rs:194:5 + | +LL | let mut x = String::from("hello"); // WARNING + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: collection is never read + --> $DIR/collection_is_never_read.rs:197:5 + | +LL | let mut x = Vec::new(); // WARNING + | ^^^^^^^^^^^^^^^^^^^^^^^ error: collection is never read - --> $DIR/collection_is_never_read.rs:187:5 + --> $DIR/collection_is_never_read.rs:201:5 | -LL | let mut s = String::from("Hello, World!"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | let mut x = std::collections::VecDeque::new(); // WARNING + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 12 previous errors +error: aborting due to 20 previous errors diff --git a/tests/ui/comparison_to_empty.fixed b/tests/ui/comparison_to_empty.fixed index 261024caca761..dd2615ab25cf1 100644 --- a/tests/ui/comparison_to_empty.fixed +++ b/tests/ui/comparison_to_empty.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::comparison_to_empty)] diff --git a/tests/ui/comparison_to_empty.rs b/tests/ui/comparison_to_empty.rs index 98ddd97495161..5462784c6ac8a 100644 --- a/tests/ui/comparison_to_empty.rs +++ b/tests/ui/comparison_to_empty.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::comparison_to_empty)] diff --git a/tests/ui/crashes/auxiliary/proc_macro_crash.rs b/tests/ui/crashes/auxiliary/proc_macro_crash.rs index 5ff2af7cd8253..66419656a327a 100644 --- a/tests/ui/crashes/auxiliary/proc_macro_crash.rs +++ b/tests/ui/crashes/auxiliary/proc_macro_crash.rs @@ -1,5 +1,5 @@ -// compile-flags: --emit=link -// no-prefer-dynamic +//@compile-flags: --emit=link +//@no-prefer-dynamic // ^ compiletest by default builds all aux files as dylibs, but we don't want that for proc-macro // crates. If we don't set this, compiletest will override the `crate_type` attribute below and // compile this as dylib. Removing this then causes the test to fail because a `dylib` crate can't diff --git a/tests/ui/crashes/ice-10148.rs b/tests/ui/crashes/ice-10148.rs index 1ab3570c907ce..c7f0224820ed0 100644 --- a/tests/ui/crashes/ice-10148.rs +++ b/tests/ui/crashes/ice-10148.rs @@ -1,4 +1,4 @@ -// aux-build:../../auxiliary/proc_macros.rs +//@aux-build:../../auxiliary/proc_macros.rs extern crate proc_macros; diff --git a/tests/ui/crashes/ice-3741.rs b/tests/ui/crashes/ice-3741.rs index 1253ddcfaeb3b..3106a2e721694 100644 --- a/tests/ui/crashes/ice-3741.rs +++ b/tests/ui/crashes/ice-3741.rs @@ -1,4 +1,4 @@ -// aux-build:proc_macro_crash.rs +//@aux-build:proc_macro_crash.rs #![warn(clippy::suspicious_else_formatting)] diff --git a/tests/ui/crashes/ice-4968.rs b/tests/ui/crashes/ice-4968.rs index e0510d942c200..ac724ac93e3f2 100644 --- a/tests/ui/crashes/ice-4968.rs +++ b/tests/ui/crashes/ice-4968.rs @@ -1,4 +1,4 @@ -// check-pass +//@check-pass // Test for https://github.com/rust-lang/rust-clippy/issues/4968 diff --git a/tests/ui/crashes/ice-5207.stderr b/tests/ui/crashes/ice-5207.stderr index 367e9a08b7563..59146c23e0d57 100644 --- a/tests/ui/crashes/ice-5207.stderr +++ b/tests/ui/crashes/ice-5207.stderr @@ -1,4 +1,4 @@ -warning: future cannot be sent between threads safely +error: future cannot be sent between threads safely --> $DIR/ice-5207.rs:6:35 | LL | pub async fn bar<'a, T: 'a>(_: T) {} @@ -12,5 +12,5 @@ LL | pub async fn bar<'a, T: 'a>(_: T) {} = note: `T` doesn't implement `std::marker::Send` = note: `-D clippy::future-not-send` implied by `-D warnings` -warning: 1 warning emitted +error: aborting due to previous error diff --git a/tests/ui/crashes/ice-7272.rs b/tests/ui/crashes/ice-7272.rs index 57ab6ca14f86a..e949038c8d0b1 100644 --- a/tests/ui/crashes/ice-7272.rs +++ b/tests/ui/crashes/ice-7272.rs @@ -1,4 +1,4 @@ -// aux-build:ice-7272-aux.rs +//@aux-build:ice-7272-aux.rs #![allow(clippy::no_effect)] diff --git a/tests/ui/crashes/ice-7410.rs b/tests/ui/crashes/ice-7410.rs index 85fa421032191..ffe20ab1c3101 100644 --- a/tests/ui/crashes/ice-7410.rs +++ b/tests/ui/crashes/ice-7410.rs @@ -1,6 +1,6 @@ -// compile-flags: -Clink-arg=-nostartfiles -// ignore-macos -// ignore-windows +//@compile-flags: -Clink-arg=-nostartfiles +//@ignore-macos +//@ignore-windows #![feature(lang_items, start, libc)] #![no_std] diff --git a/tests/ui/crashes/ice-8681.rs b/tests/ui/crashes/ice-8681.rs index ee14f011f631b..607b9caa32491 100644 --- a/tests/ui/crashes/ice-8681.rs +++ b/tests/ui/crashes/ice-8681.rs @@ -1,4 +1,4 @@ -// aux-build: ice-8681-aux.rs +//@aux-build: ice-8681-aux.rs #![warn(clippy::undocumented_unsafe_blocks)] diff --git a/tests/ui/crate_in_macro_def.fixed b/tests/ui/crate_in_macro_def.fixed index 9fc594be311e2..12a7b9470b315 100644 --- a/tests/ui/crate_in_macro_def.fixed +++ b/tests/ui/crate_in_macro_def.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::crate_in_macro_def)] mod hygienic { diff --git a/tests/ui/crate_in_macro_def.rs b/tests/ui/crate_in_macro_def.rs index ac456108e4ab1..a1a9eabf639bf 100644 --- a/tests/ui/crate_in_macro_def.rs +++ b/tests/ui/crate_in_macro_def.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::crate_in_macro_def)] mod hygienic { diff --git a/tests/ui/crate_level_checks/entrypoint_recursion.rs b/tests/ui/crate_level_checks/entrypoint_recursion.rs index 1b3bcece6f1e7..d6cd594d7c971 100644 --- a/tests/ui/crate_level_checks/entrypoint_recursion.rs +++ b/tests/ui/crate_level_checks/entrypoint_recursion.rs @@ -1,4 +1,4 @@ -// ignore-macos +//@ignore-macos #![feature(rustc_attrs)] diff --git a/tests/ui/crate_level_checks/no_std_main_recursion.rs b/tests/ui/crate_level_checks/no_std_main_recursion.rs index e1c9fe30a9dfb..a382135bb6951 100644 --- a/tests/ui/crate_level_checks/no_std_main_recursion.rs +++ b/tests/ui/crate_level_checks/no_std_main_recursion.rs @@ -1,5 +1,5 @@ -// compile-flags: -Clink-arg=-nostartfiles -// ignore-macos +//@compile-flags: -Clink-arg=-nostartfiles +//@ignore-macos #![feature(lang_items, start, libc)] #![no_std] diff --git a/tests/ui/create_dir.fixed b/tests/ui/create_dir.fixed index 8ed53a56ac043..5de3e9fea0bca 100644 --- a/tests/ui/create_dir.fixed +++ b/tests/ui/create_dir.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused_must_use)] #![warn(clippy::create_dir)] diff --git a/tests/ui/create_dir.rs b/tests/ui/create_dir.rs index 19c8fc24ba23f..d375bfb4a688c 100644 --- a/tests/ui/create_dir.rs +++ b/tests/ui/create_dir.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused_must_use)] #![warn(clippy::create_dir)] diff --git a/tests/ui/dbg_macro.rs b/tests/ui/dbg_macro.rs index 25294e8c766f8..8701e3cd29f47 100644 --- a/tests/ui/dbg_macro.rs +++ b/tests/ui/dbg_macro.rs @@ -1,4 +1,4 @@ -// compile-flags: --test +//@compile-flags: --test #![warn(clippy::dbg_macro)] fn foo(n: u32) -> u32 { diff --git a/tests/ui/decimal_literal_representation.fixed b/tests/ui/decimal_literal_representation.fixed index de391465125ce..a6eb8c214578f 100644 --- a/tests/ui/decimal_literal_representation.fixed +++ b/tests/ui/decimal_literal_representation.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #[warn(clippy::decimal_literal_representation)] #[allow(unused_variables)] diff --git a/tests/ui/decimal_literal_representation.rs b/tests/ui/decimal_literal_representation.rs index 55d07698e7e5b..7c666d6d7a697 100644 --- a/tests/ui/decimal_literal_representation.rs +++ b/tests/ui/decimal_literal_representation.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #[warn(clippy::decimal_literal_representation)] #[allow(unused_variables)] diff --git a/tests/ui/def_id_nocore.rs b/tests/ui/def_id_nocore.rs index 1af77d1a25b2d..f7819068ac5ab 100644 --- a/tests/ui/def_id_nocore.rs +++ b/tests/ui/def_id_nocore.rs @@ -1,4 +1,4 @@ -// ignore-macos +//@ignore-macos #![feature(no_core, lang_items, start)] #![no_core] diff --git a/tests/ui/default_instead_of_iter_empty.fixed b/tests/ui/default_instead_of_iter_empty.fixed index f1abfdcd6ce69..f44d34576f680 100644 --- a/tests/ui/default_instead_of_iter_empty.fixed +++ b/tests/ui/default_instead_of_iter_empty.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::default_instead_of_iter_empty)] #![allow(dead_code)] use std::collections::HashMap; diff --git a/tests/ui/default_instead_of_iter_empty.rs b/tests/ui/default_instead_of_iter_empty.rs index 2630519c46da4..1c649df253cca 100644 --- a/tests/ui/default_instead_of_iter_empty.rs +++ b/tests/ui/default_instead_of_iter_empty.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::default_instead_of_iter_empty)] #![allow(dead_code)] use std::collections::HashMap; diff --git a/tests/ui/default_numeric_fallback_f64.fixed b/tests/ui/default_numeric_fallback_f64.fixed index 42c15d6a70b83..9520efe6329b1 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:proc_macros.rs +//@run-rustfix +//@aux-build:proc_macros.rs #![warn(clippy::default_numeric_fallback)] #![allow( diff --git a/tests/ui/default_numeric_fallback_f64.rs b/tests/ui/default_numeric_fallback_f64.rs index 7da7ea254e98b..cacbdb4a95bf4 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:proc_macros.rs +//@run-rustfix +//@aux-build:proc_macros.rs #![warn(clippy::default_numeric_fallback)] #![allow( diff --git a/tests/ui/default_numeric_fallback_i32.fixed b/tests/ui/default_numeric_fallback_i32.fixed index b7485b73dcddd..fbabb8bcf8e33 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:proc_macros.rs +//@run-rustfix +//@aux-build:proc_macros.rs #![feature(lint_reasons)] #![warn(clippy::default_numeric_fallback)] diff --git a/tests/ui/default_numeric_fallback_i32.rs b/tests/ui/default_numeric_fallback_i32.rs index 7307d31354ebd..7bfc390e4bfab 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:proc_macros.rs +//@run-rustfix +//@aux-build:proc_macros.rs #![feature(lint_reasons)] #![warn(clippy::default_numeric_fallback)] diff --git a/tests/ui/default_trait_access.fixed b/tests/ui/default_trait_access.fixed index 7842ef3ec40c2..bf5dca976416d 100644 --- a/tests/ui/default_trait_access.fixed +++ b/tests/ui/default_trait_access.fixed @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build: proc_macros.rs +//@run-rustfix +//@aux-build: proc_macros.rs #![deny(clippy::default_trait_access)] #![allow(dead_code, unused_imports)] #![allow(clippy::uninlined_format_args)] diff --git a/tests/ui/default_trait_access.rs b/tests/ui/default_trait_access.rs index cbb3e59c970eb..5e8e9ce85b1c5 100644 --- a/tests/ui/default_trait_access.rs +++ b/tests/ui/default_trait_access.rs @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build: proc_macros.rs +//@run-rustfix +//@aux-build: proc_macros.rs #![deny(clippy::default_trait_access)] #![allow(dead_code, unused_imports)] #![allow(clippy::uninlined_format_args)] diff --git a/tests/ui/deref_addrof.fixed b/tests/ui/deref_addrof.fixed index ca5c03304c7f2..b27d3bc100283 100644 --- a/tests/ui/deref_addrof.fixed +++ b/tests/ui/deref_addrof.fixed @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:proc_macros.rs +//@run-rustfix +//@aux-build:proc_macros.rs #![allow(clippy::return_self_not_must_use)] #![warn(clippy::deref_addrof)] diff --git a/tests/ui/deref_addrof.rs b/tests/ui/deref_addrof.rs index 3db5fafe94499..825090c7c122e 100644 --- a/tests/ui/deref_addrof.rs +++ b/tests/ui/deref_addrof.rs @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:proc_macros.rs +//@run-rustfix +//@aux-build:proc_macros.rs #![allow(clippy::return_self_not_must_use)] #![warn(clippy::deref_addrof)] diff --git a/tests/ui/deref_addrof_macro.rs b/tests/ui/deref_addrof_macro.rs index 57c0be3f51e1b..c7e60f3650603 100644 --- a/tests/ui/deref_addrof_macro.rs +++ b/tests/ui/deref_addrof_macro.rs @@ -1,4 +1,4 @@ -// aux-build:proc_macros.rs +//@aux-build:proc_macros.rs #![warn(clippy::deref_addrof)] diff --git a/tests/ui/deref_by_slicing.fixed b/tests/ui/deref_by_slicing.fixed index 257393e56ff0f..f91a425c65da4 100644 --- a/tests/ui/deref_by_slicing.fixed +++ b/tests/ui/deref_by_slicing.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::deref_by_slicing)] #![allow(clippy::borrow_deref_ref)] diff --git a/tests/ui/deref_by_slicing.rs b/tests/ui/deref_by_slicing.rs index e288046f927fd..1bfdd0a981ba2 100644 --- a/tests/ui/deref_by_slicing.rs +++ b/tests/ui/deref_by_slicing.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::deref_by_slicing)] #![allow(clippy::borrow_deref_ref)] diff --git a/tests/ui/derivable_impls.fixed b/tests/ui/derivable_impls.fixed index 89ec33a0d8f70..aa0efb85c297a 100644 --- a/tests/ui/derivable_impls.fixed +++ b/tests/ui/derivable_impls.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code)] diff --git a/tests/ui/derivable_impls.rs b/tests/ui/derivable_impls.rs index def6e41162f1b..8dc999ad58602 100644 --- a/tests/ui/derivable_impls.rs +++ b/tests/ui/derivable_impls.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code)] diff --git a/tests/ui/derive_partial_eq_without_eq.fixed b/tests/ui/derive_partial_eq_without_eq.fixed index bbbe467590f91..a1f29430c30f2 100644 --- a/tests/ui/derive_partial_eq_without_eq.fixed +++ b/tests/ui/derive_partial_eq_without_eq.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] #![warn(clippy::derive_partial_eq_without_eq)] diff --git a/tests/ui/derive_partial_eq_without_eq.rs b/tests/ui/derive_partial_eq_without_eq.rs index 88d6fbd1af7e8..ff4d888559b73 100644 --- a/tests/ui/derive_partial_eq_without_eq.rs +++ b/tests/ui/derive_partial_eq_without_eq.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] #![warn(clippy::derive_partial_eq_without_eq)] diff --git a/tests/ui/doc/doc-fixable.fixed b/tests/ui/doc/doc-fixable.fixed index ecb0bf3644eed..d3aa2816cb6d3 100644 --- a/tests/ui/doc/doc-fixable.fixed +++ b/tests/ui/doc/doc-fixable.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix //! This file tests for the `DOC_MARKDOWN` lint. #![allow(dead_code, incomplete_features)] diff --git a/tests/ui/doc/doc-fixable.rs b/tests/ui/doc/doc-fixable.rs index 11c48dd103d69..d1e7d8017d7d1 100644 --- a/tests/ui/doc/doc-fixable.rs +++ b/tests/ui/doc/doc-fixable.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix //! This file tests for the `DOC_MARKDOWN` lint. #![allow(dead_code, incomplete_features)] diff --git a/tests/ui/doc_unsafe.rs b/tests/ui/doc_unsafe.rs index 30674ce3708e7..0c8eac5ccffc3 100644 --- a/tests/ui/doc_unsafe.rs +++ b/tests/ui/doc_unsafe.rs @@ -1,4 +1,4 @@ -// aux-build:proc_macros.rs +//@aux-build:proc_macros.rs #![allow(clippy::let_unit_value)] diff --git a/tests/ui/double_comparison.fixed b/tests/ui/double_comparison.fixed index bb6cdaa667d4f..c80ff671a5db7 100644 --- a/tests/ui/double_comparison.fixed +++ b/tests/ui/double_comparison.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix fn main() { let x = 1; diff --git a/tests/ui/double_comparison.rs b/tests/ui/double_comparison.rs index 9a2a9068a28de..bc78694aa6806 100644 --- a/tests/ui/double_comparison.rs +++ b/tests/ui/double_comparison.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix fn main() { let x = 1; diff --git a/tests/ui/duration_subsec.fixed b/tests/ui/duration_subsec.fixed index d92b8998e8805..bfd30f0042d55 100644 --- a/tests/ui/duration_subsec.fixed +++ b/tests/ui/duration_subsec.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code, clippy::needless_borrow)] #![warn(clippy::duration_subsec)] diff --git a/tests/ui/duration_subsec.rs b/tests/ui/duration_subsec.rs index 08da804996d1b..860233f084f37 100644 --- a/tests/ui/duration_subsec.rs +++ b/tests/ui/duration_subsec.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code, clippy::needless_borrow)] #![warn(clippy::duration_subsec)] diff --git a/tests/ui/empty_drop.fixed b/tests/ui/empty_drop.fixed index 2e1b768461ab2..fd0a9a7081eab 100644 --- a/tests/ui/empty_drop.fixed +++ b/tests/ui/empty_drop.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::empty_drop)] #![allow(unused)] diff --git a/tests/ui/empty_drop.rs b/tests/ui/empty_drop.rs index 75232b0334df6..6c15cb9330276 100644 --- a/tests/ui/empty_drop.rs +++ b/tests/ui/empty_drop.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::empty_drop)] #![allow(unused)] diff --git a/tests/ui/empty_line_after_outer_attribute.rs b/tests/ui/empty_line_after_outer_attribute.rs index 697412c00275e..269e66ea0a816 100644 --- a/tests/ui/empty_line_after_outer_attribute.rs +++ b/tests/ui/empty_line_after_outer_attribute.rs @@ -1,4 +1,4 @@ -// aux-build:proc_macro_attr.rs +//@aux-build:proc_macro_attr.rs #![warn(clippy::empty_line_after_outer_attr)] #![allow(clippy::assertions_on_constants)] #![feature(custom_inner_attributes)] diff --git a/tests/ui/empty_loop.rs b/tests/ui/empty_loop.rs index 6a8e6b550c13f..54e8fb4907c0f 100644 --- a/tests/ui/empty_loop.rs +++ b/tests/ui/empty_loop.rs @@ -1,4 +1,4 @@ -// aux-build:proc_macros.rs +//@aux-build:proc_macros.rs #![warn(clippy::empty_loop)] diff --git a/tests/ui/empty_loop_no_std.rs b/tests/ui/empty_loop_no_std.rs index e742b396fcde0..d564b2d24f5c4 100644 --- a/tests/ui/empty_loop_no_std.rs +++ b/tests/ui/empty_loop_no_std.rs @@ -1,5 +1,5 @@ -// compile-flags: -Clink-arg=-nostartfiles -// ignore-macos +//@compile-flags: -Clink-arg=-nostartfiles +//@ignore-macos #![warn(clippy::empty_loop)] #![feature(lang_items, start, libc)] diff --git a/tests/ui/empty_structs_with_brackets.fixed b/tests/ui/empty_structs_with_brackets.fixed index 80f07603b8d4f..6fab30208393e 100644 --- a/tests/ui/empty_structs_with_brackets.fixed +++ b/tests/ui/empty_structs_with_brackets.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::empty_structs_with_brackets)] #![allow(dead_code)] diff --git a/tests/ui/empty_structs_with_brackets.rs b/tests/ui/empty_structs_with_brackets.rs index 1d1ed4c769025..0caa3c49cd668 100644 --- a/tests/ui/empty_structs_with_brackets.rs +++ b/tests/ui/empty_structs_with_brackets.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::empty_structs_with_brackets)] #![allow(dead_code)] diff --git a/tests/ui/entry.fixed b/tests/ui/entry.fixed index dbe09e0ff3c69..7e82390605ccc 100644 --- a/tests/ui/entry.fixed +++ b/tests/ui/entry.fixed @@ -1,5 +1,5 @@ -// needs-asm-support -// run-rustfix +//@needs-asm-support +//@run-rustfix #![allow(unused, clippy::needless_pass_by_value, clippy::collapsible_if)] #![warn(clippy::map_entry)] diff --git a/tests/ui/entry.rs b/tests/ui/entry.rs index 30fed34fc5de2..742c932253576 100644 --- a/tests/ui/entry.rs +++ b/tests/ui/entry.rs @@ -1,5 +1,5 @@ -// needs-asm-support -// run-rustfix +//@needs-asm-support +//@run-rustfix #![allow(unused, clippy::needless_pass_by_value, clippy::collapsible_if)] #![warn(clippy::map_entry)] diff --git a/tests/ui/entry_btree.fixed b/tests/ui/entry_btree.fixed index 94979104556bc..3baaacffd20d2 100644 --- a/tests/ui/entry_btree.fixed +++ b/tests/ui/entry_btree.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::map_entry)] #![allow(dead_code)] diff --git a/tests/ui/entry_btree.rs b/tests/ui/entry_btree.rs index 080c1d959e894..770e8e91da23f 100644 --- a/tests/ui/entry_btree.rs +++ b/tests/ui/entry_btree.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::map_entry)] #![allow(dead_code)] diff --git a/tests/ui/entry_with_else.fixed b/tests/ui/entry_with_else.fixed index 2332fa6313ff3..71fe04fd64842 100644 --- a/tests/ui/entry_with_else.fixed +++ b/tests/ui/entry_with_else.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused, clippy::needless_pass_by_value, clippy::collapsible_if)] #![warn(clippy::map_entry)] diff --git a/tests/ui/entry_with_else.rs b/tests/ui/entry_with_else.rs index 2ff0c038efe27..80f74649a6033 100644 --- a/tests/ui/entry_with_else.rs +++ b/tests/ui/entry_with_else.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused, clippy::needless_pass_by_value, clippy::collapsible_if)] #![warn(clippy::map_entry)] diff --git a/tests/ui/enum_clike_unportable_variant.rs b/tests/ui/enum_clike_unportable_variant.rs index 7d6842f5b5421..f17556ea90709 100644 --- a/tests/ui/enum_clike_unportable_variant.rs +++ b/tests/ui/enum_clike_unportable_variant.rs @@ -1,4 +1,4 @@ -// ignore-x86 +//@ignore-x86 #![warn(clippy::enum_clike_unportable_variant)] #![allow(unused, non_upper_case_globals)] diff --git a/tests/ui/enum_glob_use.fixed b/tests/ui/enum_glob_use.fixed index a98216758bb9e..419370ffb1d27 100644 --- a/tests/ui/enum_glob_use.fixed +++ b/tests/ui/enum_glob_use.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::enum_glob_use)] #![allow(unused)] diff --git a/tests/ui/enum_glob_use.rs b/tests/ui/enum_glob_use.rs index 5d929c9731d34..645ed98325c9a 100644 --- a/tests/ui/enum_glob_use.rs +++ b/tests/ui/enum_glob_use.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::enum_glob_use)] #![allow(unused)] diff --git a/tests/ui/enum_variants.rs b/tests/ui/enum_variants.rs index efed12ee2ef6f..531652a0e0026 100644 --- a/tests/ui/enum_variants.rs +++ b/tests/ui/enum_variants.rs @@ -179,4 +179,14 @@ mod issue9018 { } } +mod allow_attributes_on_variants { + enum Enum { + #[allow(clippy::enum_variant_names)] + EnumStartsWith, + #[allow(clippy::enum_variant_names)] + EndsWithEnum, + Foo, + } +} + fn main() {} diff --git a/tests/ui/eq_op.rs b/tests/ui/eq_op.rs index e737955026523..cdd33ebe582ff 100644 --- a/tests/ui/eq_op.rs +++ b/tests/ui/eq_op.rs @@ -1,4 +1,4 @@ -// compile-flags: --test +//@compile-flags: --test #![warn(clippy::eq_op)] #![allow(clippy::double_parens, clippy::identity_op, clippy::nonminimal_bool)] diff --git a/tests/ui/equatable_if_let.fixed b/tests/ui/equatable_if_let.fixed index 007702ab550bf..53e62760bef4d 100644 --- a/tests/ui/equatable_if_let.fixed +++ b/tests/ui/equatable_if_let.fixed @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:proc_macros.rs +//@run-rustfix +//@aux-build:proc_macros.rs #![allow(unused_variables, dead_code, clippy::derive_partial_eq_without_eq)] #![warn(clippy::equatable_if_let)] diff --git a/tests/ui/equatable_if_let.rs b/tests/ui/equatable_if_let.rs index 3bda7977645b3..55918a5bb1196 100644 --- a/tests/ui/equatable_if_let.rs +++ b/tests/ui/equatable_if_let.rs @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:proc_macros.rs +//@run-rustfix +//@aux-build:proc_macros.rs #![allow(unused_variables, dead_code, clippy::derive_partial_eq_without_eq)] #![warn(clippy::equatable_if_let)] diff --git a/tests/ui/err_expect.fixed b/tests/ui/err_expect.fixed index b63cbd8a8e6bd..6ade6f5468917 100644 --- a/tests/ui/err_expect.fixed +++ b/tests/ui/err_expect.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] diff --git a/tests/ui/err_expect.rs b/tests/ui/err_expect.rs index c081a745fb406..a93fb59493fec 100644 --- a/tests/ui/err_expect.rs +++ b/tests/ui/err_expect.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] diff --git a/tests/ui/eta.fixed b/tests/ui/eta.fixed index dc129591eac4e..b1baf462c0f88 100644 --- a/tests/ui/eta.fixed +++ b/tests/ui/eta.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::redundant_closure, clippy::redundant_closure_for_method_calls)] #![allow(unused)] #![allow( diff --git a/tests/ui/eta.rs b/tests/ui/eta.rs index 025fd6a0b7afd..e113c3d6cd6b2 100644 --- a/tests/ui/eta.rs +++ b/tests/ui/eta.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::redundant_closure, clippy::redundant_closure_for_method_calls)] #![allow(unused)] #![allow( diff --git a/tests/ui/excessive_precision.fixed b/tests/ui/excessive_precision.fixed index b74bda182be9b..0a07957386c23 100644 --- a/tests/ui/excessive_precision.fixed +++ b/tests/ui/excessive_precision.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::excessive_precision)] #![allow(dead_code, unused_variables, clippy::print_literal)] diff --git a/tests/ui/excessive_precision.rs b/tests/ui/excessive_precision.rs index 6e84a71f24cb6..62a832caa67b6 100644 --- a/tests/ui/excessive_precision.rs +++ b/tests/ui/excessive_precision.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::excessive_precision)] #![allow(dead_code, unused_variables, clippy::print_literal)] diff --git a/tests/ui/exhaustive_items.fixed b/tests/ui/exhaustive_items.fixed index c209f5b4b7278..6c7b1cab6f20a 100644 --- a/tests/ui/exhaustive_items.fixed +++ b/tests/ui/exhaustive_items.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![deny(clippy::exhaustive_enums, clippy::exhaustive_structs)] #![allow(unused)] diff --git a/tests/ui/exhaustive_items.rs b/tests/ui/exhaustive_items.rs index 6f59dbf2da59b..d205bac2d2aba 100644 --- a/tests/ui/exhaustive_items.rs +++ b/tests/ui/exhaustive_items.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![deny(clippy::exhaustive_enums, clippy::exhaustive_structs)] #![allow(unused)] diff --git a/tests/ui/expect_fun_call.fixed b/tests/ui/expect_fun_call.fixed index 15172ae345c2e..8e97054fb6bca 100644 --- a/tests/ui/expect_fun_call.fixed +++ b/tests/ui/expect_fun_call.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::expect_fun_call)] #![allow(clippy::to_string_in_format_args, clippy::uninlined_format_args)] diff --git a/tests/ui/expect_fun_call.rs b/tests/ui/expect_fun_call.rs index 0f448d004174f..31e6bcc7ff643 100644 --- a/tests/ui/expect_fun_call.rs +++ b/tests/ui/expect_fun_call.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::expect_fun_call)] #![allow(clippy::to_string_in_format_args, clippy::uninlined_format_args)] diff --git a/tests/ui/explicit_auto_deref.fixed b/tests/ui/explicit_auto_deref.fixed index 5d40c850424ff..71a5ed96d5c46 100644 --- a/tests/ui/explicit_auto_deref.fixed +++ b/tests/ui/explicit_auto_deref.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(closure_lifetime_binder)] #![warn(clippy::explicit_auto_deref)] diff --git a/tests/ui/explicit_auto_deref.rs b/tests/ui/explicit_auto_deref.rs index 79e03f4d76c17..9d0cafa150f6c 100644 --- a/tests/ui/explicit_auto_deref.rs +++ b/tests/ui/explicit_auto_deref.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(closure_lifetime_binder)] #![warn(clippy::explicit_auto_deref)] diff --git a/tests/ui/explicit_deref_methods.fixed b/tests/ui/explicit_deref_methods.fixed index 6d32bbece1e57..77e9f5fc1fdf1 100644 --- a/tests/ui/explicit_deref_methods.fixed +++ b/tests/ui/explicit_deref_methods.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::explicit_deref_methods)] #![allow(unused_variables)] #![allow( diff --git a/tests/ui/explicit_deref_methods.rs b/tests/ui/explicit_deref_methods.rs index 779909e42380c..0c2cc7c2c3a6a 100644 --- a/tests/ui/explicit_deref_methods.rs +++ b/tests/ui/explicit_deref_methods.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::explicit_deref_methods)] #![allow(unused_variables)] #![allow( diff --git a/tests/ui/explicit_write.fixed b/tests/ui/explicit_write.fixed index 862c3fea9ee82..213485bc221b8 100644 --- a/tests/ui/explicit_write.fixed +++ b/tests/ui/explicit_write.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::explicit_write)] #![allow(unused_imports)] #![allow(clippy::uninlined_format_args)] diff --git a/tests/ui/explicit_write.rs b/tests/ui/explicit_write.rs index 41d7c2255738c..64acd7108bfa8 100644 --- a/tests/ui/explicit_write.rs +++ b/tests/ui/explicit_write.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::explicit_write)] #![allow(unused_imports)] #![allow(clippy::uninlined_format_args)] diff --git a/tests/ui/extend_with_drain.fixed b/tests/ui/extend_with_drain.fixed index 71ebad24c16ea..594f2f6d4135e 100644 --- a/tests/ui/extend_with_drain.fixed +++ b/tests/ui/extend_with_drain.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::extend_with_drain)] #![allow(clippy::iter_with_drain)] use std::collections::BinaryHeap; diff --git a/tests/ui/extend_with_drain.rs b/tests/ui/extend_with_drain.rs index e9f011abb0e83..3e2ad02052d78 100644 --- a/tests/ui/extend_with_drain.rs +++ b/tests/ui/extend_with_drain.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::extend_with_drain)] #![allow(clippy::iter_with_drain)] use std::collections::BinaryHeap; diff --git a/tests/ui/extra_unused_lifetimes.rs b/tests/ui/extra_unused_lifetimes.rs index d6631e0129000..cdfaf8d3afea8 100644 --- a/tests/ui/extra_unused_lifetimes.rs +++ b/tests/ui/extra_unused_lifetimes.rs @@ -1,4 +1,4 @@ -// aux-build:proc_macro_derive.rs +//@aux-build:proc_macro_derive.rs #![allow( unused, diff --git a/tests/ui/extra_unused_type_parameters.fixed b/tests/ui/extra_unused_type_parameters.fixed index 19e718625582c..adcd1f6d4076c 100644 --- a/tests/ui/extra_unused_type_parameters.fixed +++ b/tests/ui/extra_unused_type_parameters.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused, clippy::needless_lifetimes)] #![warn(clippy::extra_unused_type_parameters)] diff --git a/tests/ui/extra_unused_type_parameters.rs b/tests/ui/extra_unused_type_parameters.rs index e53bb587e89ac..c4c5227ac9187 100644 --- a/tests/ui/extra_unused_type_parameters.rs +++ b/tests/ui/extra_unused_type_parameters.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused, clippy::needless_lifetimes)] #![warn(clippy::extra_unused_type_parameters)] diff --git a/tests/ui/field_reassign_with_default.rs b/tests/ui/field_reassign_with_default.rs index 0e208b3ed0e15..2045b1eebcd7f 100644 --- a/tests/ui/field_reassign_with_default.rs +++ b/tests/ui/field_reassign_with_default.rs @@ -1,5 +1,5 @@ -// aux-build:proc_macro_derive.rs -// aux-build:proc_macros.rs +//@aux-build:proc_macro_derive.rs +//@aux-build:proc_macros.rs #![warn(clippy::field_reassign_with_default)] diff --git a/tests/ui/filter_map_identity.fixed b/tests/ui/filter_map_identity.fixed index a5860aa49b3bb..44665b451adac 100644 --- a/tests/ui/filter_map_identity.fixed +++ b/tests/ui/filter_map_identity.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused_imports, clippy::needless_return)] #![warn(clippy::filter_map_identity)] diff --git a/tests/ui/filter_map_identity.rs b/tests/ui/filter_map_identity.rs index 7e998b9cdf701..9832acb013f85 100644 --- a/tests/ui/filter_map_identity.rs +++ b/tests/ui/filter_map_identity.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused_imports, clippy::needless_return)] #![warn(clippy::filter_map_identity)] diff --git a/tests/ui/filter_map_next_fixable.fixed b/tests/ui/filter_map_next_fixable.fixed index 462d46169fcbe..efb37f8b1b73c 100644 --- a/tests/ui/filter_map_next_fixable.fixed +++ b/tests/ui/filter_map_next_fixable.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::all, clippy::pedantic)] #![allow(unused)] diff --git a/tests/ui/filter_map_next_fixable.rs b/tests/ui/filter_map_next_fixable.rs index 2ea00cf73072e..b10e20d359ed7 100644 --- a/tests/ui/filter_map_next_fixable.rs +++ b/tests/ui/filter_map_next_fixable.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::all, clippy::pedantic)] #![allow(unused)] diff --git a/tests/ui/flat_map_identity.fixed b/tests/ui/flat_map_identity.fixed index 1f4b880ef5bcd..97091d6f1a5be 100644 --- a/tests/ui/flat_map_identity.fixed +++ b/tests/ui/flat_map_identity.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused_imports, clippy::needless_return)] #![warn(clippy::flat_map_identity)] diff --git a/tests/ui/flat_map_identity.rs b/tests/ui/flat_map_identity.rs index de14a06d4e6b3..5607683a5d04e 100644 --- a/tests/ui/flat_map_identity.rs +++ b/tests/ui/flat_map_identity.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused_imports, clippy::needless_return)] #![warn(clippy::flat_map_identity)] diff --git a/tests/ui/flat_map_option.fixed b/tests/ui/flat_map_option.fixed index 6a34f008995cd..eeab864c42ff7 100644 --- a/tests/ui/flat_map_option.fixed +++ b/tests/ui/flat_map_option.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::flat_map_option)] #![allow(clippy::redundant_closure, clippy::unnecessary_filter_map)] diff --git a/tests/ui/flat_map_option.rs b/tests/ui/flat_map_option.rs index 2479abddbf04e..ebc389f7f0294 100644 --- a/tests/ui/flat_map_option.rs +++ b/tests/ui/flat_map_option.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::flat_map_option)] #![allow(clippy::redundant_closure, clippy::unnecessary_filter_map)] diff --git a/tests/ui/floating_point_abs.fixed b/tests/ui/floating_point_abs.fixed index ca747fefc6468..0cc572822e771 100644 --- a/tests/ui/floating_point_abs.fixed +++ b/tests/ui/floating_point_abs.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(const_fn_floating_point_arithmetic)] #![warn(clippy::suboptimal_flops)] diff --git a/tests/ui/floating_point_abs.rs b/tests/ui/floating_point_abs.rs index e4b6065749798..6c732d398f068 100644 --- a/tests/ui/floating_point_abs.rs +++ b/tests/ui/floating_point_abs.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(const_fn_floating_point_arithmetic)] #![warn(clippy::suboptimal_flops)] diff --git a/tests/ui/floating_point_exp.fixed b/tests/ui/floating_point_exp.fixed index b9e3d89c2b29d..1a33b8153ecab 100644 --- a/tests/ui/floating_point_exp.fixed +++ b/tests/ui/floating_point_exp.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::imprecise_flops)] #![allow(clippy::unnecessary_cast)] diff --git a/tests/ui/floating_point_exp.rs b/tests/ui/floating_point_exp.rs index ef008dd9be055..4f4a5ec81ac9d 100644 --- a/tests/ui/floating_point_exp.rs +++ b/tests/ui/floating_point_exp.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::imprecise_flops)] #![allow(clippy::unnecessary_cast)] diff --git a/tests/ui/floating_point_hypot.fixed b/tests/ui/floating_point_hypot.fixed index bbe411b3f4884..431cb2709787a 100644 --- a/tests/ui/floating_point_hypot.fixed +++ b/tests/ui/floating_point_hypot.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::imprecise_flops)] fn main() { diff --git a/tests/ui/floating_point_hypot.rs b/tests/ui/floating_point_hypot.rs index 586fd170ea145..e5506ed391c02 100644 --- a/tests/ui/floating_point_hypot.rs +++ b/tests/ui/floating_point_hypot.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::imprecise_flops)] fn main() { diff --git a/tests/ui/floating_point_log.fixed b/tests/ui/floating_point_log.fixed index ee54064616007..6582c0a0f6c87 100644 --- a/tests/ui/floating_point_log.fixed +++ b/tests/ui/floating_point_log.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code, clippy::double_parens, clippy::unnecessary_cast)] #![warn(clippy::suboptimal_flops, clippy::imprecise_flops)] diff --git a/tests/ui/floating_point_log.rs b/tests/ui/floating_point_log.rs index 0590670a50bc7..854d269fff59c 100644 --- a/tests/ui/floating_point_log.rs +++ b/tests/ui/floating_point_log.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code, clippy::double_parens, clippy::unnecessary_cast)] #![warn(clippy::suboptimal_flops, clippy::imprecise_flops)] diff --git a/tests/ui/floating_point_logbase.fixed b/tests/ui/floating_point_logbase.fixed index 7347bf72cbea6..0783ecee1eec8 100644 --- a/tests/ui/floating_point_logbase.fixed +++ b/tests/ui/floating_point_logbase.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::suboptimal_flops)] #![allow(clippy::unnecessary_cast)] diff --git a/tests/ui/floating_point_logbase.rs b/tests/ui/floating_point_logbase.rs index ba5b8d4069283..80fcfab682525 100644 --- a/tests/ui/floating_point_logbase.rs +++ b/tests/ui/floating_point_logbase.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::suboptimal_flops)] #![allow(clippy::unnecessary_cast)] diff --git a/tests/ui/floating_point_mul_add.fixed b/tests/ui/floating_point_mul_add.fixed index d3e536ba3500d..8848981a11d8f 100644 --- a/tests/ui/floating_point_mul_add.fixed +++ b/tests/ui/floating_point_mul_add.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(const_fn_floating_point_arithmetic)] #![warn(clippy::suboptimal_flops)] diff --git a/tests/ui/floating_point_mul_add.rs b/tests/ui/floating_point_mul_add.rs index 5d4a9e35cfc22..b0edf5cb210c8 100644 --- a/tests/ui/floating_point_mul_add.rs +++ b/tests/ui/floating_point_mul_add.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(const_fn_floating_point_arithmetic)] #![warn(clippy::suboptimal_flops)] diff --git a/tests/ui/floating_point_powf.fixed b/tests/ui/floating_point_powf.fixed index f7f93de29577d..1e660b140c583 100644 --- a/tests/ui/floating_point_powf.fixed +++ b/tests/ui/floating_point_powf.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::suboptimal_flops, clippy::imprecise_flops)] #![allow(clippy::unnecessary_cast)] diff --git a/tests/ui/floating_point_powf.rs b/tests/ui/floating_point_powf.rs index 499fc0e15e478..71c2f5292053b 100644 --- a/tests/ui/floating_point_powf.rs +++ b/tests/ui/floating_point_powf.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::suboptimal_flops, clippy::imprecise_flops)] #![allow(clippy::unnecessary_cast)] diff --git a/tests/ui/floating_point_powi.fixed b/tests/ui/floating_point_powi.fixed index 8ffd4cc513790..41d5288d6e0cf 100644 --- a/tests/ui/floating_point_powi.fixed +++ b/tests/ui/floating_point_powi.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::suboptimal_flops)] #![allow(clippy::unnecessary_cast)] diff --git a/tests/ui/floating_point_powi.rs b/tests/ui/floating_point_powi.rs index 9ae3455a1346a..7951aab31beba 100644 --- a/tests/ui/floating_point_powi.rs +++ b/tests/ui/floating_point_powi.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::suboptimal_flops)] #![allow(clippy::unnecessary_cast)] diff --git a/tests/ui/floating_point_rad.fixed b/tests/ui/floating_point_rad.fixed index 27674b8a455b0..af23645271289 100644 --- a/tests/ui/floating_point_rad.fixed +++ b/tests/ui/floating_point_rad.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(const_fn_floating_point_arithmetic)] #![warn(clippy::suboptimal_flops)] diff --git a/tests/ui/floating_point_rad.rs b/tests/ui/floating_point_rad.rs index f1ea73df39845..d7612c56a3e49 100644 --- a/tests/ui/floating_point_rad.rs +++ b/tests/ui/floating_point_rad.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(const_fn_floating_point_arithmetic)] #![warn(clippy::suboptimal_flops)] diff --git a/tests/ui/fn_to_numeric_cast.rs b/tests/ui/fn_to_numeric_cast.rs index a456c085c8761..4f6af87088992 100644 --- a/tests/ui/fn_to_numeric_cast.rs +++ b/tests/ui/fn_to_numeric_cast.rs @@ -1,4 +1,4 @@ -// ignore-32bit +//@ignore-32bit #![warn(clippy::fn_to_numeric_cast, clippy::fn_to_numeric_cast_with_truncation)] diff --git a/tests/ui/fn_to_numeric_cast_32bit.rs b/tests/ui/fn_to_numeric_cast_32bit.rs index 04ee985c0863d..62ce97f098d4c 100644 --- a/tests/ui/fn_to_numeric_cast_32bit.rs +++ b/tests/ui/fn_to_numeric_cast_32bit.rs @@ -1,4 +1,4 @@ -// ignore-64bit +//@ignore-64bit #![warn(clippy::fn_to_numeric_cast, clippy::fn_to_numeric_cast_with_truncation)] diff --git a/tests/ui/fn_to_numeric_cast_32bit.stderr b/tests/ui/fn_to_numeric_cast_32bit.stderr index 08dd611d67524..671347d2bcd54 100644 --- a/tests/ui/fn_to_numeric_cast_32bit.stderr +++ b/tests/ui/fn_to_numeric_cast_32bit.stderr @@ -12,19 +12,19 @@ error: casting function pointer `foo` to `i16`, which truncates the value LL | let _ = foo as i16; | ^^^^^^^^^^ help: try: `foo as usize` -error: casting function pointer `foo` to `i32` +error: casting function pointer `foo` to `i32`, which truncates the value --> $DIR/fn_to_numeric_cast_32bit.rs:12:13 | LL | let _ = foo as i32; | ^^^^^^^^^^ help: try: `foo as usize` - | - = note: `-D clippy::fn-to-numeric-cast` implied by `-D warnings` error: casting function pointer `foo` to `i64` --> $DIR/fn_to_numeric_cast_32bit.rs:13:13 | LL | let _ = foo as i64; | ^^^^^^^^^^ help: try: `foo as usize` + | + = note: `-D clippy::fn-to-numeric-cast` implied by `-D warnings` error: casting function pointer `foo` to `i128` --> $DIR/fn_to_numeric_cast_32bit.rs:14:13 @@ -50,7 +50,7 @@ error: casting function pointer `foo` to `u16`, which truncates the value LL | let _ = foo as u16; | ^^^^^^^^^^ help: try: `foo as usize` -error: casting function pointer `foo` to `u32` +error: casting function pointer `foo` to `u32`, which truncates the value --> $DIR/fn_to_numeric_cast_32bit.rs:19:13 | LL | let _ = foo as u32; @@ -80,7 +80,7 @@ error: casting function pointer `abc` to `i16`, which truncates the value LL | let _ = abc as i16; | ^^^^^^^^^^ help: try: `abc as usize` -error: casting function pointer `abc` to `i32` +error: casting function pointer `abc` to `i32`, which truncates the value --> $DIR/fn_to_numeric_cast_32bit.rs:36:13 | LL | let _ = abc as i32; @@ -116,7 +116,7 @@ error: casting function pointer `abc` to `u16`, which truncates the value LL | let _ = abc as u16; | ^^^^^^^^^^ help: try: `abc as usize` -error: casting function pointer `abc` to `u32` +error: casting function pointer `abc` to `u32`, which truncates the value --> $DIR/fn_to_numeric_cast_32bit.rs:43:13 | LL | let _ = abc as u32; @@ -134,7 +134,7 @@ error: casting function pointer `abc` to `u128` LL | let _ = abc as u128; | ^^^^^^^^^^^ help: try: `abc as usize` -error: casting function pointer `f` to `i32` +error: casting function pointer `f` to `i32`, which truncates the value --> $DIR/fn_to_numeric_cast_32bit.rs:52:5 | LL | f as i32 diff --git a/tests/ui/for_loop_fixable.fixed b/tests/ui/for_loop_fixable.fixed index e9dd38fe40e65..f578c98da1534 100644 --- a/tests/ui/for_loop_fixable.fixed +++ b/tests/ui/for_loop_fixable.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code, unused)] #![allow(clippy::uninlined_format_args)] diff --git a/tests/ui/for_loop_fixable.rs b/tests/ui/for_loop_fixable.rs index 534fb4dd4ef28..42bc6de0c7dda 100644 --- a/tests/ui/for_loop_fixable.rs +++ b/tests/ui/for_loop_fixable.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code, unused)] #![allow(clippy::uninlined_format_args)] diff --git a/tests/ui/format.fixed b/tests/ui/format.fixed index beedf2c1db292..9288956f51306 100644 --- a/tests/ui/format.fixed +++ b/tests/ui/format.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::useless_format)] #![allow( unused_tuple_struct_fields, diff --git a/tests/ui/format.rs b/tests/ui/format.rs index e805f18188989..b2b817e0f4c43 100644 --- a/tests/ui/format.rs +++ b/tests/ui/format.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::useless_format)] #![allow( unused_tuple_struct_fields, diff --git a/tests/ui/format_args.fixed b/tests/ui/format_args.fixed index 825e122be5a5f..ea38368613570 100644 --- a/tests/ui/format_args.fixed +++ b/tests/ui/format_args.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::to_string_in_format_args)] #![allow(unused)] #![allow( diff --git a/tests/ui/format_args.rs b/tests/ui/format_args.rs index a41e53389e52a..bfb324492467e 100644 --- a/tests/ui/format_args.rs +++ b/tests/ui/format_args.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::to_string_in_format_args)] #![allow(unused)] #![allow( diff --git a/tests/ui/from_iter_instead_of_collect.fixed b/tests/ui/from_iter_instead_of_collect.fixed index 48f8093311cbd..915ff4fb079d2 100644 --- a/tests/ui/from_iter_instead_of_collect.fixed +++ b/tests/ui/from_iter_instead_of_collect.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::from_iter_instead_of_collect)] #![allow(unused_imports, unused_tuple_struct_fields)] diff --git a/tests/ui/from_iter_instead_of_collect.rs b/tests/ui/from_iter_instead_of_collect.rs index ebe0ad278be30..e926f8c529df3 100644 --- a/tests/ui/from_iter_instead_of_collect.rs +++ b/tests/ui/from_iter_instead_of_collect.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::from_iter_instead_of_collect)] #![allow(unused_imports, unused_tuple_struct_fields)] diff --git a/tests/ui/from_over_into.fixed b/tests/ui/from_over_into.fixed index 72d635c2ccd65..fc6d937060dc0 100644 --- a/tests/ui/from_over_into.fixed +++ b/tests/ui/from_over_into.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(type_alias_impl_trait)] #![warn(clippy::from_over_into)] diff --git a/tests/ui/from_over_into.rs b/tests/ui/from_over_into.rs index 965f4d5d7859e..fe1ebee35f166 100644 --- a/tests/ui/from_over_into.rs +++ b/tests/ui/from_over_into.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(type_alias_impl_trait)] #![warn(clippy::from_over_into)] diff --git a/tests/ui/get_first.fixed b/tests/ui/get_first.fixed index def58afa4fbf2..ef132b7961177 100644 --- a/tests/ui/get_first.fixed +++ b/tests/ui/get_first.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::get_first)] use std::collections::BTreeMap; use std::collections::HashMap; diff --git a/tests/ui/get_first.rs b/tests/ui/get_first.rs index 85a381854cd3b..4d8722356144e 100644 --- a/tests/ui/get_first.rs +++ b/tests/ui/get_first.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::get_first)] use std::collections::BTreeMap; use std::collections::HashMap; diff --git a/tests/ui/get_last_with_len.fixed b/tests/ui/get_last_with_len.fixed index 1e90b37687a15..a58dfda798855 100644 --- a/tests/ui/get_last_with_len.fixed +++ b/tests/ui/get_last_with_len.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::get_last_with_len)] #![allow(unused)] diff --git a/tests/ui/get_last_with_len.rs b/tests/ui/get_last_with_len.rs index d63a731bd5246..d626656c78f95 100644 --- a/tests/ui/get_last_with_len.rs +++ b/tests/ui/get_last_with_len.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::get_last_with_len)] #![allow(unused)] diff --git a/tests/ui/get_unwrap.fixed b/tests/ui/get_unwrap.fixed index 5827fc7d76e60..4950c47ddeb80 100644 --- a/tests/ui/get_unwrap.fixed +++ b/tests/ui/get_unwrap.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused_mut, clippy::from_iter_instead_of_collect, clippy::get_first)] #![warn(clippy::unwrap_used)] diff --git a/tests/ui/get_unwrap.rs b/tests/ui/get_unwrap.rs index a2a323c14fb7c..6b1e8edb7bd2f 100644 --- a/tests/ui/get_unwrap.rs +++ b/tests/ui/get_unwrap.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused_mut, clippy::from_iter_instead_of_collect, clippy::get_first)] #![warn(clippy::unwrap_used)] diff --git a/tests/ui/identity_op.fixed b/tests/ui/identity_op.fixed index cac69ef42c413..beb16000eca20 100644 --- a/tests/ui/identity_op.fixed +++ b/tests/ui/identity_op.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::identity_op)] #![allow(unused)] #![allow( diff --git a/tests/ui/identity_op.rs b/tests/ui/identity_op.rs index 33201aad4f641..072e00c00f0ad 100644 --- a/tests/ui/identity_op.rs +++ b/tests/ui/identity_op.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::identity_op)] #![allow(unused)] #![allow( diff --git a/tests/ui/implicit_clone.fixed b/tests/ui/implicit_clone.fixed index 8ccc3da7b47c0..e62db8b40be68 100644 --- a/tests/ui/implicit_clone.fixed +++ b/tests/ui/implicit_clone.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::implicit_clone)] #![allow(clippy::clone_on_copy, clippy::redundant_clone)] use std::borrow::Borrow; diff --git a/tests/ui/implicit_clone.rs b/tests/ui/implicit_clone.rs index 5933331260777..88352b06af3cb 100644 --- a/tests/ui/implicit_clone.rs +++ b/tests/ui/implicit_clone.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::implicit_clone)] #![allow(clippy::clone_on_copy, clippy::redundant_clone)] use std::borrow::Borrow; diff --git a/tests/ui/implicit_hasher.rs b/tests/ui/implicit_hasher.rs index 35d08a07bc3fe..ca7c12213728b 100644 --- a/tests/ui/implicit_hasher.rs +++ b/tests/ui/implicit_hasher.rs @@ -1,4 +1,4 @@ -// aux-build:proc_macros.rs +//@aux-build:proc_macros.rs #![deny(clippy::implicit_hasher)] #![allow(unused)] diff --git a/tests/ui/implicit_return.fixed b/tests/ui/implicit_return.fixed index 5e55b8b673919..64813eafda644 100644 --- a/tests/ui/implicit_return.fixed +++ b/tests/ui/implicit_return.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(lint_reasons)] #![warn(clippy::implicit_return)] #![allow(clippy::needless_return, clippy::needless_bool, unused, clippy::never_loop)] diff --git a/tests/ui/implicit_return.rs b/tests/ui/implicit_return.rs index 76f0a98035209..39d47b110db7f 100644 --- a/tests/ui/implicit_return.rs +++ b/tests/ui/implicit_return.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(lint_reasons)] #![warn(clippy::implicit_return)] #![allow(clippy::needless_return, clippy::needless_bool, unused, clippy::never_loop)] diff --git a/tests/ui/implicit_saturating_add.fixed b/tests/ui/implicit_saturating_add.fixed index 7d363d59a6f09..7fc510d6b415d 100644 --- a/tests/ui/implicit_saturating_add.fixed +++ b/tests/ui/implicit_saturating_add.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] #![warn(clippy::implicit_saturating_add)] diff --git a/tests/ui/implicit_saturating_add.rs b/tests/ui/implicit_saturating_add.rs index 31a5916277fa7..3dcd91f42fedb 100644 --- a/tests/ui/implicit_saturating_add.rs +++ b/tests/ui/implicit_saturating_add.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] #![warn(clippy::implicit_saturating_add)] diff --git a/tests/ui/implicit_saturating_sub.fixed b/tests/ui/implicit_saturating_sub.fixed index 93df81b1a7ff0..1a11db0982f7b 100644 --- a/tests/ui/implicit_saturating_sub.fixed +++ b/tests/ui/implicit_saturating_sub.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused_assignments, unused_mut, clippy::assign_op_pattern)] #![warn(clippy::implicit_saturating_sub)] diff --git a/tests/ui/implicit_saturating_sub.rs b/tests/ui/implicit_saturating_sub.rs index 8340bc8264d58..9369df67430c5 100644 --- a/tests/ui/implicit_saturating_sub.rs +++ b/tests/ui/implicit_saturating_sub.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused_assignments, unused_mut, clippy::assign_op_pattern)] #![warn(clippy::implicit_saturating_sub)] diff --git a/tests/ui/inconsistent_digit_grouping.fixed b/tests/ui/inconsistent_digit_grouping.fixed index dd683e7f746a4..06919809ee926 100644 --- a/tests/ui/inconsistent_digit_grouping.fixed +++ b/tests/ui/inconsistent_digit_grouping.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #[warn(clippy::inconsistent_digit_grouping)] #[deny(clippy::unreadable_literal)] #[allow(unused_variables, clippy::excessive_precision)] diff --git a/tests/ui/inconsistent_digit_grouping.rs b/tests/ui/inconsistent_digit_grouping.rs index d5d27c853c28d..04d9125f2bfa9 100644 --- a/tests/ui/inconsistent_digit_grouping.rs +++ b/tests/ui/inconsistent_digit_grouping.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #[warn(clippy::inconsistent_digit_grouping)] #[deny(clippy::unreadable_literal)] #[allow(unused_variables, clippy::excessive_precision)] diff --git a/tests/ui/inconsistent_struct_constructor.fixed b/tests/ui/inconsistent_struct_constructor.fixed index 5aaa00f851724..620d45e6828cc 100644 --- a/tests/ui/inconsistent_struct_constructor.fixed +++ b/tests/ui/inconsistent_struct_constructor.fixed @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:proc_macros.rs +//@run-rustfix +//@aux-build:proc_macros.rs #![warn(clippy::inconsistent_struct_constructor)] #![allow(clippy::redundant_field_names)] diff --git a/tests/ui/inconsistent_struct_constructor.rs b/tests/ui/inconsistent_struct_constructor.rs index 2b2dd7f59a4da..10ffadcb2ba90 100644 --- a/tests/ui/inconsistent_struct_constructor.rs +++ b/tests/ui/inconsistent_struct_constructor.rs @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:proc_macros.rs +//@run-rustfix +//@aux-build:proc_macros.rs #![warn(clippy::inconsistent_struct_constructor)] #![allow(clippy::redundant_field_names)] diff --git a/tests/ui/inefficient_to_string.fixed b/tests/ui/inefficient_to_string.fixed index c972b9419ef76..557f7fb73585d 100644 --- a/tests/ui/inefficient_to_string.fixed +++ b/tests/ui/inefficient_to_string.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![deny(clippy::inefficient_to_string)] use std::borrow::Cow; diff --git a/tests/ui/inefficient_to_string.rs b/tests/ui/inefficient_to_string.rs index acdc55aa0d69d..6503001e345bc 100644 --- a/tests/ui/inefficient_to_string.rs +++ b/tests/ui/inefficient_to_string.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![deny(clippy::inefficient_to_string)] use std::borrow::Cow; diff --git a/tests/ui/infallible_destructuring_match.fixed b/tests/ui/infallible_destructuring_match.fixed index 61985e56b769e..e396ae94aaab2 100644 --- a/tests/ui/infallible_destructuring_match.fixed +++ b/tests/ui/infallible_destructuring_match.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(exhaustive_patterns, never_type)] #![allow(dead_code, unreachable_code, unused_variables)] #![allow(clippy::let_and_return)] diff --git a/tests/ui/infallible_destructuring_match.rs b/tests/ui/infallible_destructuring_match.rs index f2768245bbc41..3fce7bbb6c712 100644 --- a/tests/ui/infallible_destructuring_match.rs +++ b/tests/ui/infallible_destructuring_match.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(exhaustive_patterns, never_type)] #![allow(dead_code, unreachable_code, unused_variables)] #![allow(clippy::let_and_return)] diff --git a/tests/ui/inline_fn_without_body.fixed b/tests/ui/inline_fn_without_body.fixed index fe21a71a42c26..9c5819558feab 100644 --- a/tests/ui/inline_fn_without_body.fixed +++ b/tests/ui/inline_fn_without_body.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::inline_fn_without_body)] #![allow(clippy::inline_always)] diff --git a/tests/ui/inline_fn_without_body.rs b/tests/ui/inline_fn_without_body.rs index 5074698946650..43ffaf8122b6d 100644 --- a/tests/ui/inline_fn_without_body.rs +++ b/tests/ui/inline_fn_without_body.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::inline_fn_without_body)] #![allow(clippy::inline_always)] diff --git a/tests/ui/int_plus_one.fixed b/tests/ui/int_plus_one.fixed index 642830f24f58a..5a36ec462d4c6 100644 --- a/tests/ui/int_plus_one.fixed +++ b/tests/ui/int_plus_one.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #[allow(clippy::no_effect, clippy::unnecessary_operation)] #[warn(clippy::int_plus_one)] diff --git a/tests/ui/int_plus_one.rs b/tests/ui/int_plus_one.rs index 0755a0c79d280..bffa4afd6b080 100644 --- a/tests/ui/int_plus_one.rs +++ b/tests/ui/int_plus_one.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #[allow(clippy::no_effect, clippy::unnecessary_operation)] #[warn(clippy::int_plus_one)] diff --git a/tests/ui/integer_arithmetic.rs b/tests/ui/integer_arithmetic.rs index 8dfdee662b9d7..ab9b6094c2c1d 100644 --- a/tests/ui/integer_arithmetic.rs +++ b/tests/ui/integer_arithmetic.rs @@ -1,6 +1,13 @@ +//@aux-build:proc_macro_derive.rs + #![warn(clippy::integer_arithmetic, clippy::float_arithmetic)] #![allow(clippy::no_effect, clippy::unnecessary_operation, clippy::op_ref)] +extern crate proc_macro_derive; + +#[derive(proc_macro_derive::ShadowDerive)] +pub struct Nothing; + #[rustfmt::skip] fn main() { let mut i = 1i32; diff --git a/tests/ui/integer_arithmetic.stderr b/tests/ui/integer_arithmetic.stderr index 9a795b1f29154..add3b6b90fa26 100644 --- a/tests/ui/integer_arithmetic.stderr +++ b/tests/ui/integer_arithmetic.stderr @@ -1,5 +1,5 @@ error: this operation will panic at runtime - --> $DIR/integer_arithmetic.rs:30:5 + --> $DIR/integer_arithmetic.rs:37:5 | LL | i /= 0; | ^^^^^^ attempt to divide `_` by zero @@ -7,13 +7,13 @@ LL | i /= 0; = note: `#[deny(unconditional_panic)]` on by default error: this operation will panic at runtime - --> $DIR/integer_arithmetic.rs:35:5 + --> $DIR/integer_arithmetic.rs:42:5 | LL | i %= 0; | ^^^^^^ attempt to calculate the remainder of `_` with a divisor of zero error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:9:5 + --> $DIR/integer_arithmetic.rs:16:5 | LL | 1 + i; | ^^^^^ @@ -21,146 +21,146 @@ LL | 1 + i; = note: `-D clippy::integer-arithmetic` implied by `-D warnings` error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:10:5 + --> $DIR/integer_arithmetic.rs:17:5 | LL | i * 2; | ^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:11:5 + --> $DIR/integer_arithmetic.rs:18:5 | LL | / 1 % LL | | i / 2; // no error, this is part of the expression in the preceding line | |_____^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:13:5 + --> $DIR/integer_arithmetic.rs:20:5 | LL | i - 2 + 2 - i; | ^^^^^^^^^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:14:5 + --> $DIR/integer_arithmetic.rs:21:5 | LL | -i; | ^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:15:5 + --> $DIR/integer_arithmetic.rs:22:5 | LL | i >> 1; | ^^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:16:5 + --> $DIR/integer_arithmetic.rs:23:5 | LL | i << 1; | ^^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:26:5 + --> $DIR/integer_arithmetic.rs:33:5 | LL | i += 1; | ^^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:27:5 + --> $DIR/integer_arithmetic.rs:34:5 | LL | i -= 1; | ^^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:28:5 + --> $DIR/integer_arithmetic.rs:35:5 | LL | i *= 2; | ^^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:31:11 + --> $DIR/integer_arithmetic.rs:38:11 | LL | i /= -1; | ^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:32:5 + --> $DIR/integer_arithmetic.rs:39:5 | LL | i /= var1; | ^^^^^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:33:5 + --> $DIR/integer_arithmetic.rs:40:5 | LL | i /= var2; | ^^^^^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:36:11 + --> $DIR/integer_arithmetic.rs:43:11 | LL | i %= -1; | ^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:37:5 + --> $DIR/integer_arithmetic.rs:44:5 | LL | i %= var1; | ^^^^^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:38:5 + --> $DIR/integer_arithmetic.rs:45:5 | LL | i %= var2; | ^^^^^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:39:5 + --> $DIR/integer_arithmetic.rs:46:5 | LL | i <<= 3; | ^^^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:40:5 + --> $DIR/integer_arithmetic.rs:47:5 | LL | i >>= 2; | ^^^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:82:5 + --> $DIR/integer_arithmetic.rs:89:5 | LL | 3 + &1; | ^^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:83:5 + --> $DIR/integer_arithmetic.rs:90:5 | LL | &3 + 1; | ^^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:84:5 + --> $DIR/integer_arithmetic.rs:91:5 | LL | &3 + &1; | ^^^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:89:5 + --> $DIR/integer_arithmetic.rs:96:5 | LL | a + x | ^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:93:5 + --> $DIR/integer_arithmetic.rs:100:5 | LL | x + y | ^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:97:5 + --> $DIR/integer_arithmetic.rs:104:5 | LL | x + y | ^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:101:5 + --> $DIR/integer_arithmetic.rs:108:5 | LL | (&x + &y) | ^^^^^^^^^ diff --git a/tests/ui/into_iter_on_ref.fixed b/tests/ui/into_iter_on_ref.fixed index b77f17944d89a..9f550acb1577c 100644 --- a/tests/ui/into_iter_on_ref.fixed +++ b/tests/ui/into_iter_on_ref.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(clippy::useless_vec, clippy::needless_borrow)] #![warn(clippy::into_iter_on_ref)] diff --git a/tests/ui/into_iter_on_ref.rs b/tests/ui/into_iter_on_ref.rs index 3854bb05af8fb..3381ae04dcecd 100644 --- a/tests/ui/into_iter_on_ref.rs +++ b/tests/ui/into_iter_on_ref.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(clippy::useless_vec, clippy::needless_borrow)] #![warn(clippy::into_iter_on_ref)] diff --git a/tests/ui/invalid_null_ptr_usage.fixed b/tests/ui/invalid_null_ptr_usage.fixed index 4f5322ebf202f..9264fb7e9e7d8 100644 --- a/tests/ui/invalid_null_ptr_usage.fixed +++ b/tests/ui/invalid_null_ptr_usage.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix fn main() { unsafe { diff --git a/tests/ui/invalid_null_ptr_usage.rs b/tests/ui/invalid_null_ptr_usage.rs index ae51c52d8af0c..80c942d775729 100644 --- a/tests/ui/invalid_null_ptr_usage.rs +++ b/tests/ui/invalid_null_ptr_usage.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix fn main() { unsafe { diff --git a/tests/ui/is_digit_ascii_radix.fixed b/tests/ui/is_digit_ascii_radix.fixed index c0ba647d70791..bc43303a680df 100644 --- a/tests/ui/is_digit_ascii_radix.fixed +++ b/tests/ui/is_digit_ascii_radix.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::is_digit_ascii_radix)] diff --git a/tests/ui/is_digit_ascii_radix.rs b/tests/ui/is_digit_ascii_radix.rs index 68e3f3243d96d..93cba5c8e4e56 100644 --- a/tests/ui/is_digit_ascii_radix.rs +++ b/tests/ui/is_digit_ascii_radix.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::is_digit_ascii_radix)] diff --git a/tests/ui/issue_2356.fixed b/tests/ui/issue_2356.fixed index a73ee0fb2e594..a69f5ebdc08c5 100644 --- a/tests/ui/issue_2356.fixed +++ b/tests/ui/issue_2356.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![deny(clippy::while_let_on_iterator)] #![allow(unused_mut)] #![allow(clippy::uninlined_format_args)] diff --git a/tests/ui/issue_2356.rs b/tests/ui/issue_2356.rs index 9dd9069609b14..50e1bce1f8c91 100644 --- a/tests/ui/issue_2356.rs +++ b/tests/ui/issue_2356.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![deny(clippy::while_let_on_iterator)] #![allow(unused_mut)] #![allow(clippy::uninlined_format_args)] diff --git a/tests/ui/items_after_test_module.rs b/tests/ui/items_after_test_module.rs new file mode 100644 index 0000000000000..5136b2557ec1a --- /dev/null +++ b/tests/ui/items_after_test_module.rs @@ -0,0 +1,23 @@ +//@compile-flags: --test +#![allow(unused)] +#![warn(clippy::items_after_test_module)] + +fn main() {} + +fn should_not_lint() {} + +#[allow(dead_code)] +#[allow(unused)] // Some attributes to check that span replacement is good enough +#[allow(clippy::allow_attributes)] +#[cfg(test)] +mod tests { + #[test] + fn hi() {} +} + +fn should_lint() {} + +const SHOULD_ALSO_LINT: usize = 1; +macro_rules! should_not_lint { + () => {}; +} diff --git a/tests/ui/items_after_test_module.stderr b/tests/ui/items_after_test_module.stderr new file mode 100644 index 0000000000000..8f1616dabc1f0 --- /dev/null +++ b/tests/ui/items_after_test_module.stderr @@ -0,0 +1,17 @@ +error: items were found after the testing module + --> $DIR/items_after_test_module.rs:13:1 + | +LL | / mod tests { +LL | | #[test] +LL | | fn hi() {} +LL | | } +... | +LL | | () => {}; +LL | | } + | |_^ + | + = help: move the items to before the testing module was defined + = note: `-D clippy::items-after-test-module` implied by `-D warnings` + +error: aborting due to previous error + diff --git a/tests/ui/iter_cloned_collect.fixed b/tests/ui/iter_cloned_collect.fixed index 9b86213358045..88f08bb991b8d 100644 --- a/tests/ui/iter_cloned_collect.fixed +++ b/tests/ui/iter_cloned_collect.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] diff --git a/tests/ui/iter_cloned_collect.rs b/tests/ui/iter_cloned_collect.rs index 639f50665f2aa..d3438b7f51a2c 100644 --- a/tests/ui/iter_cloned_collect.rs +++ b/tests/ui/iter_cloned_collect.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] diff --git a/tests/ui/iter_count.fixed b/tests/ui/iter_count.fixed index 90a6eef75261f..4367a12f820d5 100644 --- a/tests/ui/iter_count.fixed +++ b/tests/ui/iter_count.fixed @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:option_helpers.rs +//@run-rustfix +//@aux-build:option_helpers.rs #![warn(clippy::iter_count)] #![allow( diff --git a/tests/ui/iter_count.rs b/tests/ui/iter_count.rs index 6681a480a28c8..8c7543cf03b39 100644 --- a/tests/ui/iter_count.rs +++ b/tests/ui/iter_count.rs @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:option_helpers.rs +//@run-rustfix +//@aux-build:option_helpers.rs #![warn(clippy::iter_count)] #![allow( diff --git a/tests/ui/iter_kv_map.fixed b/tests/ui/iter_kv_map.fixed index f2a4c284cb16d..64201b553fdde 100644 --- a/tests/ui/iter_kv_map.fixed +++ b/tests/ui/iter_kv_map.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::iter_kv_map)] #![allow(unused_mut, clippy::redundant_clone, clippy::suspicious_map, clippy::map_identity)] diff --git a/tests/ui/iter_kv_map.rs b/tests/ui/iter_kv_map.rs index ad6564df40846..ec0231ba5727b 100644 --- a/tests/ui/iter_kv_map.rs +++ b/tests/ui/iter_kv_map.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::iter_kv_map)] #![allow(unused_mut, clippy::redundant_clone, clippy::suspicious_map, clippy::map_identity)] diff --git a/tests/ui/iter_next_slice.fixed b/tests/ui/iter_next_slice.fixed index f612d26aaabcc..d862abc34e0bb 100644 --- a/tests/ui/iter_next_slice.fixed +++ b/tests/ui/iter_next_slice.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::iter_next_slice)] fn main() { diff --git a/tests/ui/iter_next_slice.rs b/tests/ui/iter_next_slice.rs index 5195f1c86675f..da6fc46e42874 100644 --- a/tests/ui/iter_next_slice.rs +++ b/tests/ui/iter_next_slice.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::iter_next_slice)] fn main() { diff --git a/tests/ui/iter_nth.rs b/tests/ui/iter_nth.rs index 9c21dd82ee45e..e7fb97d4fbc8a 100644 --- a/tests/ui/iter_nth.rs +++ b/tests/ui/iter_nth.rs @@ -1,4 +1,4 @@ -// aux-build:option_helpers.rs +//@aux-build:option_helpers.rs #![warn(clippy::iter_nth)] diff --git a/tests/ui/iter_nth_zero.fixed b/tests/ui/iter_nth_zero.fixed index f23671c26e4cc..587b0d1d366a7 100644 --- a/tests/ui/iter_nth_zero.fixed +++ b/tests/ui/iter_nth_zero.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::iter_nth_zero)] use std::collections::HashSet; diff --git a/tests/ui/iter_nth_zero.rs b/tests/ui/iter_nth_zero.rs index 7c968d4984571..93b576ec56fed 100644 --- a/tests/ui/iter_nth_zero.rs +++ b/tests/ui/iter_nth_zero.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::iter_nth_zero)] use std::collections::HashSet; diff --git a/tests/ui/iter_on_empty_collections.fixed b/tests/ui/iter_on_empty_collections.fixed index bd9b07aefbfb8..4616f0cdc45e5 100644 --- a/tests/ui/iter_on_empty_collections.fixed +++ b/tests/ui/iter_on_empty_collections.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::iter_on_empty_collections)] #![allow(clippy::iter_next_slice, clippy::redundant_clone)] diff --git a/tests/ui/iter_on_empty_collections.rs b/tests/ui/iter_on_empty_collections.rs index e15ba94bd4655..81cc7265e11e4 100644 --- a/tests/ui/iter_on_empty_collections.rs +++ b/tests/ui/iter_on_empty_collections.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::iter_on_empty_collections)] #![allow(clippy::iter_next_slice, clippy::redundant_clone)] diff --git a/tests/ui/iter_on_single_items.fixed b/tests/ui/iter_on_single_items.fixed index 1fa4b03641bc7..80dbe454b4708 100644 --- a/tests/ui/iter_on_single_items.fixed +++ b/tests/ui/iter_on_single_items.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::iter_on_single_items)] #![allow(clippy::iter_next_slice, clippy::redundant_clone)] diff --git a/tests/ui/iter_on_single_items.rs b/tests/ui/iter_on_single_items.rs index ea96d8066c568..71c8c7a3f94cc 100644 --- a/tests/ui/iter_on_single_items.rs +++ b/tests/ui/iter_on_single_items.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::iter_on_single_items)] #![allow(clippy::iter_next_slice, clippy::redundant_clone)] diff --git a/tests/ui/iter_overeager_cloned.fixed b/tests/ui/iter_overeager_cloned.fixed index c100705d01781..bf576e9cbfb34 100644 --- a/tests/ui/iter_overeager_cloned.fixed +++ b/tests/ui/iter_overeager_cloned.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::iter_overeager_cloned, clippy::redundant_clone, clippy::filter_next)] #![allow(dead_code, clippy::let_unit_value)] diff --git a/tests/ui/iter_overeager_cloned.rs b/tests/ui/iter_overeager_cloned.rs index 2caa88020662d..df42d88eff00d 100644 --- a/tests/ui/iter_overeager_cloned.rs +++ b/tests/ui/iter_overeager_cloned.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::iter_overeager_cloned, clippy::redundant_clone, clippy::filter_next)] #![allow(dead_code, clippy::let_unit_value)] diff --git a/tests/ui/iter_skip_next.fixed b/tests/ui/iter_skip_next.fixed index d56d623b5268e..8f2cefc430434 100644 --- a/tests/ui/iter_skip_next.fixed +++ b/tests/ui/iter_skip_next.fixed @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:option_helpers.rs +//@run-rustfix +//@aux-build:option_helpers.rs #![warn(clippy::iter_skip_next)] #![allow(clippy::disallowed_names)] diff --git a/tests/ui/iter_skip_next.rs b/tests/ui/iter_skip_next.rs index 3ec5d1b821426..71d83384f3a05 100644 --- a/tests/ui/iter_skip_next.rs +++ b/tests/ui/iter_skip_next.rs @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:option_helpers.rs +//@run-rustfix +//@aux-build:option_helpers.rs #![warn(clippy::iter_skip_next)] #![allow(clippy::disallowed_names)] diff --git a/tests/ui/iter_with_drain.fixed b/tests/ui/iter_with_drain.fixed index 0330d5549264a..24a95c4d0fee4 100644 --- a/tests/ui/iter_with_drain.fixed +++ b/tests/ui/iter_with_drain.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix // will emits unused mut warnings after fixing #![allow(unused_mut)] // will emits needless collect warnings after fixing diff --git a/tests/ui/iter_with_drain.rs b/tests/ui/iter_with_drain.rs index 993936fb8de3d..a118c981ee3f5 100644 --- a/tests/ui/iter_with_drain.rs +++ b/tests/ui/iter_with_drain.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix // will emits unused mut warnings after fixing #![allow(unused_mut)] // will emits needless collect warnings after fixing diff --git a/tests/ui/large_const_arrays.fixed b/tests/ui/large_const_arrays.fixed index c5af07c8a1728..f7ce6fbe6bb4c 100644 --- a/tests/ui/large_const_arrays.fixed +++ b/tests/ui/large_const_arrays.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::large_const_arrays)] #![allow(dead_code)] diff --git a/tests/ui/large_const_arrays.rs b/tests/ui/large_const_arrays.rs index a160b9f8ad5b0..002ac77ddda9c 100644 --- a/tests/ui/large_const_arrays.rs +++ b/tests/ui/large_const_arrays.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::large_const_arrays)] #![allow(dead_code)] diff --git a/tests/ui/large_digit_groups.fixed b/tests/ui/large_digit_groups.fixed index ea18dac068336..f42fcd96d7955 100644 --- a/tests/ui/large_digit_groups.fixed +++ b/tests/ui/large_digit_groups.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::large_digit_groups)] fn main() { diff --git a/tests/ui/large_digit_groups.rs b/tests/ui/large_digit_groups.rs index ac116d5dbda15..3db9da6a3a58a 100644 --- a/tests/ui/large_digit_groups.rs +++ b/tests/ui/large_digit_groups.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::large_digit_groups)] fn main() { diff --git a/tests/ui/large_enum_variant.rs b/tests/ui/large_enum_variant.rs index f09f8ae0ccc35..ea8bc5b4aca1f 100644 --- a/tests/ui/large_enum_variant.rs +++ b/tests/ui/large_enum_variant.rs @@ -1,4 +1,4 @@ -// aux-build:proc_macros.rs +//@aux-build:proc_macros.rs #![allow(dead_code)] #![allow(unused_variables)] diff --git a/tests/ui/large_types_passed_by_value.rs b/tests/ui/large_types_passed_by_value.rs index 7601b5c66fa35..f9e3c7192ad5b 100644 --- a/tests/ui/large_types_passed_by_value.rs +++ b/tests/ui/large_types_passed_by_value.rs @@ -1,5 +1,5 @@ -// normalize-stderr-test "\(\d+ byte\)" -> "(N byte)" -// normalize-stderr-test "\(limit: \d+ byte\)" -> "(limit: N byte)" +//@normalize-stderr-test: "\(\d+ byte\)" -> "(N byte)" +//@normalize-stderr-test: "\(limit: \d+ byte\)" -> "(limit: N byte)" #![warn(clippy::large_types_passed_by_value)] diff --git a/tests/ui/len_zero.fixed b/tests/ui/len_zero.fixed index c1c0b5ae40f61..2c22abd7e4b14 100644 --- a/tests/ui/len_zero.fixed +++ b/tests/ui/len_zero.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::len_zero)] #![allow(dead_code, unused, clippy::len_without_is_empty)] @@ -176,6 +176,10 @@ fn main() { // No error; `HasWrongIsEmpty` does not have `.is_empty()`. println!("Or this!"); } + + // issue #10529 + (!has_is_empty.is_empty()).then(|| println!("This can happen.")); + (has_is_empty.is_empty()).then(|| println!("Or this!")); } fn test_slice(b: &[u8]) { diff --git a/tests/ui/len_zero.rs b/tests/ui/len_zero.rs index cc2eb05b6bfd2..a011ff976448b 100644 --- a/tests/ui/len_zero.rs +++ b/tests/ui/len_zero.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::len_zero)] #![allow(dead_code, unused, clippy::len_without_is_empty)] @@ -176,6 +176,10 @@ fn main() { // No error; `HasWrongIsEmpty` does not have `.is_empty()`. println!("Or this!"); } + + // issue #10529 + (has_is_empty.len() > 0).then(|| println!("This can happen.")); + (has_is_empty.len() == 0).then(|| println!("Or this!")); } fn test_slice(b: &[u8]) { diff --git a/tests/ui/len_zero.stderr b/tests/ui/len_zero.stderr index b6f13780253c2..396cfb75fb620 100644 --- a/tests/ui/len_zero.stderr +++ b/tests/ui/len_zero.stderr @@ -123,10 +123,22 @@ LL | if with_is_empty.len() == 0 { | ^^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `with_is_empty.is_empty()` error: length comparison to zero - --> $DIR/len_zero.rs:182:8 + --> $DIR/len_zero.rs:181:6 + | +LL | (has_is_empty.len() > 0).then(|| println!("This can happen.")); + | ^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()` + +error: length comparison to zero + --> $DIR/len_zero.rs:182:6 + | +LL | (has_is_empty.len() == 0).then(|| println!("Or this!")); + | ^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `has_is_empty.is_empty()` + +error: length comparison to zero + --> $DIR/len_zero.rs:186:8 | LL | if b.len() != 0 {} | ^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!b.is_empty()` -error: aborting due to 21 previous errors +error: aborting due to 23 previous errors diff --git a/tests/ui/len_zero_ranges.fixed b/tests/ui/len_zero_ranges.fixed index 7978176624274..4b1241ec86b44 100644 --- a/tests/ui/len_zero_ranges.fixed +++ b/tests/ui/len_zero_ranges.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::len_zero)] #![allow(unused)] diff --git a/tests/ui/len_zero_ranges.rs b/tests/ui/len_zero_ranges.rs index a0eb51cc9760c..4b47132c76618 100644 --- a/tests/ui/len_zero_ranges.rs +++ b/tests/ui/len_zero_ranges.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::len_zero)] #![allow(unused)] diff --git a/tests/ui/let_underscore_untyped.rs b/tests/ui/let_underscore_untyped.rs index bcb33c5c7e37e..8486137d3a662 100644 --- a/tests/ui/let_underscore_untyped.rs +++ b/tests/ui/let_underscore_untyped.rs @@ -28,6 +28,10 @@ fn f() -> Box { Box::new(1) } +fn g() -> impl Fn() { + || {} +} + fn main() { let _ = a(); let _ = b(1); @@ -35,6 +39,7 @@ fn main() { let _ = d(&1); let _ = e(); let _ = f(); + let _ = g(); _ = a(); _ = b(1); diff --git a/tests/ui/let_underscore_untyped.stderr b/tests/ui/let_underscore_untyped.stderr index 36c3d1214d6b3..47e76ea1d04e9 100644 --- a/tests/ui/let_underscore_untyped.stderr +++ b/tests/ui/let_underscore_untyped.stderr @@ -1,5 +1,5 @@ error: non-binding `let` without a type annotation - --> $DIR/let_underscore_untyped.rs:32:5 + --> $DIR/let_underscore_untyped.rs:36:5 | LL | let _ = a(); | ^^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | let _ = a(); = note: `-D clippy::let-underscore-untyped` implied by `-D warnings` error: non-binding `let` without a type annotation - --> $DIR/let_underscore_untyped.rs:33:5 + --> $DIR/let_underscore_untyped.rs:37:5 | LL | let _ = b(1); | ^^^^^^^^^^^^^ @@ -16,15 +16,7 @@ LL | let _ = b(1); = help: consider adding a type annotation or removing the `let` keyword error: non-binding `let` without a type annotation - --> $DIR/let_underscore_untyped.rs:34:5 - | -LL | let _ = c(); - | ^^^^^^^^^^^^ - | - = help: consider adding a type annotation or removing the `let` keyword - -error: non-binding `let` without a type annotation - --> $DIR/let_underscore_untyped.rs:35:5 + --> $DIR/let_underscore_untyped.rs:39:5 | LL | let _ = d(&1); | ^^^^^^^^^^^^^^ @@ -32,7 +24,7 @@ LL | let _ = d(&1); = help: consider adding a type annotation or removing the `let` keyword error: non-binding `let` without a type annotation - --> $DIR/let_underscore_untyped.rs:36:5 + --> $DIR/let_underscore_untyped.rs:40:5 | LL | let _ = e(); | ^^^^^^^^^^^^ @@ -40,12 +32,12 @@ LL | let _ = e(); = help: consider adding a type annotation or removing the `let` keyword error: non-binding `let` without a type annotation - --> $DIR/let_underscore_untyped.rs:37:5 + --> $DIR/let_underscore_untyped.rs:41:5 | LL | let _ = f(); | ^^^^^^^^^^^^ | = help: consider adding a type annotation or removing the `let` keyword -error: aborting due to 6 previous errors +error: aborting due to 5 previous errors diff --git a/tests/ui/let_unit.fixed b/tests/ui/let_unit.fixed index 76ff0645f4177..8ba89ec78bbde 100644 --- a/tests/ui/let_unit.fixed +++ b/tests/ui/let_unit.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(lint_reasons)] #![warn(clippy::let_unit_value)] diff --git a/tests/ui/let_unit.rs b/tests/ui/let_unit.rs index 895ccfe366a2d..7e8764a482a20 100644 --- a/tests/ui/let_unit.rs +++ b/tests/ui/let_unit.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(lint_reasons)] #![warn(clippy::let_unit_value)] diff --git a/tests/ui/lines_filter_map_ok.fixed b/tests/ui/lines_filter_map_ok.fixed index f4033cd8ed850..64114f6585d31 100644 --- a/tests/ui/lines_filter_map_ok.fixed +++ b/tests/ui/lines_filter_map_ok.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused, clippy::map_identity)] #![warn(clippy::lines_filter_map_ok)] diff --git a/tests/ui/lines_filter_map_ok.rs b/tests/ui/lines_filter_map_ok.rs index 7e11816b2acd3..5aedc68633607 100644 --- a/tests/ui/lines_filter_map_ok.rs +++ b/tests/ui/lines_filter_map_ok.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused, clippy::map_identity)] #![warn(clippy::lines_filter_map_ok)] diff --git a/tests/ui/lossy_float_literal.fixed b/tests/ui/lossy_float_literal.fixed index 24e372354fc05..a208857561030 100644 --- a/tests/ui/lossy_float_literal.fixed +++ b/tests/ui/lossy_float_literal.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::lossy_float_literal)] fn main() { diff --git a/tests/ui/lossy_float_literal.rs b/tests/ui/lossy_float_literal.rs index 3dcf98fa0bdda..1a75f214c856f 100644 --- a/tests/ui/lossy_float_literal.rs +++ b/tests/ui/lossy_float_literal.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::lossy_float_literal)] fn main() { diff --git a/tests/ui/macro_use_imports.fixed b/tests/ui/macro_use_imports.fixed index a395e4f5653f0..b4dabe3cae5d3 100644 --- a/tests/ui/macro_use_imports.fixed +++ b/tests/ui/macro_use_imports.fixed @@ -1,8 +1,8 @@ -// aux-build:macro_rules.rs -// aux-build:macro_use_helper.rs -// aux-build:proc_macro_derive.rs -// run-rustfix -// ignore-32bit +//@aux-build:macro_rules.rs +//@aux-build:macro_use_helper.rs +//@aux-build:proc_macro_derive.rs +//@run-rustfix +//@ignore-32bit #![feature(lint_reasons)] #![allow(unused_imports, unreachable_code, unused_variables, dead_code, unused_attributes)] diff --git a/tests/ui/macro_use_imports.rs b/tests/ui/macro_use_imports.rs index b1a2873329490..925a2c61f8d20 100644 --- a/tests/ui/macro_use_imports.rs +++ b/tests/ui/macro_use_imports.rs @@ -1,8 +1,8 @@ -// aux-build:macro_rules.rs -// aux-build:macro_use_helper.rs -// aux-build:proc_macro_derive.rs -// run-rustfix -// ignore-32bit +//@aux-build:macro_rules.rs +//@aux-build:macro_use_helper.rs +//@aux-build:proc_macro_derive.rs +//@run-rustfix +//@ignore-32bit #![feature(lint_reasons)] #![allow(unused_imports, unreachable_code, unused_variables, dead_code, unused_attributes)] diff --git a/tests/ui/macro_use_imports_expect.rs b/tests/ui/macro_use_imports_expect.rs index 5aac5af26db56..b9677851b92de 100644 --- a/tests/ui/macro_use_imports_expect.rs +++ b/tests/ui/macro_use_imports_expect.rs @@ -1,7 +1,7 @@ -// aux-build:macro_rules.rs -// aux-build:macro_use_helper.rs -// aux-build:proc_macro_derive.rs -// ignore-32bit +//@aux-build:macro_rules.rs +//@aux-build:macro_use_helper.rs +//@aux-build:proc_macro_derive.rs +//@ignore-32bit #![feature(lint_reasons)] #![allow(unused_imports, unreachable_code, unused_variables, dead_code, unused_attributes)] diff --git a/tests/ui/manual_assert.edition2018.fixed b/tests/ui/manual_assert.edition2018.fixed index 8c7e919bf62a1..ab9b375dc03d5 100644 --- a/tests/ui/manual_assert.edition2018.fixed +++ b/tests/ui/manual_assert.edition2018.fixed @@ -1,7 +1,7 @@ -// revisions: edition2018 edition2021 -//[edition2018] edition:2018 -//[edition2021] edition:2021 -// run-rustfix +//@revisions: edition2018 edition2021 +//@[edition2018] edition:2018 +//@[edition2021] edition:2021 +//@run-rustfix #![warn(clippy::manual_assert)] #![allow(dead_code, unused_doc_comments)] diff --git a/tests/ui/manual_assert.edition2021.fixed b/tests/ui/manual_assert.edition2021.fixed index 8c7e919bf62a1..ab9b375dc03d5 100644 --- a/tests/ui/manual_assert.edition2021.fixed +++ b/tests/ui/manual_assert.edition2021.fixed @@ -1,7 +1,7 @@ -// revisions: edition2018 edition2021 -//[edition2018] edition:2018 -//[edition2021] edition:2021 -// run-rustfix +//@revisions: edition2018 edition2021 +//@[edition2018] edition:2018 +//@[edition2021] edition:2021 +//@run-rustfix #![warn(clippy::manual_assert)] #![allow(dead_code, unused_doc_comments)] diff --git a/tests/ui/manual_assert.rs b/tests/ui/manual_assert.rs index f037c5b8405c7..eac52d1b5de57 100644 --- a/tests/ui/manual_assert.rs +++ b/tests/ui/manual_assert.rs @@ -1,7 +1,7 @@ -// revisions: edition2018 edition2021 -//[edition2018] edition:2018 -//[edition2021] edition:2021 -// run-rustfix +//@revisions: edition2018 edition2021 +//@[edition2018] edition:2018 +//@[edition2021] edition:2021 +//@run-rustfix #![warn(clippy::manual_assert)] #![allow(dead_code, unused_doc_comments)] diff --git a/tests/ui/manual_async_fn.fixed b/tests/ui/manual_async_fn.fixed index 5cc4a43af7e36..e458f0d254f66 100644 --- a/tests/ui/manual_async_fn.fixed +++ b/tests/ui/manual_async_fn.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::manual_async_fn)] #![allow(unused)] diff --git a/tests/ui/manual_async_fn.rs b/tests/ui/manual_async_fn.rs index ba504b8a8231f..dd5ca1c9b5b7e 100644 --- a/tests/ui/manual_async_fn.rs +++ b/tests/ui/manual_async_fn.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::manual_async_fn)] #![allow(unused)] diff --git a/tests/ui/manual_bits.fixed b/tests/ui/manual_bits.fixed index e7f8cd878ca78..037de0262e2f2 100644 --- a/tests/ui/manual_bits.fixed +++ b/tests/ui/manual_bits.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::manual_bits)] #![allow( diff --git a/tests/ui/manual_bits.rs b/tests/ui/manual_bits.rs index 7b1d15495287a..b15a531ec1751 100644 --- a/tests/ui/manual_bits.rs +++ b/tests/ui/manual_bits.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::manual_bits)] #![allow( diff --git a/tests/ui/manual_filter.fixed b/tests/ui/manual_filter.fixed index ef6780dc96d9c..755caa664d59a 100644 --- a/tests/ui/manual_filter.fixed +++ b/tests/ui/manual_filter.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::manual_filter)] #![allow(unused_variables, dead_code)] diff --git a/tests/ui/manual_filter.rs b/tests/ui/manual_filter.rs index ea0ce83172b7d..faccfe9db12a6 100644 --- a/tests/ui/manual_filter.rs +++ b/tests/ui/manual_filter.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::manual_filter)] #![allow(unused_variables, dead_code)] diff --git a/tests/ui/manual_filter_map.fixed b/tests/ui/manual_filter_map.fixed index 4936dc9b2e017..831323089e7f2 100644 --- a/tests/ui/manual_filter_map.fixed +++ b/tests/ui/manual_filter_map.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code)] #![warn(clippy::manual_filter_map)] #![allow(clippy::redundant_closure)] // FIXME suggestion may have redundant closure diff --git a/tests/ui/manual_filter_map.rs b/tests/ui/manual_filter_map.rs index 8c67e827b4c35..2692303d31382 100644 --- a/tests/ui/manual_filter_map.rs +++ b/tests/ui/manual_filter_map.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code)] #![warn(clippy::manual_filter_map)] #![allow(clippy::redundant_closure)] // FIXME suggestion may have redundant closure diff --git a/tests/ui/manual_find_fixable.fixed b/tests/ui/manual_find_fixable.fixed index 2bce6e624c90d..9c5eb20c81cb0 100644 --- a/tests/ui/manual_find_fixable.fixed +++ b/tests/ui/manual_find_fixable.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::manual_find)] #![allow(unused)] #![allow(clippy::needless_return, clippy::uninlined_format_args)] diff --git a/tests/ui/manual_find_fixable.rs b/tests/ui/manual_find_fixable.rs index f5c6de37a257f..7b670320ee336 100644 --- a/tests/ui/manual_find_fixable.rs +++ b/tests/ui/manual_find_fixable.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::manual_find)] #![allow(unused)] #![allow(clippy::needless_return, clippy::uninlined_format_args)] diff --git a/tests/ui/manual_find_map.fixed b/tests/ui/manual_find_map.fixed index 54302beceff62..554613a30a9ea 100644 --- a/tests/ui/manual_find_map.fixed +++ b/tests/ui/manual_find_map.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code)] #![warn(clippy::manual_find_map)] #![allow(clippy::redundant_closure)] // FIXME suggestion may have redundant closure diff --git a/tests/ui/manual_find_map.rs b/tests/ui/manual_find_map.rs index afcc1825a9ac1..d6245758f9d09 100644 --- a/tests/ui/manual_find_map.rs +++ b/tests/ui/manual_find_map.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code)] #![warn(clippy::manual_find_map)] #![allow(clippy::redundant_closure)] // FIXME suggestion may have redundant closure diff --git a/tests/ui/manual_instant_elapsed.fixed b/tests/ui/manual_instant_elapsed.fixed index 85a91543c893a..55073c3b57cf9 100644 --- a/tests/ui/manual_instant_elapsed.fixed +++ b/tests/ui/manual_instant_elapsed.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::manual_instant_elapsed)] #![allow(clippy::unnecessary_operation)] #![allow(clippy::unchecked_duration_subtraction)] diff --git a/tests/ui/manual_instant_elapsed.rs b/tests/ui/manual_instant_elapsed.rs index c98cb15b91649..c9029a049408f 100644 --- a/tests/ui/manual_instant_elapsed.rs +++ b/tests/ui/manual_instant_elapsed.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::manual_instant_elapsed)] #![allow(clippy::unnecessary_operation)] #![allow(clippy::unchecked_duration_subtraction)] diff --git a/tests/ui/manual_is_ascii_check.fixed b/tests/ui/manual_is_ascii_check.fixed index 5b2b44c2fdb2b..87e866586683b 100644 --- a/tests/ui/manual_is_ascii_check.fixed +++ b/tests/ui/manual_is_ascii_check.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused, dead_code)] #![warn(clippy::manual_is_ascii_check)] diff --git a/tests/ui/manual_is_ascii_check.rs b/tests/ui/manual_is_ascii_check.rs index c9433f33a1b6f..931f0f20276bb 100644 --- a/tests/ui/manual_is_ascii_check.rs +++ b/tests/ui/manual_is_ascii_check.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused, dead_code)] #![warn(clippy::manual_is_ascii_check)] diff --git a/tests/ui/manual_main_separator_str.fixed b/tests/ui/manual_main_separator_str.fixed index 50f46d6b35500..7e7da8f20bb3e 100644 --- a/tests/ui/manual_main_separator_str.fixed +++ b/tests/ui/manual_main_separator_str.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] #![warn(clippy::manual_main_separator_str)] diff --git a/tests/ui/manual_main_separator_str.rs b/tests/ui/manual_main_separator_str.rs index 2dbb9e66151d4..cf90e12efc33a 100644 --- a/tests/ui/manual_main_separator_str.rs +++ b/tests/ui/manual_main_separator_str.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] #![warn(clippy::manual_main_separator_str)] diff --git a/tests/ui/manual_map_option.fixed b/tests/ui/manual_map_option.fixed index e12ea7ec14500..e8ff65cad6aa5 100644 --- a/tests/ui/manual_map_option.fixed +++ b/tests/ui/manual_map_option.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::manual_map)] #![allow( diff --git a/tests/ui/manual_map_option.rs b/tests/ui/manual_map_option.rs index 325a6db06c4e5..b06a96451ce75 100644 --- a/tests/ui/manual_map_option.rs +++ b/tests/ui/manual_map_option.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::manual_map)] #![allow( diff --git a/tests/ui/manual_map_option_2.fixed b/tests/ui/manual_map_option_2.fixed index ebf3f8cabd470..dc72287824874 100644 --- a/tests/ui/manual_map_option_2.fixed +++ b/tests/ui/manual_map_option_2.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::manual_map)] #![allow(clippy::toplevel_ref_arg)] diff --git a/tests/ui/manual_map_option_2.rs b/tests/ui/manual_map_option_2.rs index 1382d9af0aa08..c495ab0fa6e0e 100644 --- a/tests/ui/manual_map_option_2.rs +++ b/tests/ui/manual_map_option_2.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::manual_map)] #![allow(clippy::toplevel_ref_arg)] diff --git a/tests/ui/manual_ok_or.fixed b/tests/ui/manual_ok_or.fixed index fc8511626b3d1..d8901dc3b037a 100644 --- a/tests/ui/manual_ok_or.fixed +++ b/tests/ui/manual_ok_or.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::manual_ok_or)] #![allow(clippy::or_fun_call)] #![allow(clippy::disallowed_names)] diff --git a/tests/ui/manual_ok_or.rs b/tests/ui/manual_ok_or.rs index b5303d33f5fd1..7188a521357ec 100644 --- a/tests/ui/manual_ok_or.rs +++ b/tests/ui/manual_ok_or.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::manual_ok_or)] #![allow(clippy::or_fun_call)] #![allow(clippy::disallowed_names)] diff --git a/tests/ui/manual_rem_euclid.fixed b/tests/ui/manual_rem_euclid.fixed index 1f6df1b0a8654..f2e44e56f0205 100644 --- a/tests/ui/manual_rem_euclid.fixed +++ b/tests/ui/manual_rem_euclid.fixed @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:proc_macros.rs +//@run-rustfix +//@aux-build:proc_macros.rs #![warn(clippy::manual_rem_euclid)] #![allow(clippy::let_with_type_underscore)] diff --git a/tests/ui/manual_rem_euclid.rs b/tests/ui/manual_rem_euclid.rs index b275e8a38d21e..b2329c33a47d5 100644 --- a/tests/ui/manual_rem_euclid.rs +++ b/tests/ui/manual_rem_euclid.rs @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:proc_macros.rs +//@run-rustfix +//@aux-build:proc_macros.rs #![warn(clippy::manual_rem_euclid)] #![allow(clippy::let_with_type_underscore)] diff --git a/tests/ui/manual_retain.fixed b/tests/ui/manual_retain.fixed index 8f25fea678f19..d3cac6667630e 100644 --- a/tests/ui/manual_retain.fixed +++ b/tests/ui/manual_retain.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::manual_retain)] #![allow(unused, clippy::redundant_clone)] use std::collections::BTreeMap; diff --git a/tests/ui/manual_retain.rs b/tests/ui/manual_retain.rs index e6b3995a689b3..34f0c4d5029eb 100644 --- a/tests/ui/manual_retain.rs +++ b/tests/ui/manual_retain.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::manual_retain)] #![allow(unused, clippy::redundant_clone)] use std::collections::BTreeMap; diff --git a/tests/ui/manual_saturating_arithmetic.fixed b/tests/ui/manual_saturating_arithmetic.fixed index c4f53c446c9f7..7dd4521fa78ef 100644 --- a/tests/ui/manual_saturating_arithmetic.fixed +++ b/tests/ui/manual_saturating_arithmetic.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused_imports)] diff --git a/tests/ui/manual_saturating_arithmetic.rs b/tests/ui/manual_saturating_arithmetic.rs index cd83cf6e65e94..463ee0692899b 100644 --- a/tests/ui/manual_saturating_arithmetic.rs +++ b/tests/ui/manual_saturating_arithmetic.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused_imports)] diff --git a/tests/ui/manual_slice_size_calculation.fixed b/tests/ui/manual_slice_size_calculation.fixed new file mode 100644 index 0000000000000..ac85bd8d3acac --- /dev/null +++ b/tests/ui/manual_slice_size_calculation.fixed @@ -0,0 +1,46 @@ +//@run-rustfix +//@aux-build:proc_macros.rs +#![allow(unused)] +#![warn(clippy::manual_slice_size_calculation)] + +extern crate proc_macros; + +use core::mem::{align_of, size_of}; +use proc_macros::external; + +fn main() { + let v_i32 = Vec::::new(); + let s_i32 = v_i32.as_slice(); + + // True positives: + let _ = std::mem::size_of_val(s_i32); // WARNING + let _ = std::mem::size_of_val(s_i32); // WARNING + let _ = std::mem::size_of_val(s_i32) * 5; // WARNING + + let len = s_i32.len(); + let size = size_of::(); + let _ = std::mem::size_of_val(s_i32); // WARNING + let _ = std::mem::size_of_val(s_i32); // WARNING + let _ = std::mem::size_of_val(s_i32); // WARNING + + let _ = std::mem::size_of_val(external!(&[1u64][..])); + + // True negatives: + let _ = size_of::() + s_i32.len(); // Ok, not a multiplication + let _ = size_of::() * s_i32.partition_point(|_| true); // Ok, not len() + let _ = size_of::() * v_i32.len(); // Ok, not a slice + let _ = align_of::() * s_i32.len(); // Ok, not size_of() + let _ = size_of::() * s_i32.len(); // Ok, different types + + let _ = external!($s_i32.len() * size_of::()); + let _ = external!($s_i32.len()) * size_of::(); + + // False negatives: + let _ = 5 * size_of::() * s_i32.len(); // Ok (MISSED OPPORTUNITY) + let _ = size_of::() * 5 * s_i32.len(); // Ok (MISSED OPPORTUNITY) +} + +const fn _const(s_i32: &[i32]) { + // True negative: + let _ = s_i32.len() * size_of::(); // Ok, can't use size_of_val in const +} diff --git a/tests/ui/manual_slice_size_calculation.rs b/tests/ui/manual_slice_size_calculation.rs index 5082f931f3c2b..1f824b12bc263 100644 --- a/tests/ui/manual_slice_size_calculation.rs +++ b/tests/ui/manual_slice_size_calculation.rs @@ -1,7 +1,12 @@ +//@run-rustfix +//@aux-build:proc_macros.rs #![allow(unused)] #![warn(clippy::manual_slice_size_calculation)] +extern crate proc_macros; + use core::mem::{align_of, size_of}; +use proc_macros::external; fn main() { let v_i32 = Vec::::new(); @@ -18,6 +23,8 @@ fn main() { let _ = s_i32.len() * size; // WARNING let _ = len * size; // WARNING + let _ = external!(&[1u64][..]).len() * size_of::(); + // True negatives: let _ = size_of::() + s_i32.len(); // Ok, not a multiplication let _ = size_of::() * s_i32.partition_point(|_| true); // Ok, not len() @@ -25,6 +32,9 @@ fn main() { let _ = align_of::() * s_i32.len(); // Ok, not size_of() let _ = size_of::() * s_i32.len(); // Ok, different types + let _ = external!($s_i32.len() * size_of::()); + let _ = external!($s_i32.len()) * size_of::(); + // False negatives: let _ = 5 * size_of::() * s_i32.len(); // Ok (MISSED OPPORTUNITY) let _ = size_of::() * 5 * s_i32.len(); // Ok (MISSED OPPORTUNITY) diff --git a/tests/ui/manual_slice_size_calculation.stderr b/tests/ui/manual_slice_size_calculation.stderr index 4a24fc60a0faf..e09d8057a3b98 100644 --- a/tests/ui/manual_slice_size_calculation.stderr +++ b/tests/ui/manual_slice_size_calculation.stderr @@ -1,51 +1,46 @@ error: manual slice size calculation - --> $DIR/manual_slice_size_calculation.rs:11:13 + --> $DIR/manual_slice_size_calculation.rs:16:13 | LL | let _ = s_i32.len() * size_of::(); // WARNING - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::mem::size_of_val(s_i32)` | - = help: consider using std::mem::size_of_value instead = note: `-D clippy::manual-slice-size-calculation` implied by `-D warnings` error: manual slice size calculation - --> $DIR/manual_slice_size_calculation.rs:12:13 + --> $DIR/manual_slice_size_calculation.rs:17:13 | LL | let _ = size_of::() * s_i32.len(); // WARNING - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: consider using std::mem::size_of_value instead + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::mem::size_of_val(s_i32)` error: manual slice size calculation - --> $DIR/manual_slice_size_calculation.rs:13:13 + --> $DIR/manual_slice_size_calculation.rs:18:13 | LL | let _ = size_of::() * s_i32.len() * 5; // WARNING - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: consider using std::mem::size_of_value instead + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::mem::size_of_val(s_i32)` error: manual slice size calculation - --> $DIR/manual_slice_size_calculation.rs:17:13 + --> $DIR/manual_slice_size_calculation.rs:22:13 | LL | let _ = len * size_of::(); // WARNING - | ^^^^^^^^^^^^^^^^^^^^^^ - | - = help: consider using std::mem::size_of_value instead + | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::mem::size_of_val(s_i32)` error: manual slice size calculation - --> $DIR/manual_slice_size_calculation.rs:18:13 + --> $DIR/manual_slice_size_calculation.rs:23:13 | LL | let _ = s_i32.len() * size; // WARNING - | ^^^^^^^^^^^^^^^^^^ - | - = help: consider using std::mem::size_of_value instead + | ^^^^^^^^^^^^^^^^^^ help: try: `std::mem::size_of_val(s_i32)` error: manual slice size calculation - --> $DIR/manual_slice_size_calculation.rs:19:13 + --> $DIR/manual_slice_size_calculation.rs:24:13 | LL | let _ = len * size; // WARNING - | ^^^^^^^^^^ + | ^^^^^^^^^^ help: try: `std::mem::size_of_val(s_i32)` + +error: manual slice size calculation + --> $DIR/manual_slice_size_calculation.rs:26:13 | - = help: consider using std::mem::size_of_value instead +LL | let _ = external!(&[1u64][..]).len() * size_of::(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::mem::size_of_val(external!(&[1u64][..]))` -error: aborting due to 6 previous errors +error: aborting due to 7 previous errors diff --git a/tests/ui/manual_split_once.fixed b/tests/ui/manual_split_once.fixed index 50b02019cc274..e317c597109b0 100644 --- a/tests/ui/manual_split_once.fixed +++ b/tests/ui/manual_split_once.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::manual_split_once)] #![allow(unused, clippy::iter_skip_next, clippy::iter_nth_zero)] diff --git a/tests/ui/manual_split_once.rs b/tests/ui/manual_split_once.rs index e1e8b71a9deff..7e2dc22bc4669 100644 --- a/tests/ui/manual_split_once.rs +++ b/tests/ui/manual_split_once.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::manual_split_once)] #![allow(unused, clippy::iter_skip_next, clippy::iter_nth_zero)] diff --git a/tests/ui/manual_str_repeat.fixed b/tests/ui/manual_str_repeat.fixed index 3d56f2a0dedb2..9468c3df9047a 100644 --- a/tests/ui/manual_str_repeat.fixed +++ b/tests/ui/manual_str_repeat.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::manual_str_repeat)] diff --git a/tests/ui/manual_str_repeat.rs b/tests/ui/manual_str_repeat.rs index e8240a949dbc2..baa0a10260d40 100644 --- a/tests/ui/manual_str_repeat.rs +++ b/tests/ui/manual_str_repeat.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::manual_str_repeat)] diff --git a/tests/ui/manual_string_new.fixed b/tests/ui/manual_string_new.fixed index a376411bfbc80..0d1bab2330464 100644 --- a/tests/ui/manual_string_new.fixed +++ b/tests/ui/manual_string_new.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::manual_string_new)] diff --git a/tests/ui/manual_string_new.rs b/tests/ui/manual_string_new.rs index 6bfc52fb1bce3..2392ebfc32292 100644 --- a/tests/ui/manual_string_new.rs +++ b/tests/ui/manual_string_new.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::manual_string_new)] diff --git a/tests/ui/manual_unwrap_or.fixed b/tests/ui/manual_unwrap_or.fixed index 7d68978216c9c..c17634bffe303 100644 --- a/tests/ui/manual_unwrap_or.fixed +++ b/tests/ui/manual_unwrap_or.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code)] #![allow(unused_variables, clippy::unnecessary_wraps)] diff --git a/tests/ui/manual_unwrap_or.rs b/tests/ui/manual_unwrap_or.rs index b937fe6f977e5..6d49a6949fa98 100644 --- a/tests/ui/manual_unwrap_or.rs +++ b/tests/ui/manual_unwrap_or.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code)] #![allow(unused_variables, clippy::unnecessary_wraps)] diff --git a/tests/ui/map_clone.fixed b/tests/ui/map_clone.fixed index 0860dcf8e0ddb..d7474f3571912 100644 --- a/tests/ui/map_clone.fixed +++ b/tests/ui/map_clone.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::map_clone)] #![allow( clippy::clone_on_copy, diff --git a/tests/ui/map_clone.rs b/tests/ui/map_clone.rs index b6987336834b8..74978ae8006d7 100644 --- a/tests/ui/map_clone.rs +++ b/tests/ui/map_clone.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::map_clone)] #![allow( clippy::clone_on_copy, diff --git a/tests/ui/map_collect_result_unit.fixed b/tests/ui/map_collect_result_unit.fixed index e66c9cc24207a..b00c2cf284ec9 100644 --- a/tests/ui/map_collect_result_unit.fixed +++ b/tests/ui/map_collect_result_unit.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::map_collect_result_unit)] fn main() { diff --git a/tests/ui/map_collect_result_unit.rs b/tests/ui/map_collect_result_unit.rs index 6f08f4c3c5354..ad2198ec1fe75 100644 --- a/tests/ui/map_collect_result_unit.rs +++ b/tests/ui/map_collect_result_unit.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::map_collect_result_unit)] fn main() { diff --git a/tests/ui/map_flatten_fixable.fixed b/tests/ui/map_flatten_fixable.fixed index 8e2f11389f898..14816de1a636b 100644 --- a/tests/ui/map_flatten_fixable.fixed +++ b/tests/ui/map_flatten_fixable.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::all, clippy::pedantic)] #![allow(clippy::let_underscore_untyped)] diff --git a/tests/ui/map_flatten_fixable.rs b/tests/ui/map_flatten_fixable.rs index a783a99c4ffd3..f38a00a59facf 100644 --- a/tests/ui/map_flatten_fixable.rs +++ b/tests/ui/map_flatten_fixable.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::all, clippy::pedantic)] #![allow(clippy::let_underscore_untyped)] diff --git a/tests/ui/map_identity.fixed b/tests/ui/map_identity.fixed index 2256e51f2d09c..7fb7d8c121885 100644 --- a/tests/ui/map_identity.fixed +++ b/tests/ui/map_identity.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::map_identity)] #![allow(clippy::needless_return)] diff --git a/tests/ui/map_identity.rs b/tests/ui/map_identity.rs index ccfdc9ea76d52..7891c24262838 100644 --- a/tests/ui/map_identity.rs +++ b/tests/ui/map_identity.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::map_identity)] #![allow(clippy::needless_return)] diff --git a/tests/ui/map_unwrap_or.rs b/tests/ui/map_unwrap_or.rs index 32631024ca5dc..cb25d8567aa01 100644 --- a/tests/ui/map_unwrap_or.rs +++ b/tests/ui/map_unwrap_or.rs @@ -1,4 +1,4 @@ -// aux-build:option_helpers.rs +//@aux-build:option_helpers.rs #![warn(clippy::map_unwrap_or)] #![allow(clippy::uninlined_format_args, clippy::unnecessary_lazy_evaluations)] diff --git a/tests/ui/map_unwrap_or_fixable.fixed b/tests/ui/map_unwrap_or_fixable.fixed index bd5b4f7165a4e..ea5b6a6691e58 100644 --- a/tests/ui/map_unwrap_or_fixable.fixed +++ b/tests/ui/map_unwrap_or_fixable.fixed @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:option_helpers.rs +//@run-rustfix +//@aux-build:option_helpers.rs #![warn(clippy::map_unwrap_or)] diff --git a/tests/ui/map_unwrap_or_fixable.rs b/tests/ui/map_unwrap_or_fixable.rs index 0b892caf20e82..f8bb9d8ca6a35 100644 --- a/tests/ui/map_unwrap_or_fixable.rs +++ b/tests/ui/map_unwrap_or_fixable.rs @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:option_helpers.rs +//@run-rustfix +//@aux-build:option_helpers.rs #![warn(clippy::map_unwrap_or)] diff --git a/tests/ui/match_as_ref.fixed b/tests/ui/match_as_ref.fixed index ddfa1e741ada4..8fa3f5325871d 100644 --- a/tests/ui/match_as_ref.fixed +++ b/tests/ui/match_as_ref.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] #![warn(clippy::match_as_ref)] diff --git a/tests/ui/match_as_ref.rs b/tests/ui/match_as_ref.rs index 025d475ae13db..02a17791426cf 100644 --- a/tests/ui/match_as_ref.rs +++ b/tests/ui/match_as_ref.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] #![warn(clippy::match_as_ref)] diff --git a/tests/ui/match_expr_like_matches_macro.fixed b/tests/ui/match_expr_like_matches_macro.fixed index 55cd15bd5c385..7215660da67f1 100644 --- a/tests/ui/match_expr_like_matches_macro.fixed +++ b/tests/ui/match_expr_like_matches_macro.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::match_like_matches_macro)] #![allow( diff --git a/tests/ui/match_expr_like_matches_macro.rs b/tests/ui/match_expr_like_matches_macro.rs index 5d645e108e511..afdf1069f5e4a 100644 --- a/tests/ui/match_expr_like_matches_macro.rs +++ b/tests/ui/match_expr_like_matches_macro.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::match_like_matches_macro)] #![allow( diff --git a/tests/ui/match_ref_pats.fixed b/tests/ui/match_ref_pats.fixed index cf37fc6dc90a1..50c3dcc1e0a82 100644 --- a/tests/ui/match_ref_pats.fixed +++ b/tests/ui/match_ref_pats.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::match_ref_pats)] #![allow(dead_code, unused_variables)] #![allow(clippy::enum_variant_names, clippy::equatable_if_let, clippy::uninlined_format_args)] diff --git a/tests/ui/match_ref_pats.rs b/tests/ui/match_ref_pats.rs index 3220b97d1b511..d29ddacc04ad3 100644 --- a/tests/ui/match_ref_pats.rs +++ b/tests/ui/match_ref_pats.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::match_ref_pats)] #![allow(dead_code, unused_variables)] #![allow(clippy::enum_variant_names, clippy::equatable_if_let, clippy::uninlined_format_args)] diff --git a/tests/ui/match_result_ok.fixed b/tests/ui/match_result_ok.fixed index 10ae1ee5245eb..fe67b225fa176 100644 --- a/tests/ui/match_result_ok.fixed +++ b/tests/ui/match_result_ok.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::match_result_ok)] #![allow(dead_code)] #![allow(clippy::boxed_local, clippy::uninlined_format_args)] diff --git a/tests/ui/match_result_ok.rs b/tests/ui/match_result_ok.rs index bc2c4b50e2729..eac382e1f623a 100644 --- a/tests/ui/match_result_ok.rs +++ b/tests/ui/match_result_ok.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::match_result_ok)] #![allow(dead_code)] #![allow(clippy::boxed_local, clippy::uninlined_format_args)] diff --git a/tests/ui/match_single_binding.fixed b/tests/ui/match_single_binding.fixed index 201301cc9b737..7c29bb08e64da 100644 --- a/tests/ui/match_single_binding.fixed +++ b/tests/ui/match_single_binding.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::match_single_binding)] #![allow( unused, diff --git a/tests/ui/match_single_binding.rs b/tests/ui/match_single_binding.rs index 8b047b19ce968..c068d5e17c33d 100644 --- a/tests/ui/match_single_binding.rs +++ b/tests/ui/match_single_binding.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::match_single_binding)] #![allow( unused, diff --git a/tests/ui/match_single_binding2.fixed b/tests/ui/match_single_binding2.fixed index e3cf56a4293cc..adfb4ba91f743 100644 --- a/tests/ui/match_single_binding2.fixed +++ b/tests/ui/match_single_binding2.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::match_single_binding)] #![allow(unused_variables)] #![allow(clippy::uninlined_format_args)] diff --git a/tests/ui/match_single_binding2.rs b/tests/ui/match_single_binding2.rs index 5a4bb8441fffc..b5cfe3654a58d 100644 --- a/tests/ui/match_single_binding2.rs +++ b/tests/ui/match_single_binding2.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::match_single_binding)] #![allow(unused_variables)] #![allow(clippy::uninlined_format_args)] diff --git a/tests/ui/match_str_case_mismatch.fixed b/tests/ui/match_str_case_mismatch.fixed index e436bcf495fd2..cd53b1f06faa7 100644 --- a/tests/ui/match_str_case_mismatch.fixed +++ b/tests/ui/match_str_case_mismatch.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::match_str_case_mismatch)] #![allow(dead_code)] diff --git a/tests/ui/match_str_case_mismatch.rs b/tests/ui/match_str_case_mismatch.rs index 92e2a000ade25..6885305662a25 100644 --- a/tests/ui/match_str_case_mismatch.rs +++ b/tests/ui/match_str_case_mismatch.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::match_str_case_mismatch)] #![allow(dead_code)] diff --git a/tests/ui/match_wildcard_for_single_variants.fixed b/tests/ui/match_wildcard_for_single_variants.fixed index 9fd3739b69c2c..d2e6fef07594a 100644 --- a/tests/ui/match_wildcard_for_single_variants.fixed +++ b/tests/ui/match_wildcard_for_single_variants.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::match_wildcard_for_single_variants)] #![allow(dead_code)] diff --git a/tests/ui/match_wildcard_for_single_variants.rs b/tests/ui/match_wildcard_for_single_variants.rs index 9a5c849e6ec9a..cff0c89606500 100644 --- a/tests/ui/match_wildcard_for_single_variants.rs +++ b/tests/ui/match_wildcard_for_single_variants.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::match_wildcard_for_single_variants)] #![allow(dead_code)] diff --git a/tests/ui/mem_replace.fixed b/tests/ui/mem_replace.fixed index 7fd340173af9e..d37e97b0a0608 100644 --- a/tests/ui/mem_replace.fixed +++ b/tests/ui/mem_replace.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] #![warn( diff --git a/tests/ui/mem_replace.rs b/tests/ui/mem_replace.rs index fa2903addbc03..34e37f3dbbbdb 100644 --- a/tests/ui/mem_replace.rs +++ b/tests/ui/mem_replace.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] #![warn( diff --git a/tests/ui/mem_replace_macro.rs b/tests/ui/mem_replace_macro.rs index 3932e7d00c19d..132873858b7c5 100644 --- a/tests/ui/mem_replace_macro.rs +++ b/tests/ui/mem_replace_macro.rs @@ -1,4 +1,4 @@ -// aux-build:proc_macros.rs +//@aux-build:proc_macros.rs #![warn(clippy::mem_replace_with_default)] extern crate proc_macros; diff --git a/tests/ui/methods.rs b/tests/ui/methods.rs index 1519e4da9348a..e0e2cac30a286 100644 --- a/tests/ui/methods.rs +++ b/tests/ui/methods.rs @@ -1,4 +1,4 @@ -// aux-build:option_helpers.rs +//@aux-build:option_helpers.rs #![warn(clippy::all, clippy::pedantic)] #![allow( diff --git a/tests/ui/methods_fixable.fixed b/tests/ui/methods_fixable.fixed index ee7c1b0da6d97..dcbed5a4d997f 100644 --- a/tests/ui/methods_fixable.fixed +++ b/tests/ui/methods_fixable.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::filter_next)] diff --git a/tests/ui/methods_fixable.rs b/tests/ui/methods_fixable.rs index 6d0f1b7bd5147..3a976d235276a 100644 --- a/tests/ui/methods_fixable.rs +++ b/tests/ui/methods_fixable.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::filter_next)] diff --git a/tests/ui/mismatched_target_os_non_unix.fixed b/tests/ui/mismatched_target_os_non_unix.fixed index f219a570e7fcc..f58e9a429b623 100644 --- a/tests/ui/mismatched_target_os_non_unix.fixed +++ b/tests/ui/mismatched_target_os_non_unix.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::mismatched_target_os)] #![allow(unused)] diff --git a/tests/ui/mismatched_target_os_non_unix.rs b/tests/ui/mismatched_target_os_non_unix.rs index 8a8ae756a4fcf..e00224f5ceb40 100644 --- a/tests/ui/mismatched_target_os_non_unix.rs +++ b/tests/ui/mismatched_target_os_non_unix.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::mismatched_target_os)] #![allow(unused)] diff --git a/tests/ui/mismatched_target_os_unix.fixed b/tests/ui/mismatched_target_os_unix.fixed index 7d9d406d99dfc..330587a3c4c3e 100644 --- a/tests/ui/mismatched_target_os_unix.fixed +++ b/tests/ui/mismatched_target_os_unix.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::mismatched_target_os)] #![allow(unused)] diff --git a/tests/ui/mismatched_target_os_unix.rs b/tests/ui/mismatched_target_os_unix.rs index c1177f1eedc62..5a90019a2e4c3 100644 --- a/tests/ui/mismatched_target_os_unix.rs +++ b/tests/ui/mismatched_target_os_unix.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::mismatched_target_os)] #![allow(unused)] 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 e6f88c6e622cb..5db73a7b8ead4 100644 --- a/tests/ui/missing_const_for_fn/cant_be_const.rs +++ b/tests/ui/missing_const_for_fn/cant_be_const.rs @@ -2,8 +2,8 @@ //! compilation error. //! The .stderr output of this test should be empty. Otherwise it's a bug somewhere. -// aux-build:helper.rs -// aux-build:../../auxiliary/proc_macros.rs +//@aux-build:helper.rs +//@aux-build:../../auxiliary/proc_macros.rs #![warn(clippy::missing_const_for_fn)] #![feature(start)] diff --git a/tests/ui/missing_doc.rs b/tests/ui/missing_doc.rs index 5752048949ca4..bf587e774f743 100644 --- a/tests/ui/missing_doc.rs +++ b/tests/ui/missing_doc.rs @@ -1,5 +1,5 @@ -// needs-asm-support -// aux-build: proc_macros.rs +//@needs-asm-support +//@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 diff --git a/tests/ui/missing_doc_impl.rs b/tests/ui/missing_doc_impl.rs index e2d49b0907d57..520ddbe16b829 100644 --- a/tests/ui/missing_doc_impl.rs +++ b/tests/ui/missing_doc_impl.rs @@ -1,4 +1,4 @@ -// aux-build: proc_macros.rs +//@aux-build: proc_macros.rs #![warn(clippy::missing_docs_in_private_items)] #![allow(dead_code)] diff --git a/tests/ui/missing_spin_loop.fixed b/tests/ui/missing_spin_loop.fixed index aa89e04d26eb2..a15298dc37b25 100644 --- a/tests/ui/missing_spin_loop.fixed +++ b/tests/ui/missing_spin_loop.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::missing_spin_loop)] #![allow(clippy::bool_comparison)] #![allow(unused_braces)] diff --git a/tests/ui/missing_spin_loop.rs b/tests/ui/missing_spin_loop.rs index 88745e4773248..be74581ecd03b 100644 --- a/tests/ui/missing_spin_loop.rs +++ b/tests/ui/missing_spin_loop.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::missing_spin_loop)] #![allow(clippy::bool_comparison)] #![allow(unused_braces)] diff --git a/tests/ui/missing_spin_loop_no_std.fixed b/tests/ui/missing_spin_loop_no_std.fixed index bb4b4795516ec..960e5c05fb63d 100644 --- a/tests/ui/missing_spin_loop_no_std.fixed +++ b/tests/ui/missing_spin_loop_no_std.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::missing_spin_loop)] #![feature(lang_items, start, libc)] #![no_std] diff --git a/tests/ui/missing_spin_loop_no_std.rs b/tests/ui/missing_spin_loop_no_std.rs index a19bc72baf8d1..e532ca62dc533 100644 --- a/tests/ui/missing_spin_loop_no_std.rs +++ b/tests/ui/missing_spin_loop_no_std.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::missing_spin_loop)] #![feature(lang_items, start, libc)] #![no_std] diff --git a/tests/ui/mistyped_literal_suffix.fixed b/tests/ui/mistyped_literal_suffix.fixed index 9a47d7c56ed1e..62cfeafdc49fb 100644 --- a/tests/ui/mistyped_literal_suffix.fixed +++ b/tests/ui/mistyped_literal_suffix.fixed @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build: proc_macros.rs +//@run-rustfix +//@aux-build: proc_macros.rs #![allow( dead_code, diff --git a/tests/ui/mistyped_literal_suffix.rs b/tests/ui/mistyped_literal_suffix.rs index 04261cba55aa4..f83b7c3dbda5e 100644 --- a/tests/ui/mistyped_literal_suffix.rs +++ b/tests/ui/mistyped_literal_suffix.rs @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build: proc_macros.rs +//@run-rustfix +//@aux-build: proc_macros.rs #![allow( dead_code, diff --git a/tests/ui/module_name_repetitions.rs b/tests/ui/module_name_repetitions.rs index ebaa77cc283e0..fb2c7612343c8 100644 --- a/tests/ui/module_name_repetitions.rs +++ b/tests/ui/module_name_repetitions.rs @@ -1,4 +1,4 @@ -// compile-flags: --test +//@compile-flags: --test #![warn(clippy::module_name_repetitions)] #![allow(dead_code)] diff --git a/tests/ui/multiple_unsafe_ops_per_block.rs b/tests/ui/multiple_unsafe_ops_per_block.rs index 9082f1675a875..73ef35c8c3661 100644 --- a/tests/ui/multiple_unsafe_ops_per_block.rs +++ b/tests/ui/multiple_unsafe_ops_per_block.rs @@ -1,4 +1,4 @@ -// aux-build:proc_macros.rs +//@aux-build:proc_macros.rs #![allow(unused)] #![allow(deref_nullptr)] #![allow(clippy::unnecessary_operation)] diff --git a/tests/ui/must_use_candidates.fixed b/tests/ui/must_use_candidates.fixed index bbbb3cf621e41..0c275504d36b3 100644 --- a/tests/ui/must_use_candidates.fixed +++ b/tests/ui/must_use_candidates.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(never_type)] #![allow(unused_mut, unused_tuple_struct_fields, clippy::redundant_allocation)] #![warn(clippy::must_use_candidate)] diff --git a/tests/ui/must_use_candidates.rs b/tests/ui/must_use_candidates.rs index 94d3c83bdb93a..d1c9267732fa0 100644 --- a/tests/ui/must_use_candidates.rs +++ b/tests/ui/must_use_candidates.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(never_type)] #![allow(unused_mut, unused_tuple_struct_fields, clippy::redundant_allocation)] #![warn(clippy::must_use_candidate)] diff --git a/tests/ui/must_use_unit.fixed b/tests/ui/must_use_unit.fixed index b7d375ff80e11..4f7cf4e56d152 100644 --- a/tests/ui/must_use_unit.fixed +++ b/tests/ui/must_use_unit.fixed @@ -1,5 +1,5 @@ -//run-rustfix -// aux-build:proc_macros.rs +//@run-rustfix +//@aux-build:proc_macros.rs #![warn(clippy::must_use_unit)] #![allow(clippy::unused_unit)] diff --git a/tests/ui/must_use_unit.rs b/tests/ui/must_use_unit.rs index 74d6b4ca865cd..3a814ce16859e 100644 --- a/tests/ui/must_use_unit.rs +++ b/tests/ui/must_use_unit.rs @@ -1,5 +1,5 @@ -//run-rustfix -// aux-build:proc_macros.rs +//@run-rustfix +//@aux-build:proc_macros.rs #![warn(clippy::must_use_unit)] #![allow(clippy::unused_unit)] diff --git a/tests/ui/mut_mut.rs b/tests/ui/mut_mut.rs index 06bb085442a79..d838098de113e 100644 --- a/tests/ui/mut_mut.rs +++ b/tests/ui/mut_mut.rs @@ -1,4 +1,4 @@ -// aux-build:proc_macros.rs +//@aux-build:proc_macros.rs #![warn(clippy::mut_mut)] #![allow(unused)] #![allow(clippy::no_effect, clippy::uninlined_format_args, clippy::unnecessary_operation)] diff --git a/tests/ui/mut_mutex_lock.fixed b/tests/ui/mut_mutex_lock.fixed index ecad10a829038..433817a4e03da 100644 --- a/tests/ui/mut_mutex_lock.fixed +++ b/tests/ui/mut_mutex_lock.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code, unused_mut)] #![warn(clippy::mut_mutex_lock)] diff --git a/tests/ui/mut_mutex_lock.rs b/tests/ui/mut_mutex_lock.rs index f2b1d6fbfbc3e..567a0b59e7030 100644 --- a/tests/ui/mut_mutex_lock.rs +++ b/tests/ui/mut_mutex_lock.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code, unused_mut)] #![warn(clippy::mut_mutex_lock)] diff --git a/tests/ui/needless_arbitrary_self_type.fixed b/tests/ui/needless_arbitrary_self_type.fixed index 9da21eb6b29b8..d7eb1a047ed3a 100644 --- a/tests/ui/needless_arbitrary_self_type.fixed +++ b/tests/ui/needless_arbitrary_self_type.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::needless_arbitrary_self_type)] #![allow(unused_mut, clippy::needless_lifetimes)] diff --git a/tests/ui/needless_arbitrary_self_type.rs b/tests/ui/needless_arbitrary_self_type.rs index 17aeaaf97ac73..85a2a957f29a1 100644 --- a/tests/ui/needless_arbitrary_self_type.rs +++ b/tests/ui/needless_arbitrary_self_type.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::needless_arbitrary_self_type)] #![allow(unused_mut, clippy::needless_lifetimes)] diff --git a/tests/ui/needless_arbitrary_self_type_unfixable.rs b/tests/ui/needless_arbitrary_self_type_unfixable.rs index 02b43cce2bd4c..00871f9f450ca 100644 --- a/tests/ui/needless_arbitrary_self_type_unfixable.rs +++ b/tests/ui/needless_arbitrary_self_type_unfixable.rs @@ -1,4 +1,4 @@ -// aux-build:proc_macro_attr.rs +//@aux-build:proc_macro_attr.rs #![warn(clippy::needless_arbitrary_self_type)] diff --git a/tests/ui/needless_arbitrary_self_type_unfixable.stderr b/tests/ui/needless_arbitrary_self_type_unfixable.stderr index b2edbfe4323e1..c7df5936d706a 100644 --- a/tests/ui/needless_arbitrary_self_type_unfixable.stderr +++ b/tests/ui/needless_arbitrary_self_type_unfixable.stderr @@ -2,7 +2,7 @@ error: the type of the `self` parameter does not need to be arbitrary --> $DIR/needless_arbitrary_self_type_unfixable.rs:42:31 | LL | fn call_with_mut_self(self: &mut Self) {} - | ^^^^^^^^^^^^^^^ help: consider to change this parameter to: `&'_ mut self` + | ^^^^^^^^^^^^^^^ help: consider to change this parameter to: `&mut self` | = note: `-D clippy::needless-arbitrary-self-type` implied by `-D warnings` diff --git a/tests/ui/needless_bitwise_bool.fixed b/tests/ui/needless_bitwise_bool.fixed index 5e1ea663a1077..7543ab72ca214 100644 --- a/tests/ui/needless_bitwise_bool.fixed +++ b/tests/ui/needless_bitwise_bool.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::needless_bitwise_bool)] diff --git a/tests/ui/needless_bitwise_bool.rs b/tests/ui/needless_bitwise_bool.rs index f3075fba0a2d6..2cea701dce636 100644 --- a/tests/ui/needless_bitwise_bool.rs +++ b/tests/ui/needless_bitwise_bool.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::needless_bitwise_bool)] diff --git a/tests/ui/needless_bool/fixable.fixed b/tests/ui/needless_bool/fixable.fixed index 89dc13fd5b13d..f860852e7b7b9 100644 --- a/tests/ui/needless_bool/fixable.fixed +++ b/tests/ui/needless_bool/fixable.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::needless_bool)] #![allow( diff --git a/tests/ui/needless_bool/fixable.rs b/tests/ui/needless_bool/fixable.rs index c11d9472e8d06..6680dab5b6dd0 100644 --- a/tests/ui/needless_bool/fixable.rs +++ b/tests/ui/needless_bool/fixable.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::needless_bool)] #![allow( diff --git a/tests/ui/needless_borrow.fixed b/tests/ui/needless_borrow.fixed index 4cb7f6b687f11..425e6eb6200ec 100644 --- a/tests/ui/needless_borrow.fixed +++ b/tests/ui/needless_borrow.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(lint_reasons)] #![allow( unused, diff --git a/tests/ui/needless_borrow.rs b/tests/ui/needless_borrow.rs index 9a01190ed8dbd..3f7fa4a9d7dc4 100644 --- a/tests/ui/needless_borrow.rs +++ b/tests/ui/needless_borrow.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(lint_reasons)] #![allow( unused, diff --git a/tests/ui/needless_borrowed_ref.fixed b/tests/ui/needless_borrowed_ref.fixed index 0c47ceb7b6791..6663520da8a1d 100644 --- a/tests/ui/needless_borrowed_ref.fixed +++ b/tests/ui/needless_borrowed_ref.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::needless_borrowed_reference)] #![allow( diff --git a/tests/ui/needless_borrowed_ref.rs b/tests/ui/needless_borrowed_ref.rs index f883bb0c88917..6c8efd2ce1804 100644 --- a/tests/ui/needless_borrowed_ref.rs +++ b/tests/ui/needless_borrowed_ref.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::needless_borrowed_reference)] #![allow( diff --git a/tests/ui/needless_collect.fixed b/tests/ui/needless_collect.fixed index 2659ad384885e..024c22de225da 100644 --- a/tests/ui/needless_collect.fixed +++ b/tests/ui/needless_collect.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused, clippy::suspicious_map, clippy::iter_count)] diff --git a/tests/ui/needless_collect.rs b/tests/ui/needless_collect.rs index 535ec82982b13..7ed7babec3078 100644 --- a/tests/ui/needless_collect.rs +++ b/tests/ui/needless_collect.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused, clippy::suspicious_map, clippy::iter_count)] diff --git a/tests/ui/needless_for_each_fixable.fixed b/tests/ui/needless_for_each_fixable.fixed index 09e671b88e1aa..a04f9ec651ed5 100644 --- a/tests/ui/needless_for_each_fixable.fixed +++ b/tests/ui/needless_for_each_fixable.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::needless_for_each)] #![allow(unused)] #![allow( diff --git a/tests/ui/needless_for_each_fixable.rs b/tests/ui/needless_for_each_fixable.rs index abb4045b9197d..4975c7050810e 100644 --- a/tests/ui/needless_for_each_fixable.rs +++ b/tests/ui/needless_for_each_fixable.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::needless_for_each)] #![allow(unused)] #![allow( diff --git a/tests/ui/needless_late_init.fixed b/tests/ui/needless_late_init.fixed index 86d899bb46c36..92f7b3f777a19 100644 --- a/tests/ui/needless_late_init.fixed +++ b/tests/ui/needless_late_init.fixed @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:proc_macros.rs +//@run-rustfix +//@aux-build:proc_macros.rs #![feature(let_chains)] #![allow(unused)] #![allow( diff --git a/tests/ui/needless_late_init.rs b/tests/ui/needless_late_init.rs index 969afb38edf2e..be378c42f95d6 100644 --- a/tests/ui/needless_late_init.rs +++ b/tests/ui/needless_late_init.rs @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:proc_macros.rs +//@run-rustfix +//@aux-build:proc_macros.rs #![feature(let_chains)] #![allow(unused)] #![allow( diff --git a/tests/ui/needless_lifetimes.fixed b/tests/ui/needless_lifetimes.fixed index e6ead69d148e8..7b99042f7449b 100644 --- a/tests/ui/needless_lifetimes.fixed +++ b/tests/ui/needless_lifetimes.fixed @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:proc_macros.rs +//@run-rustfix +//@aux-build:proc_macros.rs #![warn(clippy::needless_lifetimes)] #![allow( diff --git a/tests/ui/needless_lifetimes.rs b/tests/ui/needless_lifetimes.rs index 06eb430506f9f..6fcf1efc2ee67 100644 --- a/tests/ui/needless_lifetimes.rs +++ b/tests/ui/needless_lifetimes.rs @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:proc_macros.rs +//@run-rustfix +//@aux-build:proc_macros.rs #![warn(clippy::needless_lifetimes)] #![allow( diff --git a/tests/ui/needless_match.fixed b/tests/ui/needless_match.fixed index 7e47406798cf9..d8a0400a4f0d5 100644 --- a/tests/ui/needless_match.fixed +++ b/tests/ui/needless_match.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::needless_match)] #![allow(clippy::manual_map)] #![allow(dead_code)] diff --git a/tests/ui/needless_match.rs b/tests/ui/needless_match.rs index 809c694bf4004..3de9bd6d7a1f0 100644 --- a/tests/ui/needless_match.rs +++ b/tests/ui/needless_match.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::needless_match)] #![allow(clippy::manual_map)] #![allow(dead_code)] diff --git a/tests/ui/needless_option_as_deref.fixed b/tests/ui/needless_option_as_deref.fixed index acd22c6bb4337..70015fccf9ee5 100644 --- a/tests/ui/needless_option_as_deref.fixed +++ b/tests/ui/needless_option_as_deref.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] #![warn(clippy::needless_option_as_deref)] diff --git a/tests/ui/needless_option_as_deref.rs b/tests/ui/needless_option_as_deref.rs index 61eda5052a21e..e2e35360cb36b 100644 --- a/tests/ui/needless_option_as_deref.rs +++ b/tests/ui/needless_option_as_deref.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] #![warn(clippy::needless_option_as_deref)] diff --git a/tests/ui/needless_option_take.fixed b/tests/ui/needless_option_take.fixed index 29691e81666f7..bfc6d20d5a326 100644 --- a/tests/ui/needless_option_take.fixed +++ b/tests/ui/needless_option_take.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix fn main() { println!("Testing non erroneous option_take_on_temporary"); diff --git a/tests/ui/needless_option_take.rs b/tests/ui/needless_option_take.rs index 9f4109eb4635a..697eeab42074e 100644 --- a/tests/ui/needless_option_take.rs +++ b/tests/ui/needless_option_take.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix fn main() { println!("Testing non erroneous option_take_on_temporary"); diff --git a/tests/ui/needless_parens_on_range_literals.fixed b/tests/ui/needless_parens_on_range_literals.fixed index f11330a8916d4..9b98f6ea7f799 100644 --- a/tests/ui/needless_parens_on_range_literals.fixed +++ b/tests/ui/needless_parens_on_range_literals.fixed @@ -1,5 +1,5 @@ -// run-rustfix -// edition:2018 +//@run-rustfix +//@edition:2018 #![warn(clippy::needless_parens_on_range_literals)] #![allow(clippy::almost_complete_range)] diff --git a/tests/ui/needless_parens_on_range_literals.rs b/tests/ui/needless_parens_on_range_literals.rs index 671c0009e23b7..088e7b2b98f0f 100644 --- a/tests/ui/needless_parens_on_range_literals.rs +++ b/tests/ui/needless_parens_on_range_literals.rs @@ -1,5 +1,5 @@ -// run-rustfix -// edition:2018 +//@run-rustfix +//@edition:2018 #![warn(clippy::needless_parens_on_range_literals)] #![allow(clippy::almost_complete_range)] diff --git a/tests/ui/needless_question_mark.fixed b/tests/ui/needless_question_mark.fixed index 7eaca571992f4..679b73d404a65 100644 --- a/tests/ui/needless_question_mark.fixed +++ b/tests/ui/needless_question_mark.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::needless_question_mark)] #![allow( diff --git a/tests/ui/needless_question_mark.rs b/tests/ui/needless_question_mark.rs index 960bc7b78983f..a993d3ec35d85 100644 --- a/tests/ui/needless_question_mark.rs +++ b/tests/ui/needless_question_mark.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::needless_question_mark)] #![allow( diff --git a/tests/ui/needless_return.fixed b/tests/ui/needless_return.fixed index 57c08996ce25d..ee4e5007dc5e9 100644 --- a/tests/ui/needless_return.fixed +++ b/tests/ui/needless_return.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(lint_reasons)] #![feature(yeet_expr)] diff --git a/tests/ui/needless_return.rs b/tests/ui/needless_return.rs index 7c1feefbe32bb..cd999db4f40c2 100644 --- a/tests/ui/needless_return.rs +++ b/tests/ui/needless_return.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(lint_reasons)] #![feature(yeet_expr)] diff --git a/tests/ui/needless_splitn.fixed b/tests/ui/needless_splitn.fixed index 5496031fefabf..30a038312c876 100644 --- a/tests/ui/needless_splitn.fixed +++ b/tests/ui/needless_splitn.fixed @@ -1,5 +1,5 @@ -// run-rustfix -// edition:2018 +//@run-rustfix +//@edition:2018 #![warn(clippy::needless_splitn)] #![allow(clippy::iter_skip_next, clippy::iter_nth_zero, clippy::manual_split_once)] diff --git a/tests/ui/needless_splitn.rs b/tests/ui/needless_splitn.rs index 35c2465bae131..1b0b9a5981a19 100644 --- a/tests/ui/needless_splitn.rs +++ b/tests/ui/needless_splitn.rs @@ -1,5 +1,5 @@ -// run-rustfix -// edition:2018 +//@run-rustfix +//@edition:2018 #![warn(clippy::needless_splitn)] #![allow(clippy::iter_skip_next, clippy::iter_nth_zero, clippy::manual_split_once)] diff --git a/tests/ui/neg_multiply.fixed b/tests/ui/neg_multiply.fixed index 58ab9e8567838..e07e7c88d6848 100644 --- a/tests/ui/neg_multiply.fixed +++ b/tests/ui/neg_multiply.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::neg_multiply)] #![allow(clippy::no_effect, clippy::unnecessary_operation, clippy::precedence)] #![allow(unused)] diff --git a/tests/ui/neg_multiply.rs b/tests/ui/neg_multiply.rs index 581290dc72e43..2887af7b42187 100644 --- a/tests/ui/neg_multiply.rs +++ b/tests/ui/neg_multiply.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::neg_multiply)] #![allow(clippy::no_effect, clippy::unnecessary_operation, clippy::precedence)] #![allow(unused)] diff --git a/tests/ui/non_octal_unix_permissions.fixed b/tests/ui/non_octal_unix_permissions.fixed index a9b2dcfb08569..89d127528347c 100644 --- a/tests/ui/non_octal_unix_permissions.fixed +++ b/tests/ui/non_octal_unix_permissions.fixed @@ -1,5 +1,5 @@ -// ignore-windows -// run-rustfix +//@ignore-windows +//@run-rustfix #![warn(clippy::non_octal_unix_permissions)] use std::fs::{DirBuilder, File, OpenOptions, Permissions}; use std::os::unix::fs::{DirBuilderExt, OpenOptionsExt, PermissionsExt}; diff --git a/tests/ui/non_octal_unix_permissions.rs b/tests/ui/non_octal_unix_permissions.rs index 7d2922f494e1e..1b3a322d72658 100644 --- a/tests/ui/non_octal_unix_permissions.rs +++ b/tests/ui/non_octal_unix_permissions.rs @@ -1,5 +1,5 @@ -// ignore-windows -// run-rustfix +//@ignore-windows +//@run-rustfix #![warn(clippy::non_octal_unix_permissions)] use std::fs::{DirBuilder, File, OpenOptions, Permissions}; use std::os::unix::fs::{DirBuilderExt, OpenOptionsExt, PermissionsExt}; diff --git a/tests/ui/nonminimal_bool_methods.fixed b/tests/ui/nonminimal_bool_methods.fixed index aad44089de499..05802a2c865fb 100644 --- a/tests/ui/nonminimal_bool_methods.fixed +++ b/tests/ui/nonminimal_bool_methods.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused, clippy::diverging_sub_expression)] #![warn(clippy::nonminimal_bool)] diff --git a/tests/ui/nonminimal_bool_methods.rs b/tests/ui/nonminimal_bool_methods.rs index b9074da842706..cd5b576fa07e1 100644 --- a/tests/ui/nonminimal_bool_methods.rs +++ b/tests/ui/nonminimal_bool_methods.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused, clippy::diverging_sub_expression)] #![warn(clippy::nonminimal_bool)] diff --git a/tests/ui/numbered_fields.fixed b/tests/ui/numbered_fields.fixed index 68c987eb4c677..a52845e53a4c2 100644 --- a/tests/ui/numbered_fields.fixed +++ b/tests/ui/numbered_fields.fixed @@ -1,4 +1,4 @@ -//run-rustfix +//@run-rustfix #![warn(clippy::init_numbered_fields)] #![allow(unused_tuple_struct_fields)] diff --git a/tests/ui/numbered_fields.rs b/tests/ui/numbered_fields.rs index 2ef4fb4de5370..ca93f7dce59ac 100644 --- a/tests/ui/numbered_fields.rs +++ b/tests/ui/numbered_fields.rs @@ -1,4 +1,4 @@ -//run-rustfix +//@run-rustfix #![warn(clippy::init_numbered_fields)] #![allow(unused_tuple_struct_fields)] diff --git a/tests/ui/obfuscated_if_else.fixed b/tests/ui/obfuscated_if_else.fixed index 62d932c2c6b79..9e4f97253f843 100644 --- a/tests/ui/obfuscated_if_else.fixed +++ b/tests/ui/obfuscated_if_else.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::obfuscated_if_else)] diff --git a/tests/ui/obfuscated_if_else.rs b/tests/ui/obfuscated_if_else.rs index 273be9092a745..c2351d64c1c55 100644 --- a/tests/ui/obfuscated_if_else.rs +++ b/tests/ui/obfuscated_if_else.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::obfuscated_if_else)] diff --git a/tests/ui/octal_escapes.rs b/tests/ui/octal_escapes.rs index 53145ef0fd202..61ea96604577f 100644 --- a/tests/ui/octal_escapes.rs +++ b/tests/ui/octal_escapes.rs @@ -17,4 +17,5 @@ fn main() { let _good3 = "\0\0"; let _good4 = "X\0\0X"; let _good5 = "锈\0锈"; + let _good6 = "\0\\01"; } diff --git a/tests/ui/octal_escapes.stderr b/tests/ui/octal_escapes.stderr index 295dc1798e36d..aa362e96321bd 100644 --- a/tests/ui/octal_escapes.stderr +++ b/tests/ui/octal_escapes.stderr @@ -63,6 +63,22 @@ help: if the null character is intended, disambiguate using LL | let _bad4 = "/x001234567"; | ~~~~~~~~~~~~~ +error: octal-looking escape in string literal + --> $DIR/octal_escapes.rs:9:17 + | +LL | let _bad5 = "/0/03"; + | ^^^^^^^ + | + = help: octal escapes are not supported, `/0` is always a null character +help: if an octal escape was intended, use the hexadecimal representation instead + | +LL | let _bad5 = "/0/x03"; + | ~~~~~~~~ +help: if the null character is intended, disambiguate using + | +LL | let _bad5 = "/0/x003"; + | ~~~~~~~~~ + error: octal-looking escape in string literal --> $DIR/octal_escapes.rs:10:17 | @@ -127,5 +143,5 @@ help: if the null character is intended, disambiguate using LL | let _bad9 = "锈/x0011锈"; | ~~~~~~~~~~~~ -error: aborting due to 8 previous errors +error: aborting due to 9 previous errors diff --git a/tests/ui/option_as_ref_deref.fixed b/tests/ui/option_as_ref_deref.fixed index d124d133faa21..e1c0fa3f7fd39 100644 --- a/tests/ui/option_as_ref_deref.fixed +++ b/tests/ui/option_as_ref_deref.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused, clippy::redundant_clone)] #![warn(clippy::option_as_ref_deref)] diff --git a/tests/ui/option_as_ref_deref.rs b/tests/ui/option_as_ref_deref.rs index 86e354c6716bb..6f4917fd149c9 100644 --- a/tests/ui/option_as_ref_deref.rs +++ b/tests/ui/option_as_ref_deref.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused, clippy::redundant_clone)] #![warn(clippy::option_as_ref_deref)] diff --git a/tests/ui/option_env_unwrap.rs b/tests/ui/option_env_unwrap.rs index 9a56cf40d8a77..ee1fe3f1fc0fc 100644 --- a/tests/ui/option_env_unwrap.rs +++ b/tests/ui/option_env_unwrap.rs @@ -1,4 +1,4 @@ -// aux-build:proc_macros.rs +//@aux-build:proc_macros.rs #![warn(clippy::option_env_unwrap)] #![allow(clippy::map_flatten)] diff --git a/tests/ui/option_filter_map.fixed b/tests/ui/option_filter_map.fixed index b20f73f3110de..93c250cfa735a 100644 --- a/tests/ui/option_filter_map.fixed +++ b/tests/ui/option_filter_map.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::option_filter_map)] #![allow(clippy::map_flatten)] diff --git a/tests/ui/option_filter_map.rs b/tests/ui/option_filter_map.rs index 7abaaa0fb83b3..2c5f03250b987 100644 --- a/tests/ui/option_filter_map.rs +++ b/tests/ui/option_filter_map.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::option_filter_map)] #![allow(clippy::map_flatten)] diff --git a/tests/ui/option_if_let_else.fixed b/tests/ui/option_if_let_else.fixed index 35ce89c798649..9aebcf47100e7 100644 --- a/tests/ui/option_if_let_else.fixed +++ b/tests/ui/option_if_let_else.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::option_if_let_else)] #![allow( unused_tuple_struct_fields, diff --git a/tests/ui/option_if_let_else.rs b/tests/ui/option_if_let_else.rs index c8683e5aae2d0..b40b324902aec 100644 --- a/tests/ui/option_if_let_else.rs +++ b/tests/ui/option_if_let_else.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::option_if_let_else)] #![allow( unused_tuple_struct_fields, diff --git a/tests/ui/option_map_or_none.fixed b/tests/ui/option_map_or_none.fixed index 04bfac7735fa6..501757647bfb8 100644 --- a/tests/ui/option_map_or_none.fixed +++ b/tests/ui/option_map_or_none.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(clippy::bind_instead_of_map)] diff --git a/tests/ui/option_map_or_none.rs b/tests/ui/option_map_or_none.rs index bb84f8a48f45d..4d8704e737da5 100644 --- a/tests/ui/option_map_or_none.rs +++ b/tests/ui/option_map_or_none.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(clippy::bind_instead_of_map)] diff --git a/tests/ui/option_map_unit_fn_fixable.fixed b/tests/ui/option_map_unit_fn_fixable.fixed index 00264dcceaa8d..8f64451edf366 100644 --- a/tests/ui/option_map_unit_fn_fixable.fixed +++ b/tests/ui/option_map_unit_fn_fixable.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::option_map_unit_fn)] #![allow(unused)] #![allow(clippy::uninlined_format_args, clippy::unnecessary_wraps)] diff --git a/tests/ui/option_map_unit_fn_fixable.rs b/tests/ui/option_map_unit_fn_fixable.rs index f3363ebce54e2..2bf7a8e0f7d45 100644 --- a/tests/ui/option_map_unit_fn_fixable.rs +++ b/tests/ui/option_map_unit_fn_fixable.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::option_map_unit_fn)] #![allow(unused)] #![allow(clippy::uninlined_format_args, clippy::unnecessary_wraps)] diff --git a/tests/ui/or_fun_call.fixed b/tests/ui/or_fun_call.fixed index be9a65506e131..f723a55f77f81 100644 --- a/tests/ui/or_fun_call.fixed +++ b/tests/ui/or_fun_call.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::or_fun_call)] #![allow(dead_code)] #![allow(clippy::borrow_as_ptr, clippy::uninlined_format_args, clippy::unnecessary_wraps)] diff --git a/tests/ui/or_fun_call.rs b/tests/ui/or_fun_call.rs index 628c970463890..61ef6e27f3228 100644 --- a/tests/ui/or_fun_call.rs +++ b/tests/ui/or_fun_call.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::or_fun_call)] #![allow(dead_code)] #![allow(clippy::borrow_as_ptr, clippy::uninlined_format_args, clippy::unnecessary_wraps)] diff --git a/tests/ui/or_then_unwrap.fixed b/tests/ui/or_then_unwrap.fixed index 844cc4b7a0928..40badac4424ac 100644 --- a/tests/ui/or_then_unwrap.fixed +++ b/tests/ui/or_then_unwrap.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::or_then_unwrap)] #![allow(clippy::map_identity, clippy::let_unit_value)] diff --git a/tests/ui/or_then_unwrap.rs b/tests/ui/or_then_unwrap.rs index 1528ef9be964d..76c9942fe6c1d 100644 --- a/tests/ui/or_then_unwrap.rs +++ b/tests/ui/or_then_unwrap.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::or_then_unwrap)] #![allow(clippy::map_identity, clippy::let_unit_value)] diff --git a/tests/ui/partialeq_to_none.fixed b/tests/ui/partialeq_to_none.fixed index 4644ea8f51da1..81a716bd276c7 100644 --- a/tests/ui/partialeq_to_none.fixed +++ b/tests/ui/partialeq_to_none.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::partialeq_to_none)] struct Foobar; diff --git a/tests/ui/partialeq_to_none.rs b/tests/ui/partialeq_to_none.rs index 61011b3a8c553..f454715fa30f9 100644 --- a/tests/ui/partialeq_to_none.rs +++ b/tests/ui/partialeq_to_none.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::partialeq_to_none)] struct Foobar; diff --git a/tests/ui/path_buf_push_overwrite.fixed b/tests/ui/path_buf_push_overwrite.fixed index ef8856830fc99..393fc6e1c6933 100644 --- a/tests/ui/path_buf_push_overwrite.fixed +++ b/tests/ui/path_buf_push_overwrite.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix use std::path::PathBuf; #[warn(clippy::all, clippy::path_buf_push_overwrite)] diff --git a/tests/ui/path_buf_push_overwrite.rs b/tests/ui/path_buf_push_overwrite.rs index 6e2d483f45410..18de6e0641268 100644 --- a/tests/ui/path_buf_push_overwrite.rs +++ b/tests/ui/path_buf_push_overwrite.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix use std::path::PathBuf; #[warn(clippy::all, clippy::path_buf_push_overwrite)] diff --git a/tests/ui/patterns.fixed b/tests/ui/patterns.fixed index cd69014326ebb..a1da47d84fd5c 100644 --- a/tests/ui/patterns.fixed +++ b/tests/ui/patterns.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::all)] #![allow(unused)] #![allow(clippy::uninlined_format_args)] diff --git a/tests/ui/patterns.rs b/tests/ui/patterns.rs index 9128da420c0d3..399066b813e3e 100644 --- a/tests/ui/patterns.rs +++ b/tests/ui/patterns.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::all)] #![allow(unused)] #![allow(clippy::uninlined_format_args)] diff --git a/tests/ui/precedence.fixed b/tests/ui/precedence.fixed index 163bd044c178e..af4d5636b6162 100644 --- a/tests/ui/precedence.fixed +++ b/tests/ui/precedence.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::precedence)] #![allow(unused_must_use, clippy::no_effect, clippy::unnecessary_operation)] #![allow(clippy::identity_op)] diff --git a/tests/ui/precedence.rs b/tests/ui/precedence.rs index 8c849e3209b08..e23ae9127866a 100644 --- a/tests/ui/precedence.rs +++ b/tests/ui/precedence.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::precedence)] #![allow(unused_must_use, clippy::no_effect, clippy::unnecessary_operation)] #![allow(clippy::identity_op)] diff --git a/tests/ui/print_stdout_build_script.rs b/tests/ui/print_stdout_build_script.rs index 997ebef8a6992..91448cb0faf8e 100644 --- a/tests/ui/print_stdout_build_script.rs +++ b/tests/ui/print_stdout_build_script.rs @@ -1,4 +1,4 @@ -// compile-flags: --crate-name=build_script_build +//@compile-flags: --crate-name=build_script_build #![warn(clippy::print_stdout)] diff --git a/tests/ui/print_with_newline.rs b/tests/ui/print_with_newline.rs index b8c29d207adae..ff79ca75ffaab 100644 --- a/tests/ui/print_with_newline.rs +++ b/tests/ui/print_with_newline.rs @@ -1,5 +1,5 @@ // FIXME: Ideally these suggestions would be fixed via rustfix. Blocked by rust-lang/rust#53934 -// // run-rustfix +// #![allow(clippy::print_literal)] #![warn(clippy::print_with_newline)] diff --git a/tests/ui/println_empty_string.fixed b/tests/ui/println_empty_string.fixed index 9760680927a63..abf951ae22d64 100644 --- a/tests/ui/println_empty_string.fixed +++ b/tests/ui/println_empty_string.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(clippy::match_single_binding)] fn main() { diff --git a/tests/ui/println_empty_string.rs b/tests/ui/println_empty_string.rs index 80fdb3e6e2105..fd86e2543cc1d 100644 --- a/tests/ui/println_empty_string.rs +++ b/tests/ui/println_empty_string.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(clippy::match_single_binding)] fn main() { diff --git a/tests/ui/ptr_as_ptr.fixed b/tests/ui/ptr_as_ptr.fixed index ee7b998a0b2f3..2c2567d67cd9c 100644 --- a/tests/ui/ptr_as_ptr.fixed +++ b/tests/ui/ptr_as_ptr.fixed @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:proc_macros.rs +//@run-rustfix +//@aux-build:proc_macros.rs #![warn(clippy::ptr_as_ptr)] diff --git a/tests/ui/ptr_as_ptr.rs b/tests/ui/ptr_as_ptr.rs index c88329ce4eccd..6000e5c08acbc 100644 --- a/tests/ui/ptr_as_ptr.rs +++ b/tests/ui/ptr_as_ptr.rs @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:proc_macros.rs +//@run-rustfix +//@aux-build:proc_macros.rs #![warn(clippy::ptr_as_ptr)] diff --git a/tests/ui/ptr_eq.fixed b/tests/ui/ptr_eq.fixed index 209081e6e8011..d5fa273d41f0b 100644 --- a/tests/ui/ptr_eq.fixed +++ b/tests/ui/ptr_eq.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::ptr_eq)] macro_rules! mac { diff --git a/tests/ui/ptr_eq.rs b/tests/ui/ptr_eq.rs index 69162870807a2..e033366a4aab7 100644 --- a/tests/ui/ptr_eq.rs +++ b/tests/ui/ptr_eq.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::ptr_eq)] macro_rules! mac { diff --git a/tests/ui/ptr_offset_with_cast.fixed b/tests/ui/ptr_offset_with_cast.fixed index c57e2990fb951..f69bc131898f7 100644 --- a/tests/ui/ptr_offset_with_cast.fixed +++ b/tests/ui/ptr_offset_with_cast.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(clippy::unnecessary_cast)] fn main() { diff --git a/tests/ui/ptr_offset_with_cast.rs b/tests/ui/ptr_offset_with_cast.rs index 3de7997acddda..eae36c27729e8 100644 --- a/tests/ui/ptr_offset_with_cast.rs +++ b/tests/ui/ptr_offset_with_cast.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(clippy::unnecessary_cast)] fn main() { diff --git a/tests/ui/question_mark.fixed b/tests/ui/question_mark.fixed index 5c49d46da7260..7f1660f31fa5b 100644 --- a/tests/ui/question_mark.fixed +++ b/tests/ui/question_mark.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unreachable_code)] #![allow(dead_code)] #![allow(clippy::unnecessary_wraps)] diff --git a/tests/ui/question_mark.rs b/tests/ui/question_mark.rs index d057df6a9b35d..a90eae50ed457 100644 --- a/tests/ui/question_mark.rs +++ b/tests/ui/question_mark.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unreachable_code)] #![allow(dead_code)] #![allow(clippy::unnecessary_wraps)] diff --git a/tests/ui/range_contains.fixed b/tests/ui/range_contains.fixed index 4923731fe45e8..0a92ee7c8dd30 100644 --- a/tests/ui/range_contains.fixed +++ b/tests/ui/range_contains.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::manual_range_contains)] #![allow(unused)] diff --git a/tests/ui/range_contains.rs b/tests/ui/range_contains.rs index d623ccb5da636..7a83be609571f 100644 --- a/tests/ui/range_contains.rs +++ b/tests/ui/range_contains.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::manual_range_contains)] #![allow(unused)] diff --git a/tests/ui/range_plus_minus_one.fixed b/tests/ui/range_plus_minus_one.fixed index a16a3e54d45ea..79c133cb5e326 100644 --- a/tests/ui/range_plus_minus_one.fixed +++ b/tests/ui/range_plus_minus_one.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused_parens)] #![allow(clippy::iter_with_drain)] diff --git a/tests/ui/range_plus_minus_one.rs b/tests/ui/range_plus_minus_one.rs index bd6cb4d21be51..689a6b7a17ce6 100644 --- a/tests/ui/range_plus_minus_one.rs +++ b/tests/ui/range_plus_minus_one.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused_parens)] #![allow(clippy::iter_with_drain)] diff --git a/tests/ui/rc_buffer.fixed b/tests/ui/rc_buffer.fixed index 8910c01b1fcf9..4cba292c1b73d 100644 --- a/tests/ui/rc_buffer.fixed +++ b/tests/ui/rc_buffer.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::rc_buffer)] #![allow(dead_code, unused_imports)] diff --git a/tests/ui/rc_buffer.rs b/tests/ui/rc_buffer.rs index 1e63a43262ec1..d8a9aa2786d44 100644 --- a/tests/ui/rc_buffer.rs +++ b/tests/ui/rc_buffer.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::rc_buffer)] #![allow(dead_code, unused_imports)] diff --git a/tests/ui/rc_buffer_arc.fixed b/tests/ui/rc_buffer_arc.fixed index 13dd6f5fcd186..ac51ac9e4675b 100644 --- a/tests/ui/rc_buffer_arc.fixed +++ b/tests/ui/rc_buffer_arc.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::rc_buffer)] #![allow(dead_code, unused_imports)] diff --git a/tests/ui/rc_buffer_arc.rs b/tests/ui/rc_buffer_arc.rs index 1a521bfeb7c86..21dc27bc5fa52 100644 --- a/tests/ui/rc_buffer_arc.rs +++ b/tests/ui/rc_buffer_arc.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::rc_buffer)] #![allow(dead_code, unused_imports)] diff --git a/tests/ui/redundant_allocation_fixable.fixed b/tests/ui/redundant_allocation_fixable.fixed index 6db02718c70bb..edb7715f42cdc 100644 --- a/tests/ui/redundant_allocation_fixable.fixed +++ b/tests/ui/redundant_allocation_fixable.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::all)] #![allow(clippy::boxed_local, clippy::needless_pass_by_value)] #![allow(clippy::disallowed_names, unused_variables, dead_code)] diff --git a/tests/ui/redundant_allocation_fixable.rs b/tests/ui/redundant_allocation_fixable.rs index c15806f30c049..c59422dd96604 100644 --- a/tests/ui/redundant_allocation_fixable.rs +++ b/tests/ui/redundant_allocation_fixable.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::all)] #![allow(clippy::boxed_local, clippy::needless_pass_by_value)] #![allow(clippy::disallowed_names, unused_variables, dead_code)] diff --git a/tests/ui/redundant_async_block.fixed b/tests/ui/redundant_async_block.fixed index ad96993c4a78c..328958491eebc 100644 --- a/tests/ui/redundant_async_block.fixed +++ b/tests/ui/redundant_async_block.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused, clippy::manual_async_fn)] #![warn(clippy::redundant_async_block)] diff --git a/tests/ui/redundant_async_block.rs b/tests/ui/redundant_async_block.rs index 7ae235583694d..cd189b31555ca 100644 --- a/tests/ui/redundant_async_block.rs +++ b/tests/ui/redundant_async_block.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused, clippy::manual_async_fn)] #![warn(clippy::redundant_async_block)] diff --git a/tests/ui/redundant_clone.fixed b/tests/ui/redundant_clone.fixed index 00b427450935d..8bebb5183bc1a 100644 --- a/tests/ui/redundant_clone.fixed +++ b/tests/ui/redundant_clone.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix // rustfix-only-machine-applicable #![feature(lint_reasons)] #![allow(clippy::drop_non_drop, clippy::implicit_clone, clippy::uninlined_format_args)] diff --git a/tests/ui/redundant_clone.rs b/tests/ui/redundant_clone.rs index f899127db8d04..b4bd5d16b1a68 100644 --- a/tests/ui/redundant_clone.rs +++ b/tests/ui/redundant_clone.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix // rustfix-only-machine-applicable #![feature(lint_reasons)] #![allow(clippy::drop_non_drop, clippy::implicit_clone, clippy::uninlined_format_args)] diff --git a/tests/ui/redundant_closure_call_fixable.fixed b/tests/ui/redundant_closure_call_fixable.fixed index b987fd2ce6f08..61aed2733fef6 100644 --- a/tests/ui/redundant_closure_call_fixable.fixed +++ b/tests/ui/redundant_closure_call_fixable.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(async_closure)] #![warn(clippy::redundant_closure_call)] diff --git a/tests/ui/redundant_closure_call_fixable.rs b/tests/ui/redundant_closure_call_fixable.rs index 633a2979d5da3..56b2866353918 100644 --- a/tests/ui/redundant_closure_call_fixable.rs +++ b/tests/ui/redundant_closure_call_fixable.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(async_closure)] #![warn(clippy::redundant_closure_call)] diff --git a/tests/ui/redundant_field_names.fixed b/tests/ui/redundant_field_names.fixed index 276266a2dd803..d2a65399da658 100644 --- a/tests/ui/redundant_field_names.fixed +++ b/tests/ui/redundant_field_names.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::redundant_field_names)] #![allow(clippy::extra_unused_type_parameters, clippy::no_effect, dead_code, unused_variables)] diff --git a/tests/ui/redundant_field_names.rs b/tests/ui/redundant_field_names.rs index f674141c138e1..605ffd21e2f77 100644 --- a/tests/ui/redundant_field_names.rs +++ b/tests/ui/redundant_field_names.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::redundant_field_names)] #![allow(clippy::extra_unused_type_parameters, clippy::no_effect, dead_code, unused_variables)] diff --git a/tests/ui/redundant_pattern_matching_drop_order.fixed b/tests/ui/redundant_pattern_matching_drop_order.fixed index ce3229f17591e..bebdf89716fa2 100644 --- a/tests/ui/redundant_pattern_matching_drop_order.fixed +++ b/tests/ui/redundant_pattern_matching_drop_order.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix // Issue #5746 #![warn(clippy::redundant_pattern_matching)] diff --git a/tests/ui/redundant_pattern_matching_drop_order.rs b/tests/ui/redundant_pattern_matching_drop_order.rs index 29b8543cf473a..8fb6ed5f7eca0 100644 --- a/tests/ui/redundant_pattern_matching_drop_order.rs +++ b/tests/ui/redundant_pattern_matching_drop_order.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix // Issue #5746 #![warn(clippy::redundant_pattern_matching)] diff --git a/tests/ui/redundant_pattern_matching_ipaddr.fixed b/tests/ui/redundant_pattern_matching_ipaddr.fixed index 21bae909555ca..a9faf12cd5a11 100644 --- a/tests/ui/redundant_pattern_matching_ipaddr.fixed +++ b/tests/ui/redundant_pattern_matching_ipaddr.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::all, clippy::redundant_pattern_matching)] #![allow(unused_must_use)] #![allow( diff --git a/tests/ui/redundant_pattern_matching_ipaddr.rs b/tests/ui/redundant_pattern_matching_ipaddr.rs index 4dd9171677ec2..574671d03d1c4 100644 --- a/tests/ui/redundant_pattern_matching_ipaddr.rs +++ b/tests/ui/redundant_pattern_matching_ipaddr.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::all, clippy::redundant_pattern_matching)] #![allow(unused_must_use)] #![allow( diff --git a/tests/ui/redundant_pattern_matching_option.fixed b/tests/ui/redundant_pattern_matching_option.fixed index a89845c1dd32b..87100b972880c 100644 --- a/tests/ui/redundant_pattern_matching_option.fixed +++ b/tests/ui/redundant_pattern_matching_option.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::all)] #![warn(clippy::redundant_pattern_matching)] diff --git a/tests/ui/redundant_pattern_matching_option.rs b/tests/ui/redundant_pattern_matching_option.rs index d6f44403487ef..0b69e13f65590 100644 --- a/tests/ui/redundant_pattern_matching_option.rs +++ b/tests/ui/redundant_pattern_matching_option.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::all)] #![warn(clippy::redundant_pattern_matching)] diff --git a/tests/ui/redundant_pattern_matching_poll.fixed b/tests/ui/redundant_pattern_matching_poll.fixed index 3645f2c4bfdd2..bf3e692202c36 100644 --- a/tests/ui/redundant_pattern_matching_poll.fixed +++ b/tests/ui/redundant_pattern_matching_poll.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::all)] #![warn(clippy::redundant_pattern_matching)] diff --git a/tests/ui/redundant_pattern_matching_poll.rs b/tests/ui/redundant_pattern_matching_poll.rs index 866c71b7cfa80..892a21d9d298e 100644 --- a/tests/ui/redundant_pattern_matching_poll.rs +++ b/tests/ui/redundant_pattern_matching_poll.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::all)] #![warn(clippy::redundant_pattern_matching)] diff --git a/tests/ui/redundant_pattern_matching_result.fixed b/tests/ui/redundant_pattern_matching_result.fixed index 42348df4480b3..c48d1522935c5 100644 --- a/tests/ui/redundant_pattern_matching_result.fixed +++ b/tests/ui/redundant_pattern_matching_result.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::all)] #![warn(clippy::redundant_pattern_matching)] #![allow(deprecated, unused_must_use)] diff --git a/tests/ui/redundant_pattern_matching_result.rs b/tests/ui/redundant_pattern_matching_result.rs index 5949cb2271c62..26f37d169fac6 100644 --- a/tests/ui/redundant_pattern_matching_result.rs +++ b/tests/ui/redundant_pattern_matching_result.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::all)] #![warn(clippy::redundant_pattern_matching)] #![allow(deprecated, unused_must_use)] diff --git a/tests/ui/redundant_pub_crate.fixed b/tests/ui/redundant_pub_crate.fixed index 106947de68c12..f65c0fdd35da1 100644 --- a/tests/ui/redundant_pub_crate.fixed +++ b/tests/ui/redundant_pub_crate.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code)] #![warn(clippy::redundant_pub_crate)] diff --git a/tests/ui/redundant_pub_crate.rs b/tests/ui/redundant_pub_crate.rs index f96cfd3184384..fb07fed98befb 100644 --- a/tests/ui/redundant_pub_crate.rs +++ b/tests/ui/redundant_pub_crate.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code)] #![warn(clippy::redundant_pub_crate)] diff --git a/tests/ui/redundant_slicing.fixed b/tests/ui/redundant_slicing.fixed index 8dd8d3092378e..56ddca71903e4 100644 --- a/tests/ui/redundant_slicing.fixed +++ b/tests/ui/redundant_slicing.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused, clippy::deref_by_slicing)] #![warn(clippy::redundant_slicing)] diff --git a/tests/ui/redundant_slicing.rs b/tests/ui/redundant_slicing.rs index 51c16dd8d65a2..d67b6665e2604 100644 --- a/tests/ui/redundant_slicing.rs +++ b/tests/ui/redundant_slicing.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused, clippy::deref_by_slicing)] #![warn(clippy::redundant_slicing)] diff --git a/tests/ui/redundant_static_lifetimes.fixed b/tests/ui/redundant_static_lifetimes.fixed index bca777a890c3b..2651735d10364 100644 --- a/tests/ui/redundant_static_lifetimes.fixed +++ b/tests/ui/redundant_static_lifetimes.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] diff --git a/tests/ui/redundant_static_lifetimes.rs b/tests/ui/redundant_static_lifetimes.rs index afe7644816d2e..7286652899d6b 100644 --- a/tests/ui/redundant_static_lifetimes.rs +++ b/tests/ui/redundant_static_lifetimes.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] diff --git a/tests/ui/rename.fixed b/tests/ui/rename.fixed index 5076f61334d67..e8a00a9e7f712 100644 --- a/tests/ui/rename.fixed +++ b/tests/ui/rename.fixed @@ -2,7 +2,7 @@ // Use that command to update this file and do not edit by hand. // Manual edits will be overwritten. -// run-rustfix +//@run-rustfix #![allow(clippy::almost_complete_range)] #![allow(clippy::disallowed_names)] diff --git a/tests/ui/rename.rs b/tests/ui/rename.rs index 64bc1ca7116c5..c8ea70c2bcb1d 100644 --- a/tests/ui/rename.rs +++ b/tests/ui/rename.rs @@ -2,7 +2,7 @@ // Use that command to update this file and do not edit by hand. // Manual edits will be overwritten. -// run-rustfix +//@run-rustfix #![allow(clippy::almost_complete_range)] #![allow(clippy::disallowed_names)] diff --git a/tests/ui/renamed_builtin_attr.fixed b/tests/ui/renamed_builtin_attr.fixed index cb91b841d2cb2..0334c1e1a29c5 100644 --- a/tests/ui/renamed_builtin_attr.fixed +++ b/tests/ui/renamed_builtin_attr.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #[clippy::cognitive_complexity = "1"] fn main() {} diff --git a/tests/ui/renamed_builtin_attr.rs b/tests/ui/renamed_builtin_attr.rs index b3ce2758067cf..d350370c2449d 100644 --- a/tests/ui/renamed_builtin_attr.rs +++ b/tests/ui/renamed_builtin_attr.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #[clippy::cyclomatic_complexity = "1"] fn main() {} diff --git a/tests/ui/repeat_once.fixed b/tests/ui/repeat_once.fixed index dc197e50300d8..c517bfcc6aa93 100644 --- a/tests/ui/repeat_once.fixed +++ b/tests/ui/repeat_once.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::repeat_once)] #[allow(unused, clippy::redundant_clone)] fn main() { diff --git a/tests/ui/repeat_once.rs b/tests/ui/repeat_once.rs index 0ec5127117c6e..9a30b47418ffd 100644 --- a/tests/ui/repeat_once.rs +++ b/tests/ui/repeat_once.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::repeat_once)] #[allow(unused, clippy::redundant_clone)] fn main() { diff --git a/tests/ui/result_map_or_into_option.fixed b/tests/ui/result_map_or_into_option.fixed index 331531b5165f6..119ff25918a76 100644 --- a/tests/ui/result_map_or_into_option.fixed +++ b/tests/ui/result_map_or_into_option.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::result_map_or_into_option)] diff --git a/tests/ui/result_map_or_into_option.rs b/tests/ui/result_map_or_into_option.rs index 3058480e2ad3d..eeeef830af0a5 100644 --- a/tests/ui/result_map_or_into_option.rs +++ b/tests/ui/result_map_or_into_option.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::result_map_or_into_option)] diff --git a/tests/ui/result_map_unit_fn_fixable.fixed b/tests/ui/result_map_unit_fn_fixable.fixed index d8b56237e9832..0583d29277b35 100644 --- a/tests/ui/result_map_unit_fn_fixable.fixed +++ b/tests/ui/result_map_unit_fn_fixable.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::result_map_unit_fn)] #![allow(unused)] #![allow(clippy::uninlined_format_args)] diff --git a/tests/ui/result_map_unit_fn_fixable.rs b/tests/ui/result_map_unit_fn_fixable.rs index 44f50d21109cd..7ad3bdd04bd6d 100644 --- a/tests/ui/result_map_unit_fn_fixable.rs +++ b/tests/ui/result_map_unit_fn_fixable.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::result_map_unit_fn)] #![allow(unused)] #![allow(clippy::uninlined_format_args)] diff --git a/tests/ui/reversed_empty_ranges_fixable.fixed b/tests/ui/reversed_empty_ranges_fixable.fixed index c67edb36c67ad..30dfc977681ad 100644 --- a/tests/ui/reversed_empty_ranges_fixable.fixed +++ b/tests/ui/reversed_empty_ranges_fixable.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::reversed_empty_ranges)] #![allow(clippy::uninlined_format_args)] diff --git a/tests/ui/reversed_empty_ranges_fixable.rs b/tests/ui/reversed_empty_ranges_fixable.rs index 0a4fef5bfe87b..1837249eae1e4 100644 --- a/tests/ui/reversed_empty_ranges_fixable.rs +++ b/tests/ui/reversed_empty_ranges_fixable.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::reversed_empty_ranges)] #![allow(clippy::uninlined_format_args)] diff --git a/tests/ui/reversed_empty_ranges_loops_fixable.fixed b/tests/ui/reversed_empty_ranges_loops_fixable.fixed index 78401e463d50d..a74569599c79b 100644 --- a/tests/ui/reversed_empty_ranges_loops_fixable.fixed +++ b/tests/ui/reversed_empty_ranges_loops_fixable.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::reversed_empty_ranges)] #![allow(clippy::uninlined_format_args)] diff --git a/tests/ui/reversed_empty_ranges_loops_fixable.rs b/tests/ui/reversed_empty_ranges_loops_fixable.rs index f9e0f7fcd6dbf..42f9957dfbd01 100644 --- a/tests/ui/reversed_empty_ranges_loops_fixable.rs +++ b/tests/ui/reversed_empty_ranges_loops_fixable.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::reversed_empty_ranges)] #![allow(clippy::uninlined_format_args)] diff --git a/tests/ui/same_functions_in_if_condition.rs b/tests/ui/same_functions_in_if_condition.rs index e6198a1bc9a07..aea1507cc5bd9 100644 --- a/tests/ui/same_functions_in_if_condition.rs +++ b/tests/ui/same_functions_in_if_condition.rs @@ -1,5 +1,5 @@ #![feature(adt_const_params)] -#![warn(clippy::same_functions_in_if_condition)] +#![deny(clippy::same_functions_in_if_condition)] // ifs_same_cond warning is different from `ifs_same_cond`. // clippy::if_same_then_else, clippy::comparison_chain -- all empty blocks #![allow(incomplete_features)] diff --git a/tests/ui/same_functions_in_if_condition.stderr b/tests/ui/same_functions_in_if_condition.stderr index f352ade150ee2..aade3b1fa4571 100644 --- a/tests/ui/same_functions_in_if_condition.stderr +++ b/tests/ui/same_functions_in_if_condition.stderr @@ -9,7 +9,11 @@ note: same as this | LL | if function() { | ^^^^^^^^^^ - = note: `-D clippy::same-functions-in-if-condition` implied by `-D warnings` +note: the lint level is defined here + --> $DIR/same_functions_in_if_condition.rs:2:9 + | +LL | #![deny(clippy::same_functions_in_if_condition)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this `if` has the same function call as a previous `if` --> $DIR/same_functions_in_if_condition.rs:42:15 diff --git a/tests/ui/search_is_some.rs b/tests/ui/search_is_some.rs index 72f335153c1b1..670599b0dcf59 100644 --- a/tests/ui/search_is_some.rs +++ b/tests/ui/search_is_some.rs @@ -1,4 +1,4 @@ -// aux-build:option_helpers.rs +//@aux-build:option_helpers.rs #![warn(clippy::search_is_some)] #![allow(dead_code)] extern crate option_helpers; diff --git a/tests/ui/search_is_some_fixable_none.fixed b/tests/ui/search_is_some_fixable_none.fixed index 5190c5304c75d..9386618c123ef 100644 --- a/tests/ui/search_is_some_fixable_none.fixed +++ b/tests/ui/search_is_some_fixable_none.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code, clippy::explicit_auto_deref)] #![warn(clippy::search_is_some)] diff --git a/tests/ui/search_is_some_fixable_none.rs b/tests/ui/search_is_some_fixable_none.rs index 310d87333a93c..6b2537a96c2af 100644 --- a/tests/ui/search_is_some_fixable_none.rs +++ b/tests/ui/search_is_some_fixable_none.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code, clippy::explicit_auto_deref)] #![warn(clippy::search_is_some)] diff --git a/tests/ui/search_is_some_fixable_some.fixed b/tests/ui/search_is_some_fixable_some.fixed index 385a9986aba04..e9116fc59f10e 100644 --- a/tests/ui/search_is_some_fixable_some.fixed +++ b/tests/ui/search_is_some_fixable_some.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code, clippy::explicit_auto_deref)] #![warn(clippy::search_is_some)] diff --git a/tests/ui/search_is_some_fixable_some.rs b/tests/ui/search_is_some_fixable_some.rs index 67e190ee37837..b152839945765 100644 --- a/tests/ui/search_is_some_fixable_some.rs +++ b/tests/ui/search_is_some_fixable_some.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code, clippy::explicit_auto_deref)] #![warn(clippy::search_is_some)] diff --git a/tests/ui/seek_from_current.fixed b/tests/ui/seek_from_current.fixed index 1309c91b81c98..34c33baf686d4 100644 --- a/tests/ui/seek_from_current.fixed +++ b/tests/ui/seek_from_current.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::seek_from_current)] use std::fs::File; diff --git a/tests/ui/seek_from_current.rs b/tests/ui/seek_from_current.rs index 5d9b1424cf686..22bcff1bc4054 100644 --- a/tests/ui/seek_from_current.rs +++ b/tests/ui/seek_from_current.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::seek_from_current)] use std::fs::File; diff --git a/tests/ui/seek_to_start_instead_of_rewind.fixed b/tests/ui/seek_to_start_instead_of_rewind.fixed index dc24d447c6075..d8a6e6985d4a0 100644 --- a/tests/ui/seek_to_start_instead_of_rewind.fixed +++ b/tests/ui/seek_to_start_instead_of_rewind.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] #![warn(clippy::seek_to_start_instead_of_rewind)] diff --git a/tests/ui/seek_to_start_instead_of_rewind.rs b/tests/ui/seek_to_start_instead_of_rewind.rs index 4adde2c40182d..fc6a6433c2b09 100644 --- a/tests/ui/seek_to_start_instead_of_rewind.rs +++ b/tests/ui/seek_to_start_instead_of_rewind.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] #![warn(clippy::seek_to_start_instead_of_rewind)] diff --git a/tests/ui/semicolon_inside_block.fixed b/tests/ui/semicolon_inside_block.fixed index 42e97e1ca358e..ee359f60cbd7f 100644 --- a/tests/ui/semicolon_inside_block.fixed +++ b/tests/ui/semicolon_inside_block.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow( unused, clippy::unused_unit, diff --git a/tests/ui/semicolon_inside_block.rs b/tests/ui/semicolon_inside_block.rs index f40848f702e1c..e8516f79b20cd 100644 --- a/tests/ui/semicolon_inside_block.rs +++ b/tests/ui/semicolon_inside_block.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow( unused, clippy::unused_unit, diff --git a/tests/ui/semicolon_outside_block.fixed b/tests/ui/semicolon_outside_block.fixed index 091eaa7518e95..034c7f8c7c180 100644 --- a/tests/ui/semicolon_outside_block.fixed +++ b/tests/ui/semicolon_outside_block.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow( unused, clippy::unused_unit, diff --git a/tests/ui/semicolon_outside_block.rs b/tests/ui/semicolon_outside_block.rs index 7ce46431fac9a..4dc956d8a4b51 100644 --- a/tests/ui/semicolon_outside_block.rs +++ b/tests/ui/semicolon_outside_block.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow( unused, clippy::unused_unit, diff --git a/tests/ui/shadow.rs b/tests/ui/shadow.rs index 1fa9fc749a96a..03337ec35643c 100644 --- a/tests/ui/shadow.rs +++ b/tests/ui/shadow.rs @@ -1,6 +1,13 @@ +//@aux-build:proc_macro_derive.rs + #![warn(clippy::shadow_same, clippy::shadow_reuse, clippy::shadow_unrelated)] #![allow(clippy::let_unit_value)] +extern crate proc_macro_derive; + +#[derive(proc_macro_derive::ShadowDerive)] +pub struct Nothing; + fn shadow_same() { let x = 1; let x = x; diff --git a/tests/ui/shadow.stderr b/tests/ui/shadow.stderr index c3d7bc2a5360f..92bb937d08680 100644 --- a/tests/ui/shadow.stderr +++ b/tests/ui/shadow.stderr @@ -1,278 +1,278 @@ error: `x` is shadowed by itself in `x` - --> $DIR/shadow.rs:6:9 + --> $DIR/shadow.rs:13:9 | LL | let x = x; | ^ | note: previous binding is here - --> $DIR/shadow.rs:5:9 + --> $DIR/shadow.rs:12:9 | LL | let x = 1; | ^ = note: `-D clippy::shadow-same` implied by `-D warnings` error: `mut x` is shadowed by itself in `&x` - --> $DIR/shadow.rs:7:13 + --> $DIR/shadow.rs:14:13 | LL | let mut x = &x; | ^ | note: previous binding is here - --> $DIR/shadow.rs:6:9 + --> $DIR/shadow.rs:13:9 | LL | let x = x; | ^ error: `x` is shadowed by itself in `&mut x` - --> $DIR/shadow.rs:8:9 + --> $DIR/shadow.rs:15:9 | LL | let x = &mut x; | ^ | note: previous binding is here - --> $DIR/shadow.rs:7:9 + --> $DIR/shadow.rs:14:9 | LL | let mut x = &x; | ^^^^^ error: `x` is shadowed by itself in `*x` - --> $DIR/shadow.rs:9:9 + --> $DIR/shadow.rs:16:9 | LL | let x = *x; | ^ | note: previous binding is here - --> $DIR/shadow.rs:8:9 + --> $DIR/shadow.rs:15:9 | LL | let x = &mut x; | ^ error: `x` is shadowed - --> $DIR/shadow.rs:14:9 + --> $DIR/shadow.rs:21:9 | LL | let x = x.0; | ^ | note: previous binding is here - --> $DIR/shadow.rs:13:9 + --> $DIR/shadow.rs:20:9 | LL | let x = ([[0]], ()); | ^ = note: `-D clippy::shadow-reuse` implied by `-D warnings` error: `x` is shadowed - --> $DIR/shadow.rs:15:9 + --> $DIR/shadow.rs:22:9 | LL | let x = x[0]; | ^ | note: previous binding is here - --> $DIR/shadow.rs:14:9 + --> $DIR/shadow.rs:21:9 | LL | let x = x.0; | ^ error: `x` is shadowed - --> $DIR/shadow.rs:16:10 + --> $DIR/shadow.rs:23:10 | LL | let [x] = x; | ^ | note: previous binding is here - --> $DIR/shadow.rs:15:9 + --> $DIR/shadow.rs:22:9 | LL | let x = x[0]; | ^ error: `x` is shadowed - --> $DIR/shadow.rs:17:9 + --> $DIR/shadow.rs:24:9 | LL | let x = Some(x); | ^ | note: previous binding is here - --> $DIR/shadow.rs:16:10 + --> $DIR/shadow.rs:23:10 | LL | let [x] = x; | ^ error: `x` is shadowed - --> $DIR/shadow.rs:18:9 + --> $DIR/shadow.rs:25:9 | LL | let x = foo(x); | ^ | note: previous binding is here - --> $DIR/shadow.rs:17:9 + --> $DIR/shadow.rs:24:9 | LL | let x = Some(x); | ^ error: `x` is shadowed - --> $DIR/shadow.rs:19:9 + --> $DIR/shadow.rs:26:9 | LL | let x = || x; | ^ | note: previous binding is here - --> $DIR/shadow.rs:18:9 + --> $DIR/shadow.rs:25:9 | LL | let x = foo(x); | ^ error: `x` is shadowed - --> $DIR/shadow.rs:20:9 + --> $DIR/shadow.rs:27:9 | LL | let x = Some(1).map(|_| x)?; | ^ | note: previous binding is here - --> $DIR/shadow.rs:19:9 + --> $DIR/shadow.rs:26:9 | LL | let x = || x; | ^ error: `y` is shadowed - --> $DIR/shadow.rs:22:9 + --> $DIR/shadow.rs:29:9 | LL | let y = match y { | ^ | note: previous binding is here - --> $DIR/shadow.rs:21:9 + --> $DIR/shadow.rs:28:9 | LL | let y = 1; | ^ error: `x` shadows a previous, unrelated binding - --> $DIR/shadow.rs:31:9 + --> $DIR/shadow.rs:38:9 | LL | let x = 2; | ^ | note: previous binding is here - --> $DIR/shadow.rs:30:9 + --> $DIR/shadow.rs:37:9 | LL | let x = 1; | ^ = note: `-D clippy::shadow-unrelated` implied by `-D warnings` error: `x` shadows a previous, unrelated binding - --> $DIR/shadow.rs:36:13 + --> $DIR/shadow.rs:43:13 | LL | let x = 1; | ^ | note: previous binding is here - --> $DIR/shadow.rs:35:10 + --> $DIR/shadow.rs:42:10 | LL | fn f(x: u32) { | ^ error: `x` shadows a previous, unrelated binding - --> $DIR/shadow.rs:41:14 + --> $DIR/shadow.rs:48:14 | LL | Some(x) => { | ^ | note: previous binding is here - --> $DIR/shadow.rs:38:9 + --> $DIR/shadow.rs:45:9 | LL | let x = 1; | ^ error: `x` shadows a previous, unrelated binding - --> $DIR/shadow.rs:42:17 + --> $DIR/shadow.rs:49:17 | LL | let x = 1; | ^ | note: previous binding is here - --> $DIR/shadow.rs:41:14 + --> $DIR/shadow.rs:48:14 | LL | Some(x) => { | ^ error: `x` shadows a previous, unrelated binding - --> $DIR/shadow.rs:46:17 + --> $DIR/shadow.rs:53:17 | LL | if let Some(x) = Some(1) {} | ^ | note: previous binding is here - --> $DIR/shadow.rs:38:9 + --> $DIR/shadow.rs:45:9 | LL | let x = 1; | ^ error: `x` shadows a previous, unrelated binding - --> $DIR/shadow.rs:47:20 + --> $DIR/shadow.rs:54:20 | LL | while let Some(x) = Some(1) {} | ^ | note: previous binding is here - --> $DIR/shadow.rs:38:9 + --> $DIR/shadow.rs:45:9 | LL | let x = 1; | ^ error: `x` shadows a previous, unrelated binding - --> $DIR/shadow.rs:48:15 + --> $DIR/shadow.rs:55:15 | LL | let _ = |[x]: [u32; 1]| { | ^ | note: previous binding is here - --> $DIR/shadow.rs:38:9 + --> $DIR/shadow.rs:45:9 | LL | let x = 1; | ^ error: `x` shadows a previous, unrelated binding - --> $DIR/shadow.rs:49:13 + --> $DIR/shadow.rs:56:13 | LL | let x = 1; | ^ | note: previous binding is here - --> $DIR/shadow.rs:48:15 + --> $DIR/shadow.rs:55:15 | LL | let _ = |[x]: [u32; 1]| { | ^ error: `y` is shadowed - --> $DIR/shadow.rs:52:17 + --> $DIR/shadow.rs:59:17 | LL | if let Some(y) = y {} | ^ | note: previous binding is here - --> $DIR/shadow.rs:51:9 + --> $DIR/shadow.rs:58:9 | LL | let y = Some(1); | ^ error: `_b` shadows a previous, unrelated binding - --> $DIR/shadow.rs:88:9 + --> $DIR/shadow.rs:95:9 | LL | let _b = _a; | ^^ | note: previous binding is here - --> $DIR/shadow.rs:87:28 + --> $DIR/shadow.rs:94:28 | LL | pub async fn foo2(_a: i32, _b: i64) { | ^^ error: `x` shadows a previous, unrelated binding - --> $DIR/shadow.rs:94:21 + --> $DIR/shadow.rs:101:21 | LL | if let Some(x) = Some(1) { x } else { 1 } | ^ | note: previous binding is here - --> $DIR/shadow.rs:93:13 + --> $DIR/shadow.rs:100:13 | LL | let x = 1; | ^ diff --git a/tests/ui/short_circuit_statement.fixed b/tests/ui/short_circuit_statement.fixed index dd22ecab0b551..1737d50144198 100644 --- a/tests/ui/short_circuit_statement.fixed +++ b/tests/ui/short_circuit_statement.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::short_circuit_statement)] #![allow(clippy::nonminimal_bool)] diff --git a/tests/ui/short_circuit_statement.rs b/tests/ui/short_circuit_statement.rs index 73a55bf1f5e27..ab93aa1ca5caa 100644 --- a/tests/ui/short_circuit_statement.rs +++ b/tests/ui/short_circuit_statement.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::short_circuit_statement)] #![allow(clippy::nonminimal_bool)] diff --git a/tests/ui/significant_drop_in_scrutinee.rs b/tests/ui/significant_drop_in_scrutinee.rs index c65df9ece38c4..8c48b21f18846 100644 --- a/tests/ui/significant_drop_in_scrutinee.rs +++ b/tests/ui/significant_drop_in_scrutinee.rs @@ -1,5 +1,5 @@ // FIXME: Ideally these suggestions would be fixed via rustfix. Blocked by rust-lang/rust#53934 -// // run-rustfix +// #![warn(clippy::significant_drop_in_scrutinee)] #![allow(dead_code, unused_assignments)] #![allow(clippy::match_single_binding, clippy::single_match, clippy::uninlined_format_args)] diff --git a/tests/ui/significant_drop_tightening.fixed b/tests/ui/significant_drop_tightening.fixed index da998c610bd29..ee7f2b0631ad6 100644 --- a/tests/ui/significant_drop_tightening.fixed +++ b/tests/ui/significant_drop_tightening.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::significant_drop_tightening)] diff --git a/tests/ui/significant_drop_tightening.rs b/tests/ui/significant_drop_tightening.rs index 83823f95f68ac..9c139deb95f2d 100644 --- a/tests/ui/significant_drop_tightening.rs +++ b/tests/ui/significant_drop_tightening.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::significant_drop_tightening)] diff --git a/tests/ui/single_char_add_str.fixed b/tests/ui/single_char_add_str.fixed index 63a6d37a9cce9..cbcf1ab21c9bd 100644 --- a/tests/ui/single_char_add_str.fixed +++ b/tests/ui/single_char_add_str.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::single_char_add_str)] macro_rules! get_string { diff --git a/tests/ui/single_char_add_str.rs b/tests/ui/single_char_add_str.rs index a799ea7d88564..a1f005cc833b1 100644 --- a/tests/ui/single_char_add_str.rs +++ b/tests/ui/single_char_add_str.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::single_char_add_str)] macro_rules! get_string { diff --git a/tests/ui/single_char_pattern.fixed b/tests/ui/single_char_pattern.fixed index 68e26726724b8..dba89872070e8 100644 --- a/tests/ui/single_char_pattern.fixed +++ b/tests/ui/single_char_pattern.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused_must_use)] diff --git a/tests/ui/single_char_pattern.rs b/tests/ui/single_char_pattern.rs index 186202d78ec5a..6a145a14bfdc7 100644 --- a/tests/ui/single_char_pattern.rs +++ b/tests/ui/single_char_pattern.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused_must_use)] diff --git a/tests/ui/single_component_path_imports.fixed b/tests/ui/single_component_path_imports.fixed index 8c96c4715d308..d4d2cbbe57ac9 100644 --- a/tests/ui/single_component_path_imports.fixed +++ b/tests/ui/single_component_path_imports.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::single_component_path_imports)] #![allow(unused_imports)] diff --git a/tests/ui/single_component_path_imports.rs b/tests/ui/single_component_path_imports.rs index 8434bf7eaf1f5..80d72115f435d 100644 --- a/tests/ui/single_component_path_imports.rs +++ b/tests/ui/single_component_path_imports.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::single_component_path_imports)] #![allow(unused_imports)] diff --git a/tests/ui/single_element_loop.fixed b/tests/ui/single_element_loop.fixed index a0dcc0172e8b0..1697a0cf29b8e 100644 --- a/tests/ui/single_element_loop.fixed +++ b/tests/ui/single_element_loop.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix // Tests from for_loop.rs that don't have suggestions #[warn(clippy::single_element_loop)] diff --git a/tests/ui/single_element_loop.rs b/tests/ui/single_element_loop.rs index bc014035c98a5..860424f42ddf0 100644 --- a/tests/ui/single_element_loop.rs +++ b/tests/ui/single_element_loop.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix // Tests from for_loop.rs that don't have suggestions #[warn(clippy::single_element_loop)] diff --git a/tests/ui/single_match_else.rs b/tests/ui/single_match_else.rs index 3c86f41f3a6e7..c8ac768b60f68 100644 --- a/tests/ui/single_match_else.rs +++ b/tests/ui/single_match_else.rs @@ -1,4 +1,4 @@ -// aux-build: proc_macros.rs +//@aux-build: proc_macros.rs #![warn(clippy::single_match_else)] #![allow(clippy::needless_return, clippy::no_effect, clippy::uninlined_format_args)] diff --git a/tests/ui/skip_while_next.rs b/tests/ui/skip_while_next.rs index a551c19d98bcd..62574e2c8ceaa 100644 --- a/tests/ui/skip_while_next.rs +++ b/tests/ui/skip_while_next.rs @@ -1,4 +1,4 @@ -// aux-build:option_helpers.rs +//@aux-build:option_helpers.rs #![warn(clippy::skip_while_next)] #![allow(clippy::disallowed_names)] diff --git a/tests/ui/stable_sort_primitive.fixed b/tests/ui/stable_sort_primitive.fixed index f5f18169df295..1370dd2df4dae 100644 --- a/tests/ui/stable_sort_primitive.fixed +++ b/tests/ui/stable_sort_primitive.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::stable_sort_primitive)] fn main() { diff --git a/tests/ui/stable_sort_primitive.rs b/tests/ui/stable_sort_primitive.rs index 8149c5638e0f7..cd344dd123897 100644 --- a/tests/ui/stable_sort_primitive.rs +++ b/tests/ui/stable_sort_primitive.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::stable_sort_primitive)] fn main() { diff --git a/tests/ui/starts_ends_with.fixed b/tests/ui/starts_ends_with.fixed index 983fac7afe69a..29d56f852edde 100644 --- a/tests/ui/starts_ends_with.fixed +++ b/tests/ui/starts_ends_with.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code, unused_must_use)] fn main() {} diff --git a/tests/ui/starts_ends_with.rs b/tests/ui/starts_ends_with.rs index e3335dd2e2ef7..56bbe2574d426 100644 --- a/tests/ui/starts_ends_with.rs +++ b/tests/ui/starts_ends_with.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code, unused_must_use)] fn main() {} diff --git a/tests/ui/string_add.rs b/tests/ui/string_add.rs index 20edbe31fa9e7..de78dfe4d6990 100644 --- a/tests/ui/string_add.rs +++ b/tests/ui/string_add.rs @@ -1,4 +1,4 @@ -// aux-build:proc_macros.rs +//@aux-build:proc_macros.rs extern crate proc_macros; use proc_macros::external; diff --git a/tests/ui/string_add_assign.fixed b/tests/ui/string_add_assign.fixed index b687f43b2541a..616c6daaf6605 100644 --- a/tests/ui/string_add_assign.fixed +++ b/tests/ui/string_add_assign.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #[allow(clippy::string_add, unused)] #[warn(clippy::string_add_assign)] diff --git a/tests/ui/string_add_assign.rs b/tests/ui/string_add_assign.rs index e5dbde108fbdb..e1f8859757c64 100644 --- a/tests/ui/string_add_assign.rs +++ b/tests/ui/string_add_assign.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #[allow(clippy::string_add, unused)] #[warn(clippy::string_add_assign)] diff --git a/tests/ui/string_extend.fixed b/tests/ui/string_extend.fixed index d200d7310fca5..65c9abff3d418 100644 --- a/tests/ui/string_extend.fixed +++ b/tests/ui/string_extend.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #[derive(Copy, Clone)] struct HasChars; diff --git a/tests/ui/string_extend.rs b/tests/ui/string_extend.rs index 0dd96a3b21035..5f72ffe2fda76 100644 --- a/tests/ui/string_extend.rs +++ b/tests/ui/string_extend.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #[derive(Copy, Clone)] struct HasChars; diff --git a/tests/ui/string_from_utf8_as_bytes.fixed b/tests/ui/string_from_utf8_as_bytes.fixed index 6e665cdd56302..9b315ae2b5585 100644 --- a/tests/ui/string_from_utf8_as_bytes.fixed +++ b/tests/ui/string_from_utf8_as_bytes.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::string_from_utf8_as_bytes)] fn main() { diff --git a/tests/ui/string_from_utf8_as_bytes.rs b/tests/ui/string_from_utf8_as_bytes.rs index 670d206d3679c..043dd2350829b 100644 --- a/tests/ui/string_from_utf8_as_bytes.rs +++ b/tests/ui/string_from_utf8_as_bytes.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::string_from_utf8_as_bytes)] fn main() { diff --git a/tests/ui/string_lit_as_bytes.fixed b/tests/ui/string_lit_as_bytes.fixed index 506187fc12573..058f2aa54daaa 100644 --- a/tests/ui/string_lit_as_bytes.fixed +++ b/tests/ui/string_lit_as_bytes.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code, unused_variables)] #![warn(clippy::string_lit_as_bytes)] diff --git a/tests/ui/string_lit_as_bytes.rs b/tests/ui/string_lit_as_bytes.rs index 2c339f1ddb819..b550bea001f47 100644 --- a/tests/ui/string_lit_as_bytes.rs +++ b/tests/ui/string_lit_as_bytes.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code, unused_variables)] #![warn(clippy::string_lit_as_bytes)] diff --git a/tests/ui/strlen_on_c_strings.fixed b/tests/ui/strlen_on_c_strings.fixed index 947a59bcc027a..ef207e28cca37 100644 --- a/tests/ui/strlen_on_c_strings.fixed +++ b/tests/ui/strlen_on_c_strings.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::strlen_on_c_strings)] #![allow(dead_code)] diff --git a/tests/ui/strlen_on_c_strings.rs b/tests/ui/strlen_on_c_strings.rs index 1237f1ab03acd..03ec5f79d092c 100644 --- a/tests/ui/strlen_on_c_strings.rs +++ b/tests/ui/strlen_on_c_strings.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::strlen_on_c_strings)] #![allow(dead_code)] diff --git a/tests/ui/suspicious_doc_comments.fixed b/tests/ui/suspicious_doc_comments.fixed index b404df94d3c29..bffda1cc41296 100644 --- a/tests/ui/suspicious_doc_comments.fixed +++ b/tests/ui/suspicious_doc_comments.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] #![warn(clippy::suspicious_doc_comments)] diff --git a/tests/ui/suspicious_doc_comments.rs b/tests/ui/suspicious_doc_comments.rs index 46eff51e220f5..cdd972ee30fbf 100644 --- a/tests/ui/suspicious_doc_comments.rs +++ b/tests/ui/suspicious_doc_comments.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] #![warn(clippy::suspicious_doc_comments)] diff --git a/tests/ui/suspicious_else_formatting.rs b/tests/ui/suspicious_else_formatting.rs index 21753e5dc6a47..e0153cdd8cdcf 100644 --- a/tests/ui/suspicious_else_formatting.rs +++ b/tests/ui/suspicious_else_formatting.rs @@ -1,4 +1,4 @@ -// aux-build:proc_macro_suspicious_else_formatting.rs +//@aux-build:proc_macro_suspicious_else_formatting.rs #![warn(clippy::suspicious_else_formatting)] #![allow(clippy::if_same_then_else, clippy::let_unit_value)] diff --git a/tests/ui/suspicious_operation_groupings.fixed b/tests/ui/suspicious_operation_groupings.fixed index ede8a39fed718..0e37701ec48b8 100644 --- a/tests/ui/suspicious_operation_groupings.fixed +++ b/tests/ui/suspicious_operation_groupings.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::suspicious_operation_groupings)] #![allow(dead_code, unused_parens, clippy::eq_op)] diff --git a/tests/ui/suspicious_operation_groupings.rs b/tests/ui/suspicious_operation_groupings.rs index 26ce97bb37f84..dd4f3b71c378f 100644 --- a/tests/ui/suspicious_operation_groupings.rs +++ b/tests/ui/suspicious_operation_groupings.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::suspicious_operation_groupings)] #![allow(dead_code, unused_parens, clippy::eq_op)] diff --git a/tests/ui/swap.fixed b/tests/ui/swap.fixed index 9703674d1a4ed..fd3569cf36254 100644 --- a/tests/ui/swap.fixed +++ b/tests/ui/swap.fixed @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build: macro_rules.rs +//@run-rustfix +//@aux-build: macro_rules.rs #![warn(clippy::all)] #![allow( diff --git a/tests/ui/swap.rs b/tests/ui/swap.rs index a0228065e46b5..34fbce0524b21 100644 --- a/tests/ui/swap.rs +++ b/tests/ui/swap.rs @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build: macro_rules.rs +//@run-rustfix +//@aux-build: macro_rules.rs #![warn(clippy::all)] #![allow( diff --git a/tests/ui/swap_ptr_to_ref.fixed b/tests/ui/swap_ptr_to_ref.fixed index 596b6ee919bb4..3bede3017a13c 100644 --- a/tests/ui/swap_ptr_to_ref.fixed +++ b/tests/ui/swap_ptr_to_ref.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::swap_ptr_to_ref)] diff --git a/tests/ui/swap_ptr_to_ref.rs b/tests/ui/swap_ptr_to_ref.rs index 282f571211d95..726b09d37643a 100644 --- a/tests/ui/swap_ptr_to_ref.rs +++ b/tests/ui/swap_ptr_to_ref.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::swap_ptr_to_ref)] diff --git a/tests/ui/tabs_in_doc_comments.fixed b/tests/ui/tabs_in_doc_comments.fixed index 4bc4bc86c76c2..21020182c241b 100644 --- a/tests/ui/tabs_in_doc_comments.fixed +++ b/tests/ui/tabs_in_doc_comments.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::tabs_in_doc_comments)] #[allow(dead_code)] diff --git a/tests/ui/tabs_in_doc_comments.rs b/tests/ui/tabs_in_doc_comments.rs index 9db3416e65964..df704267dd25a 100644 --- a/tests/ui/tabs_in_doc_comments.rs +++ b/tests/ui/tabs_in_doc_comments.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::tabs_in_doc_comments)] #[allow(dead_code)] diff --git a/tests/ui/tests_outside_test_module.rs b/tests/ui/tests_outside_test_module.rs index 1982b1d0107f8..21fdfdf900516 100644 --- a/tests/ui/tests_outside_test_module.rs +++ b/tests/ui/tests_outside_test_module.rs @@ -1,4 +1,4 @@ -// compile-flags: --test +//@compile-flags: --test #![allow(unused)] #![warn(clippy::tests_outside_test_module)] diff --git a/tests/ui/to_digit_is_some.fixed b/tests/ui/to_digit_is_some.fixed index 3c5e964271465..dc9be66d48ab4 100644 --- a/tests/ui/to_digit_is_some.fixed +++ b/tests/ui/to_digit_is_some.fixed @@ -1,4 +1,4 @@ -//run-rustfix +//@run-rustfix #![warn(clippy::to_digit_is_some)] diff --git a/tests/ui/to_digit_is_some.rs b/tests/ui/to_digit_is_some.rs index 4f247c06ceeda..d2a09ac30de4e 100644 --- a/tests/ui/to_digit_is_some.rs +++ b/tests/ui/to_digit_is_some.rs @@ -1,4 +1,4 @@ -//run-rustfix +//@run-rustfix #![warn(clippy::to_digit_is_some)] diff --git a/tests/ui/toplevel_ref_arg.fixed b/tests/ui/toplevel_ref_arg.fixed index 174c858a47d1f..ea30c1fda6fce 100644 --- a/tests/ui/toplevel_ref_arg.fixed +++ b/tests/ui/toplevel_ref_arg.fixed @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:proc_macros.rs +//@run-rustfix +//@aux-build:proc_macros.rs #![warn(clippy::toplevel_ref_arg)] #![allow(clippy::uninlined_format_args, unused)] diff --git a/tests/ui/toplevel_ref_arg.rs b/tests/ui/toplevel_ref_arg.rs index 4b81a06112fe2..7a3d33e5be5a2 100644 --- a/tests/ui/toplevel_ref_arg.rs +++ b/tests/ui/toplevel_ref_arg.rs @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:proc_macros.rs +//@run-rustfix +//@aux-build:proc_macros.rs #![warn(clippy::toplevel_ref_arg)] #![allow(clippy::uninlined_format_args, unused)] diff --git a/tests/ui/toplevel_ref_arg_non_rustfix.rs b/tests/ui/toplevel_ref_arg_non_rustfix.rs index 2047593e7e4b8..8aaf47b1bd0c5 100644 --- a/tests/ui/toplevel_ref_arg_non_rustfix.rs +++ b/tests/ui/toplevel_ref_arg_non_rustfix.rs @@ -1,4 +1,4 @@ -// aux-build:proc_macros.rs +//@aux-build:proc_macros.rs #![warn(clippy::toplevel_ref_arg)] #![allow(unused)] diff --git a/tests/ui/track-diagnostics.rs b/tests/ui/track-diagnostics.rs index fa9221ed02d74..6ab0bce770e2f 100644 --- a/tests/ui/track-diagnostics.rs +++ b/tests/ui/track-diagnostics.rs @@ -1,9 +1,8 @@ -// compile-flags: -Z track-diagnostics -// error-pattern: created at +//@compile-flags: -Z track-diagnostics // Normalize the emitted location so this doesn't need // updating everytime someone adds or removes a line. -// normalize-stderr-test ".rs:\d+:\d+" -> ".rs:LL:CC" +//@normalize-stderr-test: ".rs:\d+:\d+" -> ".rs:LL:CC" struct A; struct B; diff --git a/tests/ui/trait_duplication_in_bounds.fixed b/tests/ui/trait_duplication_in_bounds.fixed index 4ce5d42178225..eef8024b131cb 100644 --- a/tests/ui/trait_duplication_in_bounds.fixed +++ b/tests/ui/trait_duplication_in_bounds.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![deny(clippy::trait_duplication_in_bounds)] #![allow(unused)] diff --git a/tests/ui/trait_duplication_in_bounds.rs b/tests/ui/trait_duplication_in_bounds.rs index 7f2e96a22e664..a7a1caf2880d3 100644 --- a/tests/ui/trait_duplication_in_bounds.rs +++ b/tests/ui/trait_duplication_in_bounds.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![deny(clippy::trait_duplication_in_bounds)] #![allow(unused)] diff --git a/tests/ui/transmute_32bit.rs b/tests/ui/transmute_32bit.rs index ffe22b12f5510..8e1316ca39d4f 100644 --- a/tests/ui/transmute_32bit.rs +++ b/tests/ui/transmute_32bit.rs @@ -1,4 +1,4 @@ -// ignore-64bit +//@ignore-64bit #[warn(clippy::wrong_transmute)] fn main() { diff --git a/tests/ui/transmute_32bit.stderr b/tests/ui/transmute_32bit.stderr index 040519564b94c..75ddca60d2aaa 100644 --- a/tests/ui/transmute_32bit.stderr +++ b/tests/ui/transmute_32bit.stderr @@ -1,28 +1,39 @@ -error: transmute from a `f32` to a pointer +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> $DIR/transmute_32bit.rs:6:31 | LL | let _: *const usize = std::mem::transmute(6.0f32); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ | - = note: `-D clippy::wrong-transmute` implied by `-D warnings` + = note: source type: `f32` (32 bits) + = note: target type: `*const usize` (64 bits) -error: transmute from a `f32` to a pointer +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> $DIR/transmute_32bit.rs:8:29 | LL | let _: *mut usize = std::mem::transmute(6.0f32); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ + | + = note: source type: `f32` (32 bits) + = note: target type: `*mut usize` (64 bits) -error: transmute from a `char` to a pointer +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> $DIR/transmute_32bit.rs:10:31 | LL | let _: *const usize = std::mem::transmute('x'); - | ^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ + | + = note: source type: `char` (32 bits) + = note: target type: `*const usize` (64 bits) -error: transmute from a `char` to a pointer +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> $DIR/transmute_32bit.rs:12:29 | LL | let _: *mut usize = std::mem::transmute('x'); - | ^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ + | + = note: source type: `char` (32 bits) + = note: target type: `*mut usize` (64 bits) error: aborting due to 4 previous errors +For more information about this error, try `rustc --explain E0512`. diff --git a/tests/ui/transmute_64bit.rs b/tests/ui/transmute_64bit.rs index 00dc0b2c36081..ceecf9b279f06 100644 --- a/tests/ui/transmute_64bit.rs +++ b/tests/ui/transmute_64bit.rs @@ -1,4 +1,4 @@ -// ignore-32bit +//@ignore-32bit #[warn(clippy::wrong_transmute)] fn main() { diff --git a/tests/ui/transmute_ptr_to_ref.fixed b/tests/ui/transmute_ptr_to_ref.fixed index 074dae5fb2868..575dadde90630 100644 --- a/tests/ui/transmute_ptr_to_ref.fixed +++ b/tests/ui/transmute_ptr_to_ref.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::transmute_ptr_to_ref)] #![allow(clippy::match_single_binding)] diff --git a/tests/ui/transmute_ptr_to_ref.rs b/tests/ui/transmute_ptr_to_ref.rs index 2edc122cf4712..4238ff804780e 100644 --- a/tests/ui/transmute_ptr_to_ref.rs +++ b/tests/ui/transmute_ptr_to_ref.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::transmute_ptr_to_ref)] #![allow(clippy::match_single_binding)] diff --git a/tests/ui/transmutes_expressible_as_ptr_casts.fixed b/tests/ui/transmutes_expressible_as_ptr_casts.fixed index cc84ba25bd0d7..05aa86c479ad6 100644 --- a/tests/ui/transmutes_expressible_as_ptr_casts.fixed +++ b/tests/ui/transmutes_expressible_as_ptr_casts.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::transmutes_expressible_as_ptr_casts)] // These two warnings currently cover the cases transmutes_expressible_as_ptr_casts // would otherwise be responsible for diff --git a/tests/ui/transmutes_expressible_as_ptr_casts.rs b/tests/ui/transmutes_expressible_as_ptr_casts.rs index aa65ab4dd2475..29fa6914cfd0b 100644 --- a/tests/ui/transmutes_expressible_as_ptr_casts.rs +++ b/tests/ui/transmutes_expressible_as_ptr_casts.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::transmutes_expressible_as_ptr_casts)] // These two warnings currently cover the cases transmutes_expressible_as_ptr_casts // would otherwise be responsible for diff --git a/tests/ui/trim_split_whitespace.fixed b/tests/ui/trim_split_whitespace.fixed index e4d352f7367e4..7909b319ddd5a 100644 --- a/tests/ui/trim_split_whitespace.fixed +++ b/tests/ui/trim_split_whitespace.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::trim_split_whitespace)] #![allow(clippy::let_unit_value)] diff --git a/tests/ui/trim_split_whitespace.rs b/tests/ui/trim_split_whitespace.rs index f98451a983712..0cf58979fb207 100644 --- a/tests/ui/trim_split_whitespace.rs +++ b/tests/ui/trim_split_whitespace.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::trim_split_whitespace)] #![allow(clippy::let_unit_value)] diff --git a/tests/ui/trivially_copy_pass_by_ref.rs b/tests/ui/trivially_copy_pass_by_ref.rs index c0af011d33d06..486155831561d 100644 --- a/tests/ui/trivially_copy_pass_by_ref.rs +++ b/tests/ui/trivially_copy_pass_by_ref.rs @@ -1,5 +1,5 @@ -// normalize-stderr-test "\(\d+ byte\)" -> "(N byte)" -// normalize-stderr-test "\(limit: \d+ byte\)" -> "(limit: N byte)" +//@normalize-stderr-test: "\(\d+ byte\)" -> "(N byte)" +//@normalize-stderr-test: "\(limit: \d+ byte\)" -> "(limit: N byte)" #![deny(clippy::trivially_copy_pass_by_ref)] #![allow( clippy::disallowed_names, diff --git a/tests/ui/try_err.fixed b/tests/ui/try_err.fixed index dc497b1690f54..dc773ad4bad95 100644 --- a/tests/ui/try_err.fixed +++ b/tests/ui/try_err.fixed @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:proc_macros.rs +//@run-rustfix +//@aux-build:proc_macros.rs #![deny(clippy::try_err)] #![allow(clippy::unnecessary_wraps, clippy::needless_question_mark)] diff --git a/tests/ui/try_err.rs b/tests/ui/try_err.rs index 86aeb75cd96a5..7a7433a7ec29a 100644 --- a/tests/ui/try_err.rs +++ b/tests/ui/try_err.rs @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:proc_macros.rs +//@run-rustfix +//@aux-build:proc_macros.rs #![deny(clippy::try_err)] #![allow(clippy::unnecessary_wraps, clippy::needless_question_mark)] diff --git a/tests/ui/types.fixed b/tests/ui/types.fixed index 417da42edf17b..4a2616a7a228e 100644 --- a/tests/ui/types.fixed +++ b/tests/ui/types.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code, unused_variables)] #![warn(clippy::cast_lossless)] diff --git a/tests/ui/types.rs b/tests/ui/types.rs index b16e9e538b106..5e0917907db75 100644 --- a/tests/ui/types.rs +++ b/tests/ui/types.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code, unused_variables)] #![warn(clippy::cast_lossless)] diff --git a/tests/ui/unchecked_duration_subtraction.fixed b/tests/ui/unchecked_duration_subtraction.fixed index a0e49a8beb1ed..757d159218472 100644 --- a/tests/ui/unchecked_duration_subtraction.fixed +++ b/tests/ui/unchecked_duration_subtraction.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::unchecked_duration_subtraction)] use std::time::{Duration, Instant}; diff --git a/tests/ui/unchecked_duration_subtraction.rs b/tests/ui/unchecked_duration_subtraction.rs index a14a7ea57cc50..da7faab6753ef 100644 --- a/tests/ui/unchecked_duration_subtraction.rs +++ b/tests/ui/unchecked_duration_subtraction.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::unchecked_duration_subtraction)] use std::time::{Duration, Instant}; diff --git a/tests/ui/undocumented_unsafe_blocks.rs b/tests/ui/undocumented_unsafe_blocks.rs index c05eb447b2ebd..229d150851a43 100644 --- a/tests/ui/undocumented_unsafe_blocks.rs +++ b/tests/ui/undocumented_unsafe_blocks.rs @@ -1,4 +1,4 @@ -// aux-build:proc_macro_unsafe.rs +//@aux-build:proc_macro_unsafe.rs #![warn(clippy::undocumented_unsafe_blocks, clippy::unnecessary_safety_comment)] #![allow(clippy::let_unit_value, clippy::missing_safety_doc)] diff --git a/tests/ui/unicode.fixed b/tests/ui/unicode.fixed index 94b4723452fad..910968afa7f44 100644 --- a/tests/ui/unicode.fixed +++ b/tests/ui/unicode.fixed @@ -1,5 +1,5 @@ -// run-rustfix -// compile-flags: --test +//@run-rustfix +//@compile-flags: --test #![allow(dead_code)] #[warn(clippy::invisible_characters)] diff --git a/tests/ui/unicode.rs b/tests/ui/unicode.rs index 6ad0b255b9485..bc4b84d34354a 100644 --- a/tests/ui/unicode.rs +++ b/tests/ui/unicode.rs @@ -1,5 +1,5 @@ -// run-rustfix -// compile-flags: --test +//@run-rustfix +//@compile-flags: --test #![allow(dead_code)] #[warn(clippy::invisible_characters)] diff --git a/tests/ui/uninlined_format_args.fixed b/tests/ui/uninlined_format_args.fixed index 3122081a44f98..e25d123dd51f1 100644 --- a/tests/ui/uninlined_format_args.fixed +++ b/tests/ui/uninlined_format_args.fixed @@ -1,5 +1,5 @@ -// aux-build:proc_macros.rs -// run-rustfix +//@aux-build:proc_macros.rs +//@run-rustfix #![warn(clippy::uninlined_format_args)] #![allow(named_arguments_used_positionally, unused)] #![allow(clippy::eq_op, clippy::format_in_format_args, clippy::print_literal)] diff --git a/tests/ui/uninlined_format_args.rs b/tests/ui/uninlined_format_args.rs index b153ef256e0c2..6793ec24441ce 100644 --- a/tests/ui/uninlined_format_args.rs +++ b/tests/ui/uninlined_format_args.rs @@ -1,5 +1,5 @@ -// aux-build:proc_macros.rs -// run-rustfix +//@aux-build:proc_macros.rs +//@run-rustfix #![warn(clippy::uninlined_format_args)] #![allow(named_arguments_used_positionally, unused)] #![allow(clippy::eq_op, clippy::format_in_format_args, clippy::print_literal)] diff --git a/tests/ui/uninlined_format_args_panic.edition2018.fixed b/tests/ui/uninlined_format_args_panic.edition2018.fixed index 52b5343c351e6..559050b3df62c 100644 --- a/tests/ui/uninlined_format_args_panic.edition2018.fixed +++ b/tests/ui/uninlined_format_args_panic.edition2018.fixed @@ -1,7 +1,7 @@ -// revisions: edition2018 edition2021 -//[edition2018] edition:2018 -//[edition2021] edition:2021 -// run-rustfix +//@revisions: edition2018 edition2021 +//@[edition2018] edition:2018 +//@[edition2021] edition:2021 +//@run-rustfix #![warn(clippy::uninlined_format_args)] diff --git a/tests/ui/uninlined_format_args_panic.edition2021.fixed b/tests/ui/uninlined_format_args_panic.edition2021.fixed index ee72065e28abf..3a753b49caf3e 100644 --- a/tests/ui/uninlined_format_args_panic.edition2021.fixed +++ b/tests/ui/uninlined_format_args_panic.edition2021.fixed @@ -1,7 +1,7 @@ -// revisions: edition2018 edition2021 -//[edition2018] edition:2018 -//[edition2021] edition:2021 -// run-rustfix +//@revisions: edition2018 edition2021 +//@[edition2018] edition:2018 +//@[edition2021] edition:2021 +//@run-rustfix #![warn(clippy::uninlined_format_args)] diff --git a/tests/ui/uninlined_format_args_panic.rs b/tests/ui/uninlined_format_args_panic.rs index b4a0a0f496e40..83fbb9afd2a19 100644 --- a/tests/ui/uninlined_format_args_panic.rs +++ b/tests/ui/uninlined_format_args_panic.rs @@ -1,7 +1,7 @@ -// revisions: edition2018 edition2021 -//[edition2018] edition:2018 -//[edition2021] edition:2021 -// run-rustfix +//@revisions: edition2018 edition2021 +//@[edition2018] edition:2018 +//@[edition2021] edition:2021 +//@run-rustfix #![warn(clippy::uninlined_format_args)] diff --git a/tests/ui/unit_arg.rs b/tests/ui/unit_arg.rs index 674ae4f1df97e..d082063c8e820 100644 --- a/tests/ui/unit_arg.rs +++ b/tests/ui/unit_arg.rs @@ -1,4 +1,4 @@ -// aux-build: proc_macros.rs +//@aux-build: proc_macros.rs #![warn(clippy::unit_arg)] #![allow(unused_must_use, unused_variables)] #![allow( diff --git a/tests/ui/unit_arg_empty_blocks.fixed b/tests/ui/unit_arg_empty_blocks.fixed index 5787471a32caa..8c065115a74e7 100644 --- a/tests/ui/unit_arg_empty_blocks.fixed +++ b/tests/ui/unit_arg_empty_blocks.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::unit_arg)] #![allow(unused_must_use, unused_variables)] #![allow(clippy::no_effect, clippy::uninlined_format_args)] diff --git a/tests/ui/unit_arg_empty_blocks.rs b/tests/ui/unit_arg_empty_blocks.rs index 6a42c2ccf42b3..af166b56ff488 100644 --- a/tests/ui/unit_arg_empty_blocks.rs +++ b/tests/ui/unit_arg_empty_blocks.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::unit_arg)] #![allow(unused_must_use, unused_variables)] #![allow(clippy::no_effect, clippy::uninlined_format_args)] diff --git a/tests/ui/unknown_clippy_lints.fixed b/tests/ui/unknown_clippy_lints.fixed index 4249ff8a958d1..0c269d650c8c4 100644 --- a/tests/ui/unknown_clippy_lints.fixed +++ b/tests/ui/unknown_clippy_lints.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::pedantic)] // Should suggest lowercase diff --git a/tests/ui/unknown_clippy_lints.rs b/tests/ui/unknown_clippy_lints.rs index 5db345f544413..b60042923ea18 100644 --- a/tests/ui/unknown_clippy_lints.rs +++ b/tests/ui/unknown_clippy_lints.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::pedantic)] // Should suggest lowercase diff --git a/tests/ui/unnecessary_box_returns.rs b/tests/ui/unnecessary_box_returns.rs index fe60d929759ba..ce7cc2e97cb25 100644 --- a/tests/ui/unnecessary_box_returns.rs +++ b/tests/ui/unnecessary_box_returns.rs @@ -54,6 +54,16 @@ fn string() -> String { String::from("Hello, world") } +struct Huge([u8; 500]); +struct HasHuge(Box); + +impl HasHuge { + // don't lint: The size of `Huge` is very large + fn into_huge(self) -> Box { + self.0 + } +} + fn main() { // don't lint: this is a closure let a = || -> Box { Box::new(5) }; diff --git a/tests/ui/unnecessary_cast.fixed b/tests/ui/unnecessary_cast.fixed index 2f7e2997e739d..bcc231ea7bce5 100644 --- a/tests/ui/unnecessary_cast.fixed +++ b/tests/ui/unnecessary_cast.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::unnecessary_cast)] #![allow( unused_must_use, diff --git a/tests/ui/unnecessary_cast.rs b/tests/ui/unnecessary_cast.rs index 54dd46ba59f10..282b2f1283ee9 100644 --- a/tests/ui/unnecessary_cast.rs +++ b/tests/ui/unnecessary_cast.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::unnecessary_cast)] #![allow( unused_must_use, diff --git a/tests/ui/unnecessary_fold.fixed b/tests/ui/unnecessary_fold.fixed index 52300a3b64061..2bed14973caa7 100644 --- a/tests/ui/unnecessary_fold.fixed +++ b/tests/ui/unnecessary_fold.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code)] diff --git a/tests/ui/unnecessary_fold.rs b/tests/ui/unnecessary_fold.rs index 4028d80c0a3cb..a3cec8ea3d554 100644 --- a/tests/ui/unnecessary_fold.rs +++ b/tests/ui/unnecessary_fold.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code)] diff --git a/tests/ui/unnecessary_iter_cloned.fixed b/tests/ui/unnecessary_iter_cloned.fixed index e01e9f07bafda..a0f8dd1a200db 100644 --- a/tests/ui/unnecessary_iter_cloned.fixed +++ b/tests/ui/unnecessary_iter_cloned.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused_assignments)] #![warn(clippy::unnecessary_to_owned)] diff --git a/tests/ui/unnecessary_iter_cloned.rs b/tests/ui/unnecessary_iter_cloned.rs index 6ef2966c8b762..98f2dfe754915 100644 --- a/tests/ui/unnecessary_iter_cloned.rs +++ b/tests/ui/unnecessary_iter_cloned.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused_assignments)] #![warn(clippy::unnecessary_to_owned)] diff --git a/tests/ui/unnecessary_join.fixed b/tests/ui/unnecessary_join.fixed index 3479539602575..e102df6259989 100644 --- a/tests/ui/unnecessary_join.fixed +++ b/tests/ui/unnecessary_join.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::unnecessary_join)] #![allow(clippy::uninlined_format_args)] diff --git a/tests/ui/unnecessary_join.rs b/tests/ui/unnecessary_join.rs index 344918cd2a2ec..b87c15bc12635 100644 --- a/tests/ui/unnecessary_join.rs +++ b/tests/ui/unnecessary_join.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::unnecessary_join)] #![allow(clippy::uninlined_format_args)] diff --git a/tests/ui/unnecessary_lazy_eval.fixed b/tests/ui/unnecessary_lazy_eval.fixed index 3b93800f8b750..c3728886ec9c6 100644 --- a/tests/ui/unnecessary_lazy_eval.fixed +++ b/tests/ui/unnecessary_lazy_eval.fixed @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build: proc_macros.rs +//@run-rustfix +//@aux-build: proc_macros.rs #![warn(clippy::unnecessary_lazy_evaluations)] #![allow(clippy::redundant_closure)] #![allow(clippy::bind_instead_of_map)] diff --git a/tests/ui/unnecessary_lazy_eval.rs b/tests/ui/unnecessary_lazy_eval.rs index 2851c0c519049..76e50fa5b0304 100644 --- a/tests/ui/unnecessary_lazy_eval.rs +++ b/tests/ui/unnecessary_lazy_eval.rs @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build: proc_macros.rs +//@run-rustfix +//@aux-build: proc_macros.rs #![warn(clippy::unnecessary_lazy_evaluations)] #![allow(clippy::redundant_closure)] #![allow(clippy::bind_instead_of_map)] diff --git a/tests/ui/unnecessary_operation.fixed b/tests/ui/unnecessary_operation.fixed index b046694f8c6f6..fbd2d34591fc0 100644 --- a/tests/ui/unnecessary_operation.fixed +++ b/tests/ui/unnecessary_operation.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow( clippy::deref_addrof, diff --git a/tests/ui/unnecessary_operation.rs b/tests/ui/unnecessary_operation.rs index 9ed9679e938b0..b45298a6dc462 100644 --- a/tests/ui/unnecessary_operation.rs +++ b/tests/ui/unnecessary_operation.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow( clippy::deref_addrof, diff --git a/tests/ui/unnecessary_owned_empty_strings.fixed b/tests/ui/unnecessary_owned_empty_strings.fixed index 40052c41039e5..af12fd1d63d01 100644 --- a/tests/ui/unnecessary_owned_empty_strings.fixed +++ b/tests/ui/unnecessary_owned_empty_strings.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::unnecessary_owned_empty_strings)] diff --git a/tests/ui/unnecessary_owned_empty_strings.rs b/tests/ui/unnecessary_owned_empty_strings.rs index 2304dff5192b9..a460b21af8c29 100644 --- a/tests/ui/unnecessary_owned_empty_strings.rs +++ b/tests/ui/unnecessary_owned_empty_strings.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::unnecessary_owned_empty_strings)] diff --git a/tests/ui/unnecessary_self_imports.fixed b/tests/ui/unnecessary_self_imports.fixed index 1185eaa1d552f..7fc978d3ef7e7 100644 --- a/tests/ui/unnecessary_self_imports.fixed +++ b/tests/ui/unnecessary_self_imports.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::unnecessary_self_imports)] #![allow(unused_imports, dead_code)] diff --git a/tests/ui/unnecessary_self_imports.rs b/tests/ui/unnecessary_self_imports.rs index 56bfbc09402ad..02424bc12b00e 100644 --- a/tests/ui/unnecessary_self_imports.rs +++ b/tests/ui/unnecessary_self_imports.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::unnecessary_self_imports)] #![allow(unused_imports, dead_code)] diff --git a/tests/ui/unnecessary_sort_by.fixed b/tests/ui/unnecessary_sort_by.fixed index 21e2da474a820..165cabd829890 100644 --- a/tests/ui/unnecessary_sort_by.fixed +++ b/tests/ui/unnecessary_sort_by.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(clippy::stable_sort_primitive)] diff --git a/tests/ui/unnecessary_sort_by.rs b/tests/ui/unnecessary_sort_by.rs index 3365bf6e119e2..8a2158d5a8416 100644 --- a/tests/ui/unnecessary_sort_by.rs +++ b/tests/ui/unnecessary_sort_by.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(clippy::stable_sort_primitive)] diff --git a/tests/ui/unnecessary_struct_initialization.fixed b/tests/ui/unnecessary_struct_initialization.fixed index b47129e4a36a8..bdf746cf2c425 100644 --- a/tests/ui/unnecessary_struct_initialization.fixed +++ b/tests/ui/unnecessary_struct_initialization.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] #![warn(clippy::unnecessary_struct_initialization)] diff --git a/tests/ui/unnecessary_struct_initialization.rs b/tests/ui/unnecessary_struct_initialization.rs index 63b11c626e5bf..7271e2f957a87 100644 --- a/tests/ui/unnecessary_struct_initialization.rs +++ b/tests/ui/unnecessary_struct_initialization.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] #![warn(clippy::unnecessary_struct_initialization)] diff --git a/tests/ui/unnecessary_to_owned.fixed b/tests/ui/unnecessary_to_owned.fixed index 345f6d604c4f0..c879fdc3b6aec 100644 --- a/tests/ui/unnecessary_to_owned.fixed +++ b/tests/ui/unnecessary_to_owned.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(clippy::needless_borrow, clippy::ptr_arg)] #![warn(clippy::unnecessary_to_owned)] diff --git a/tests/ui/unnecessary_to_owned.rs b/tests/ui/unnecessary_to_owned.rs index 7eb53df39e5b7..10588beb263b6 100644 --- a/tests/ui/unnecessary_to_owned.rs +++ b/tests/ui/unnecessary_to_owned.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(clippy::needless_borrow, clippy::ptr_arg)] #![warn(clippy::unnecessary_to_owned)] diff --git a/tests/ui/unnecessary_unsafety_doc.rs b/tests/ui/unnecessary_unsafety_doc.rs index 431093ab36969..373b18470f695 100644 --- a/tests/ui/unnecessary_unsafety_doc.rs +++ b/tests/ui/unnecessary_unsafety_doc.rs @@ -1,4 +1,4 @@ -// aux-build:proc_macros.rs +//@aux-build:proc_macros.rs #![allow(clippy::let_unit_value)] #![warn(clippy::unnecessary_safety_doc)] diff --git a/tests/ui/unneeded_wildcard_pattern.fixed b/tests/ui/unneeded_wildcard_pattern.fixed index 12c3461c95579..16c2de760e55f 100644 --- a/tests/ui/unneeded_wildcard_pattern.fixed +++ b/tests/ui/unneeded_wildcard_pattern.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(stmt_expr_attributes)] #![deny(clippy::unneeded_wildcard_pattern)] diff --git a/tests/ui/unneeded_wildcard_pattern.rs b/tests/ui/unneeded_wildcard_pattern.rs index 4ac01d5d23b04..9d9eae1d90330 100644 --- a/tests/ui/unneeded_wildcard_pattern.rs +++ b/tests/ui/unneeded_wildcard_pattern.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(stmt_expr_attributes)] #![deny(clippy::unneeded_wildcard_pattern)] diff --git a/tests/ui/unnested_or_patterns.fixed b/tests/ui/unnested_or_patterns.fixed index 0a8e7b34dfa4f..8ec35ba4eea7e 100644 --- a/tests/ui/unnested_or_patterns.fixed +++ b/tests/ui/unnested_or_patterns.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(box_patterns)] #![warn(clippy::unnested_or_patterns)] diff --git a/tests/ui/unnested_or_patterns.rs b/tests/ui/unnested_or_patterns.rs index 2c454adfe89db..efdb91b2402b7 100644 --- a/tests/ui/unnested_or_patterns.rs +++ b/tests/ui/unnested_or_patterns.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(box_patterns)] #![warn(clippy::unnested_or_patterns)] diff --git a/tests/ui/unnested_or_patterns2.fixed b/tests/ui/unnested_or_patterns2.fixed index d3539d798157b..de40e93674713 100644 --- a/tests/ui/unnested_or_patterns2.fixed +++ b/tests/ui/unnested_or_patterns2.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(box_patterns)] #![warn(clippy::unnested_or_patterns)] diff --git a/tests/ui/unnested_or_patterns2.rs b/tests/ui/unnested_or_patterns2.rs index 9cea5cdea6997..87f66d26c4678 100644 --- a/tests/ui/unnested_or_patterns2.rs +++ b/tests/ui/unnested_or_patterns2.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(box_patterns)] #![warn(clippy::unnested_or_patterns)] diff --git a/tests/ui/unreadable_literal.fixed b/tests/ui/unreadable_literal.fixed index 13e5feb19263e..f5e87648a2319 100644 --- a/tests/ui/unreadable_literal.fixed +++ b/tests/ui/unreadable_literal.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::unreadable_literal)] #![allow(unused_tuple_struct_fields)] diff --git a/tests/ui/unreadable_literal.rs b/tests/ui/unreadable_literal.rs index 82f04e7ced527..426bdf7d7328b 100644 --- a/tests/ui/unreadable_literal.rs +++ b/tests/ui/unreadable_literal.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::unreadable_literal)] #![allow(unused_tuple_struct_fields)] diff --git a/tests/ui/unseparated_prefix_literals.fixed b/tests/ui/unseparated_prefix_literals.fixed index f0c2ba7ccdfa0..b6241612d9da9 100644 --- a/tests/ui/unseparated_prefix_literals.fixed +++ b/tests/ui/unseparated_prefix_literals.fixed @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:proc_macro_derive.rs +//@run-rustfix +//@aux-build:proc_macro_derive.rs #![warn(clippy::unseparated_literal_suffix)] #![allow(dead_code)] diff --git a/tests/ui/unseparated_prefix_literals.rs b/tests/ui/unseparated_prefix_literals.rs index f44880b414756..ae583f4bde379 100644 --- a/tests/ui/unseparated_prefix_literals.rs +++ b/tests/ui/unseparated_prefix_literals.rs @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:proc_macro_derive.rs +//@run-rustfix +//@aux-build:proc_macro_derive.rs #![warn(clippy::unseparated_literal_suffix)] #![allow(dead_code)] diff --git a/tests/ui/unused_rounding.fixed b/tests/ui/unused_rounding.fixed index f6f734c05ed59..f02b55502a060 100644 --- a/tests/ui/unused_rounding.fixed +++ b/tests/ui/unused_rounding.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::unused_rounding)] fn main() { diff --git a/tests/ui/unused_rounding.rs b/tests/ui/unused_rounding.rs index a0267d8144aab..c7bd4906d0b73 100644 --- a/tests/ui/unused_rounding.rs +++ b/tests/ui/unused_rounding.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::unused_rounding)] fn main() { diff --git a/tests/ui/unused_unit.fixed b/tests/ui/unused_unit.fixed index 3dd640b86f0b3..7b8f7847dbf64 100644 --- a/tests/ui/unused_unit.fixed +++ b/tests/ui/unused_unit.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix // The output for humans should just highlight the whole span without showing // the suggested replacement, but we also want to test that suggested diff --git a/tests/ui/unused_unit.rs b/tests/ui/unused_unit.rs index bddecf06fb76d..fdde1ecadf0bb 100644 --- a/tests/ui/unused_unit.rs +++ b/tests/ui/unused_unit.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix // The output for humans should just highlight the whole span without showing // the suggested replacement, but we also want to test that suggested diff --git a/tests/ui/unwrap_or_else_default.fixed b/tests/ui/unwrap_or_else_default.fixed index 84f779569ff9d..59a0ca3f192fc 100644 --- a/tests/ui/unwrap_or_else_default.fixed +++ b/tests/ui/unwrap_or_else_default.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::unwrap_or_else_default)] #![allow(dead_code)] diff --git a/tests/ui/unwrap_or_else_default.rs b/tests/ui/unwrap_or_else_default.rs index 1735bd5808e5a..97cafa336eda6 100644 --- a/tests/ui/unwrap_or_else_default.rs +++ b/tests/ui/unwrap_or_else_default.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::unwrap_or_else_default)] #![allow(dead_code)] diff --git a/tests/ui/use_self.fixed b/tests/ui/use_self.fixed index 3ac6217312a8c..89ea14759b7db 100644 --- a/tests/ui/use_self.fixed +++ b/tests/ui/use_self.fixed @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:proc_macro_derive.rs +//@run-rustfix +//@aux-build:proc_macro_derive.rs #![warn(clippy::use_self)] #![allow(dead_code, unreachable_code)] diff --git a/tests/ui/use_self.rs b/tests/ui/use_self.rs index 9dc5d1e3f9b23..49e5bcb7ed961 100644 --- a/tests/ui/use_self.rs +++ b/tests/ui/use_self.rs @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:proc_macro_derive.rs +//@run-rustfix +//@aux-build:proc_macro_derive.rs #![warn(clippy::use_self)] #![allow(dead_code, unreachable_code)] diff --git a/tests/ui/use_self_trait.fixed b/tests/ui/use_self_trait.fixed index 4e779308d0241..4623aeeb0eb23 100644 --- a/tests/ui/use_self_trait.fixed +++ b/tests/ui/use_self_trait.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::use_self)] #![allow(dead_code)] diff --git a/tests/ui/use_self_trait.rs b/tests/ui/use_self_trait.rs index 325dc73b21ea9..d7d76dd96233c 100644 --- a/tests/ui/use_self_trait.rs +++ b/tests/ui/use_self_trait.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::use_self)] #![allow(dead_code)] diff --git a/tests/ui/used_underscore_binding.rs b/tests/ui/used_underscore_binding.rs index 8c29e15b14592..c672eff1c2710 100644 --- a/tests/ui/used_underscore_binding.rs +++ b/tests/ui/used_underscore_binding.rs @@ -1,4 +1,4 @@ -// aux-build:proc_macro_derive.rs +//@aux-build:proc_macro_derive.rs #![feature(rustc_private)] #![warn(clippy::all)] #![warn(clippy::used_underscore_binding)] diff --git a/tests/ui/useless_asref.fixed b/tests/ui/useless_asref.fixed index 38e4b9201e6de..490d36ae6d692 100644 --- a/tests/ui/useless_asref.fixed +++ b/tests/ui/useless_asref.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![deny(clippy::useless_asref)] #![allow(clippy::explicit_auto_deref, clippy::uninlined_format_args)] diff --git a/tests/ui/useless_asref.rs b/tests/ui/useless_asref.rs index f1e83f9d396cd..f2681af924da4 100644 --- a/tests/ui/useless_asref.rs +++ b/tests/ui/useless_asref.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![deny(clippy::useless_asref)] #![allow(clippy::explicit_auto_deref, clippy::uninlined_format_args)] diff --git a/tests/ui/useless_attribute.fixed b/tests/ui/useless_attribute.fixed index 871e4fb5c3a9f..de6660c95e6e9 100644 --- a/tests/ui/useless_attribute.fixed +++ b/tests/ui/useless_attribute.fixed @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:proc_macro_derive.rs +//@run-rustfix +//@aux-build:proc_macro_derive.rs #![allow(unused)] #![warn(clippy::useless_attribute)] diff --git a/tests/ui/useless_attribute.rs b/tests/ui/useless_attribute.rs index cb50736ba395a..8de4331e8a690 100644 --- a/tests/ui/useless_attribute.rs +++ b/tests/ui/useless_attribute.rs @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:proc_macro_derive.rs +//@run-rustfix +//@aux-build:proc_macro_derive.rs #![allow(unused)] #![warn(clippy::useless_attribute)] diff --git a/tests/ui/useless_conversion.fixed b/tests/ui/useless_conversion.fixed index 94b206d8e58f6..01eb6c5b080dd 100644 --- a/tests/ui/useless_conversion.fixed +++ b/tests/ui/useless_conversion.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![deny(clippy::useless_conversion)] #![allow(clippy::unnecessary_wraps)] diff --git a/tests/ui/useless_conversion.rs b/tests/ui/useless_conversion.rs index c7ae927941bf1..34b43a6299b2f 100644 --- a/tests/ui/useless_conversion.rs +++ b/tests/ui/useless_conversion.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![deny(clippy::useless_conversion)] #![allow(clippy::unnecessary_wraps)] diff --git a/tests/ui/vec.fixed b/tests/ui/vec.fixed index 2518d80491500..d77a4dd8e0b00 100644 --- a/tests/ui/vec.fixed +++ b/tests/ui/vec.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::useless_vec)] #![allow(clippy::nonstandard_macro_braces, clippy::uninlined_format_args)] diff --git a/tests/ui/vec.rs b/tests/ui/vec.rs index e1492e2f3aef0..dfed3a29a03e1 100644 --- a/tests/ui/vec.rs +++ b/tests/ui/vec.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::useless_vec)] #![allow(clippy::nonstandard_macro_braces, clippy::uninlined_format_args)] diff --git a/tests/ui/vec_box_sized.fixed b/tests/ui/vec_box_sized.fixed index a40d91fdb18ac..0d0f710b558b8 100644 --- a/tests/ui/vec_box_sized.fixed +++ b/tests/ui/vec_box_sized.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code)] diff --git a/tests/ui/vec_box_sized.rs b/tests/ui/vec_box_sized.rs index 843bbb64e7190..fd3a7543ee1a9 100644 --- a/tests/ui/vec_box_sized.rs +++ b/tests/ui/vec_box_sized.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code)] diff --git a/tests/ui/while_let_on_iterator.fixed b/tests/ui/while_let_on_iterator.fixed index 5afa0a89f82c8..c2f216a8911c4 100644 --- a/tests/ui/while_let_on_iterator.fixed +++ b/tests/ui/while_let_on_iterator.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::while_let_on_iterator)] #![allow(dead_code, unreachable_code, unused_mut)] #![allow( diff --git a/tests/ui/while_let_on_iterator.rs b/tests/ui/while_let_on_iterator.rs index 3de586c9d8fd4..971bd5f0c4a86 100644 --- a/tests/ui/while_let_on_iterator.rs +++ b/tests/ui/while_let_on_iterator.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::while_let_on_iterator)] #![allow(dead_code, unreachable_code, unused_mut)] #![allow( diff --git a/tests/ui/wildcard_enum_match_arm.fixed b/tests/ui/wildcard_enum_match_arm.fixed index 293bf75a71762..ccb40acfbe1bb 100644 --- a/tests/ui/wildcard_enum_match_arm.fixed +++ b/tests/ui/wildcard_enum_match_arm.fixed @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:non-exhaustive-enum.rs +//@run-rustfix +//@aux-build:non-exhaustive-enum.rs #![deny(clippy::wildcard_enum_match_arm)] #![allow(dead_code, unreachable_code, unused_variables)] #![allow( diff --git a/tests/ui/wildcard_enum_match_arm.rs b/tests/ui/wildcard_enum_match_arm.rs index decd86165f3a4..3ce00b021a530 100644 --- a/tests/ui/wildcard_enum_match_arm.rs +++ b/tests/ui/wildcard_enum_match_arm.rs @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:non-exhaustive-enum.rs +//@run-rustfix +//@aux-build:non-exhaustive-enum.rs #![deny(clippy::wildcard_enum_match_arm)] #![allow(dead_code, unreachable_code, unused_variables)] #![allow( diff --git a/tests/ui/wildcard_imports.fixed b/tests/ui/wildcard_imports.fixed index 0baec6f0b641e..bd845361fa89d 100644 --- a/tests/ui/wildcard_imports.fixed +++ b/tests/ui/wildcard_imports.fixed @@ -1,6 +1,6 @@ -// edition:2015 -// run-rustfix -// aux-build:wildcard_imports_helper.rs +//@edition:2015 +//@run-rustfix +//@aux-build:wildcard_imports_helper.rs // the 2015 edition here is needed because edition 2018 changed the module system // (see https://doc.rust-lang.org/edition-guide/rust-2018/path-changes.html) which means the lint diff --git a/tests/ui/wildcard_imports.rs b/tests/ui/wildcard_imports.rs index db591d56ab4d1..fb51f7bdfcc6b 100644 --- a/tests/ui/wildcard_imports.rs +++ b/tests/ui/wildcard_imports.rs @@ -1,6 +1,6 @@ -// edition:2015 -// run-rustfix -// aux-build:wildcard_imports_helper.rs +//@edition:2015 +//@run-rustfix +//@aux-build:wildcard_imports_helper.rs // the 2015 edition here is needed because edition 2018 changed the module system // (see https://doc.rust-lang.org/edition-guide/rust-2018/path-changes.html) which means the lint diff --git a/tests/ui/wildcard_imports_2021.edition2018.fixed b/tests/ui/wildcard_imports_2021.edition2018.fixed index 6d534a10edcd1..3aea013fb3a76 100644 --- a/tests/ui/wildcard_imports_2021.edition2018.fixed +++ b/tests/ui/wildcard_imports_2021.edition2018.fixed @@ -1,8 +1,8 @@ -// revisions: edition2018 edition2021 -//[edition2018] edition:2018 -//[edition2021] edition:2021 -// run-rustfix -// aux-build:wildcard_imports_helper.rs +//@revisions: edition2018 edition2021 +//@[edition2018] edition:2018 +//@[edition2021] edition:2021 +//@run-rustfix +//@aux-build:wildcard_imports_helper.rs #![warn(clippy::wildcard_imports)] #![allow(unused, clippy::unnecessary_wraps, clippy::let_unit_value)] diff --git a/tests/ui/wildcard_imports_2021.edition2021.fixed b/tests/ui/wildcard_imports_2021.edition2021.fixed index 6d534a10edcd1..3aea013fb3a76 100644 --- a/tests/ui/wildcard_imports_2021.edition2021.fixed +++ b/tests/ui/wildcard_imports_2021.edition2021.fixed @@ -1,8 +1,8 @@ -// revisions: edition2018 edition2021 -//[edition2018] edition:2018 -//[edition2021] edition:2021 -// run-rustfix -// aux-build:wildcard_imports_helper.rs +//@revisions: edition2018 edition2021 +//@[edition2018] edition:2018 +//@[edition2021] edition:2021 +//@run-rustfix +//@aux-build:wildcard_imports_helper.rs #![warn(clippy::wildcard_imports)] #![allow(unused, clippy::unnecessary_wraps, clippy::let_unit_value)] diff --git a/tests/ui/wildcard_imports_2021.rs b/tests/ui/wildcard_imports_2021.rs index b5ed58e68136f..40c2d07527d1e 100644 --- a/tests/ui/wildcard_imports_2021.rs +++ b/tests/ui/wildcard_imports_2021.rs @@ -1,8 +1,8 @@ -// revisions: edition2018 edition2021 -//[edition2018] edition:2018 -//[edition2021] edition:2021 -// run-rustfix -// aux-build:wildcard_imports_helper.rs +//@revisions: edition2018 edition2021 +//@[edition2018] edition:2018 +//@[edition2021] edition:2021 +//@run-rustfix +//@aux-build:wildcard_imports_helper.rs #![warn(clippy::wildcard_imports)] #![allow(unused, clippy::unnecessary_wraps, clippy::let_unit_value)] diff --git a/tests/ui/wildcard_imports_2021.stderr b/tests/ui/wildcard_imports_2021.stderr deleted file mode 100644 index 92f6d31530fa8..0000000000000 --- a/tests/ui/wildcard_imports_2021.stderr +++ /dev/null @@ -1,132 +0,0 @@ -error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:9:5 - | -LL | use crate::fn_mod::*; - | ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo` - | - = note: `-D clippy::wildcard-imports` implied by `-D warnings` - -error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:10:5 - | -LL | use crate::mod_mod::*; - | ^^^^^^^^^^^^^^^^^ help: try: `crate::mod_mod::inner_mod` - -error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:11:5 - | -LL | use crate::multi_fn_mod::*; - | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::multi_fn_mod::{multi_bar, multi_foo, multi_inner_mod}` - -error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:12:5 - | -LL | use crate::struct_mod::*; - | ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::struct_mod::{A, inner_struct_mod}` - -error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:15:5 - | -LL | use wildcard_imports_helper::inner::inner_for_self_import::*; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::inner::inner_for_self_import::inner_extern_bar` - -error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:17:5 - | -LL | use wildcard_imports_helper::*; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}` - -error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:87:13 - | -LL | use crate::fn_mod::*; - | ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo` - -error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:93:75 - | -LL | use wildcard_imports_helper::inner::inner_for_self_import::{self, *}; - | ^ help: try: `inner_extern_foo` - -error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:94:13 - | -LL | use wildcard_imports_helper::*; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}` - -error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:105:20 - | -LL | use self::{inner::*, inner2::*}; - | ^^^^^^^^ help: try: `inner::inner_foo` - -error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:105:30 - | -LL | use self::{inner::*, inner2::*}; - | ^^^^^^^^^ help: try: `inner2::inner_bar` - -error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:112:13 - | -LL | use wildcard_imports_helper::*; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported}` - -error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:141:9 - | -LL | use crate::in_fn_test::*; - | ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::in_fn_test::{ExportedEnum, ExportedStruct, exported}` - -error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:150:9 - | -LL | use crate:: in_fn_test:: * ; - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate:: in_fn_test::exported` - -error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:151:9 - | -LL | use crate:: fn_mod:: - | _________^ -LL | | *; - | |_________^ help: try: `crate:: fn_mod::foo` - -error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:162:13 - | -LL | use super::*; - | ^^^^^^^^ help: try: `super::foofoo` - -error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:197:17 - | -LL | use super::*; - | ^^^^^^^^ help: try: `super::insidefoo` - -error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:205:13 - | -LL | use crate::super_imports::*; - | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::super_imports::foofoo` - -error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:214:17 - | -LL | use super::super::*; - | ^^^^^^^^^^^^^^^ help: try: `super::super::foofoo` - -error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:223:13 - | -LL | use super::super::super_imports::*; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `super::super::super_imports::foofoo` - -error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:231:13 - | -LL | use super::*; - | ^^^^^^^^ help: try: `super::foofoo` - -error: aborting due to 21 previous errors - diff --git a/tests/ui/write_with_newline.rs b/tests/ui/write_with_newline.rs index b79364c8758c5..35bd9e7f3a077 100644 --- a/tests/ui/write_with_newline.rs +++ b/tests/ui/write_with_newline.rs @@ -1,5 +1,5 @@ // FIXME: Ideally these suggestions would be fixed via rustfix. Blocked by rust-lang/rust#53934 -// // run-rustfix +// #![allow(clippy::write_literal)] #![warn(clippy::write_with_newline)] @@ -54,7 +54,7 @@ fn main() { // Don't warn on CRLF (#4208) write!(v, "\r\n"); write!(v, "foo\r\n"); - write!(v, "\\r\n"); //~ ERROR + write!(v, "\\r\n"); write!(v, "foo\rbar\n"); // Ignore expanded format strings diff --git a/tests/ui/write_with_newline.stderr b/tests/ui/write_with_newline.stderr index 2baaea166d8ef..9035275b29db4 100644 --- a/tests/ui/write_with_newline.stderr +++ b/tests/ui/write_with_newline.stderr @@ -106,13 +106,13 @@ LL ~ v error: using `write!()` with a format string that ends in a single newline --> $DIR/write_with_newline.rs:57:5 | -LL | write!(v, "/r/n"); //~ ERROR +LL | write!(v, "/r/n"); | ^^^^^^^^^^^^^^^^^^ | help: use `writeln!` instead | -LL - write!(v, "/r/n"); //~ ERROR -LL + writeln!(v, "/r"); //~ ERROR +LL - write!(v, "/r/n"); +LL + writeln!(v, "/r"); | error: aborting due to 9 previous errors diff --git a/tests/ui/writeln_empty_string.fixed b/tests/ui/writeln_empty_string.fixed index e7d94acd130d6..45dedd9ead6a8 100644 --- a/tests/ui/writeln_empty_string.fixed +++ b/tests/ui/writeln_empty_string.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused_must_use)] #![warn(clippy::writeln_empty_string)] diff --git a/tests/ui/writeln_empty_string.rs b/tests/ui/writeln_empty_string.rs index 662c62f02116e..3b9f51a15d2f7 100644 --- a/tests/ui/writeln_empty_string.rs +++ b/tests/ui/writeln_empty_string.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused_must_use)] #![warn(clippy::writeln_empty_string)] diff --git a/tests/ui/zero_ptr.fixed b/tests/ui/zero_ptr.fixed index 489aa4121a3a9..bed38ecafc7e9 100644 --- a/tests/ui/zero_ptr.fixed +++ b/tests/ui/zero_ptr.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix pub fn foo(_const: *const f32, _mut: *mut i64) {} fn main() { diff --git a/tests/ui/zero_ptr.rs b/tests/ui/zero_ptr.rs index c3b55ef9ebd90..b7b778915a8f4 100644 --- a/tests/ui/zero_ptr.rs +++ b/tests/ui/zero_ptr.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix pub fn foo(_const: *const f32, _mut: *mut i64) {} fn main() { diff --git a/tests/ui/zero_ptr_no_std.fixed b/tests/ui/zero_ptr_no_std.fixed index 8906c776977a8..7afd80ccaca61 100644 --- a/tests/ui/zero_ptr_no_std.fixed +++ b/tests/ui/zero_ptr_no_std.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(lang_items, start, libc)] #![no_std] diff --git a/tests/ui/zero_ptr_no_std.rs b/tests/ui/zero_ptr_no_std.rs index 379c1b18d2992..05a0587d22bcb 100644 --- a/tests/ui/zero_ptr_no_std.rs +++ b/tests/ui/zero_ptr_no_std.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(lang_items, start, libc)] #![no_std] From 69da902f417547831009a4957037cd21b5aab678 Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Sun, 26 Feb 2023 15:44:04 +0100 Subject: [PATCH 36/86] Detect if expressions with boolean assignments to the same target --- CHANGELOG.md | 1 + clippy_lints/src/declared_lints.rs | 1 + clippy_lints/src/needless_bool.rs | 71 ++++++++++++++++++++++++++-- tests/ui/needless_bool_assign.fixed | 33 +++++++++++++ tests/ui/needless_bool_assign.rs | 45 ++++++++++++++++++ tests/ui/needless_bool_assign.stderr | 53 +++++++++++++++++++++ 6 files changed, 201 insertions(+), 3 deletions(-) create mode 100644 tests/ui/needless_bool_assign.fixed create mode 100644 tests/ui/needless_bool_assign.rs create mode 100644 tests/ui/needless_bool_assign.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 10dd28a8f6af2..f3f43830f56e6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4863,6 +4863,7 @@ Released 2018-09-13 [`needless_arbitrary_self_type`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_arbitrary_self_type [`needless_bitwise_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_bitwise_bool [`needless_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_bool +[`needless_bool_assign`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_bool_assign [`needless_borrow`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow [`needless_borrowed_reference`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrowed_reference [`needless_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_collect diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index f24dab6278095..9633f0d55f787 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -445,6 +445,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE_INFO, crate::needless_bool::BOOL_COMPARISON_INFO, crate::needless_bool::NEEDLESS_BOOL_INFO, + crate::needless_bool::NEEDLESS_BOOL_ASSIGN_INFO, crate::needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE_INFO, crate::needless_continue::NEEDLESS_CONTINUE_INFO, crate::needless_for_each::NEEDLESS_FOR_EACH_INFO, diff --git a/clippy_lints/src/needless_bool.rs b/clippy_lints/src/needless_bool.rs index c87059bf61de3..bd2e39e6ed608 100644 --- a/clippy_lints/src/needless_bool.rs +++ b/clippy_lints/src/needless_bool.rs @@ -3,10 +3,12 @@ //! This lint is **warn** by default use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; -use clippy_utils::higher; use clippy_utils::source::snippet_with_applicability; use clippy_utils::sugg::Sugg; -use clippy_utils::{get_parent_node, is_else_clause, is_expn_of, peel_blocks, peel_blocks_with_stmt}; +use clippy_utils::{ + get_parent_node, is_else_clause, is_expn_of, peel_blocks, peel_blocks_with_stmt, span_extract_comment, +}; +use clippy_utils::{higher, SpanlessEq}; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Block, Expr, ExprKind, HirId, Node, UnOp}; @@ -77,7 +79,39 @@ declare_clippy_lint! { "comparing a variable to a boolean, e.g., `if x == true` or `if x != true`" } -declare_lint_pass!(NeedlessBool => [NEEDLESS_BOOL]); +declare_clippy_lint! { + /// ### What it does + /// Checks for expressions of the form `if c { x = true } else { x = false }` + /// (or vice versa) and suggest assigning the variable directly from the + /// condition. + /// + /// ### Why is this bad? + /// Redundant code. + /// + /// ### Example + /// ```rust,ignore + /// # fn must_keep(x: i32, y: i32) -> bool { x == y } + /// # let x = 32; let y = 10; + /// # let mut skip: bool; + /// if must_keep(x, y) { + /// skip = false; + /// } else { + /// skip = true; + /// } + /// ``` + /// Use instead: + /// ```rust,ignore + /// # fn must_keep(x: i32, y: i32) -> bool { x == y } + /// # let x = 32; let y = 10; + /// # let mut skip: bool; + /// skip = !must_keep(x, y); + /// ``` + #[clippy::version = "1.69.0"] + pub NEEDLESS_BOOL_ASSIGN, + complexity, + "setting the same boolean variable in both branches of an if-statement" +} +declare_lint_pass!(NeedlessBool => [NEEDLESS_BOOL, NEEDLESS_BOOL_ASSIGN]); fn condition_needs_parentheses(e: &Expr<'_>) -> bool { let mut inner = e; @@ -173,6 +207,29 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBool { _ => (), } } + if let Some((lhs_a, a)) = fetch_assign(then) && + let Some((lhs_b, b)) = fetch_assign(r#else) && + SpanlessEq::new(cx).eq_expr(lhs_a, lhs_b) && + span_extract_comment(cx.tcx.sess.source_map(), e.span).is_empty() + { + let mut applicability = Applicability::MachineApplicable; + let cond = Sugg::hir_with_applicability(cx, cond, "..", &mut applicability); + let lhs = snippet_with_applicability(cx, lhs_a.span, "..", &mut applicability); + let sugg = if a == b { + format!("{cond}; {lhs} = {a:?};") + } else { + format!("{lhs} = {};", if a { cond } else { !cond }) + }; + span_lint_and_sugg( + cx, + NEEDLESS_BOOL_ASSIGN, + e.span, + "this if-then-else expression assigns a bool literal", + "you can reduce it to", + sugg, + applicability + ); + } } } } @@ -376,3 +433,11 @@ fn fetch_bool_expr(expr: &Expr<'_>) -> Option { } None } + +fn fetch_assign<'tcx>(expr: &'tcx Expr<'tcx>) -> Option<(&'tcx Expr<'tcx>, bool)> { + if let ExprKind::Assign(lhs, rhs, _) = peel_blocks_with_stmt(expr).kind { + fetch_bool_expr(rhs).map(|b| (lhs, b)) + } else { + None + } +} diff --git a/tests/ui/needless_bool_assign.fixed b/tests/ui/needless_bool_assign.fixed new file mode 100644 index 0000000000000..3ed31d4d711fa --- /dev/null +++ b/tests/ui/needless_bool_assign.fixed @@ -0,0 +1,33 @@ +//@run-rustfix + +#![allow(unused)] +#![warn(clippy::needless_bool_assign)] + +fn random() -> bool { + true +} + +fn main() { + struct Data { + field: bool, + }; + let mut a = Data { field: false }; + a.field = random() && random(); + a.field = !(random() && random()); + // Do not lint… + if random() { + a.field = false; + } else { + // …to avoid losing this comment + a.field = true + } + // This one also triggers lint `clippy::if_same_then_else` + // which does not suggest a rewrite. + random(); a.field = true; + let mut b = false; + if random() { + a.field = false; + } else { + b = true; + } +} diff --git a/tests/ui/needless_bool_assign.rs b/tests/ui/needless_bool_assign.rs new file mode 100644 index 0000000000000..efaeb67fa45de --- /dev/null +++ b/tests/ui/needless_bool_assign.rs @@ -0,0 +1,45 @@ +//@run-rustfix + +#![allow(unused)] +#![warn(clippy::needless_bool_assign)] + +fn random() -> bool { + true +} + +fn main() { + struct Data { + field: bool, + }; + let mut a = Data { field: false }; + if random() && random() { + a.field = true; + } else { + a.field = false + } + if random() && random() { + a.field = false; + } else { + a.field = true + } + // Do not lint… + if random() { + a.field = false; + } else { + // …to avoid losing this comment + a.field = true + } + // This one also triggers lint `clippy::if_same_then_else` + // which does not suggest a rewrite. + if random() { + a.field = true; + } else { + a.field = true; + } + let mut b = false; + if random() { + a.field = false; + } else { + b = true; + } +} diff --git a/tests/ui/needless_bool_assign.stderr b/tests/ui/needless_bool_assign.stderr new file mode 100644 index 0000000000000..601bbed5493b9 --- /dev/null +++ b/tests/ui/needless_bool_assign.stderr @@ -0,0 +1,53 @@ +error: this if-then-else expression assigns a bool literal + --> $DIR/needless_bool_assign.rs:15:5 + | +LL | / if random() && random() { +LL | | a.field = true; +LL | | } else { +LL | | a.field = false +LL | | } + | |_____^ help: you can reduce it to: `a.field = random() && random();` + | + = note: `-D clippy::needless-bool-assign` implied by `-D warnings` + +error: this if-then-else expression assigns a bool literal + --> $DIR/needless_bool_assign.rs:20:5 + | +LL | / if random() && random() { +LL | | a.field = false; +LL | | } else { +LL | | a.field = true +LL | | } + | |_____^ help: you can reduce it to: `a.field = !(random() && random());` + +error: this if-then-else expression assigns a bool literal + --> $DIR/needless_bool_assign.rs:34:5 + | +LL | / if random() { +LL | | a.field = true; +LL | | } else { +LL | | a.field = true; +LL | | } + | |_____^ help: you can reduce it to: `random(); a.field = true;` + +error: this `if` has identical blocks + --> $DIR/needless_bool_assign.rs:34:17 + | +LL | if random() { + | _________________^ +LL | | a.field = true; +LL | | } else { + | |_____^ + | +note: same as this + --> $DIR/needless_bool_assign.rs:36:12 + | +LL | } else { + | ____________^ +LL | | a.field = true; +LL | | } + | |_____^ + = note: `#[deny(clippy::if_same_then_else)]` on by default + +error: aborting due to 4 previous errors + From 572eecd267cd89086820ea72f403aba09b6268a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Sun, 23 Apr 2023 15:11:31 +0200 Subject: [PATCH 37/86] split test into 2 --- tests/ui/crashes/ice-10645.rs | 7 +++++++ tests/ui/crashes/{ice-5207.stderr => ice-10645.stderr} | 4 ++-- tests/ui/crashes/ice-5207.rs | 4 ---- 3 files changed, 9 insertions(+), 6 deletions(-) create mode 100644 tests/ui/crashes/ice-10645.rs rename tests/ui/crashes/{ice-5207.stderr => ice-10645.stderr} (89%) diff --git a/tests/ui/crashes/ice-10645.rs b/tests/ui/crashes/ice-10645.rs new file mode 100644 index 0000000000000..4d8698d383ba5 --- /dev/null +++ b/tests/ui/crashes/ice-10645.rs @@ -0,0 +1,7 @@ +// compile-flags: --cap-lints=warn +// https://github.com/rust-lang/rust-clippy/issues/10645 + +#![warn(clippy::future_not_send)] +pub async fn bar<'a, T: 'a>(_: T) {} + +fn main() {} diff --git a/tests/ui/crashes/ice-5207.stderr b/tests/ui/crashes/ice-10645.stderr similarity index 89% rename from tests/ui/crashes/ice-5207.stderr rename to tests/ui/crashes/ice-10645.stderr index 59146c23e0d57..fc084e30d7fe8 100644 --- a/tests/ui/crashes/ice-5207.stderr +++ b/tests/ui/crashes/ice-10645.stderr @@ -1,11 +1,11 @@ error: future cannot be sent between threads safely - --> $DIR/ice-5207.rs:6:35 + --> $DIR/ice-10645.rs:5:35 | LL | pub async fn bar<'a, T: 'a>(_: T) {} | ^ future returned by `bar` is not `Send` | note: captured value is not `Send` - --> $DIR/ice-5207.rs:6:29 + --> $DIR/ice-10645.rs:5:29 | LL | pub async fn bar<'a, T: 'a>(_: T) {} | ^ has type `T` which is not `Send` diff --git a/tests/ui/crashes/ice-5207.rs b/tests/ui/crashes/ice-5207.rs index 893c15f5d731c..0df8b88fea2f9 100644 --- a/tests/ui/crashes/ice-5207.rs +++ b/tests/ui/crashes/ice-5207.rs @@ -1,8 +1,4 @@ -// compile-flags: --cap-lints=warn -// ^ for https://github.com/rust-lang/rust-clippy/issues/10645 - // Regression test for https://github.com/rust-lang/rust-clippy/issues/5207 -#![warn(clippy::future_not_send)] pub async fn bar<'a, T: 'a>(_: T) {} fn main() {} From 022baa5ce360d4d90b5ab7141ba1607112fa00a6 Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Sun, 23 Apr 2023 14:25:19 +0000 Subject: [PATCH 38/86] Remove check for `lib.register_*` and `src/docs*` in `cargo dev update_lints` This reverts commit 22d435b26627c1085c5b761846ca08870288794f. --- clippy_dev/src/update_lints.rs | 54 ---------------------------------- 1 file changed, 54 deletions(-) diff --git a/clippy_dev/src/update_lints.rs b/clippy_dev/src/update_lints.rs index dd90a38f7572d..7213c9dfede99 100644 --- a/clippy_dev/src/update_lints.rs +++ b/clippy_dev/src/update_lints.rs @@ -36,60 +36,6 @@ pub enum UpdateMode { pub fn update(update_mode: UpdateMode) { let (lints, deprecated_lints, renamed_lints) = gather_all(); generate_lint_files(update_mode, &lints, &deprecated_lints, &renamed_lints); - remove_old_files(update_mode); -} - -/// Remove files no longer needed after -/// that may be reintroduced unintentionally -/// -/// FIXME: This is a temporary measure that should be removed when there are no more PRs that -/// include the stray files -fn remove_old_files(update_mode: UpdateMode) { - let mut failed = false; - let mut remove_file = |path: &Path| match update_mode { - UpdateMode::Check => { - if path.exists() { - failed = true; - println!("unexpected file: {}", path.display()); - } - }, - UpdateMode::Change => { - if fs::remove_file(path).is_ok() { - println!("removed file: {}", path.display()); - } - }, - }; - - let files = [ - "clippy_lints/src/lib.register_all.rs", - "clippy_lints/src/lib.register_cargo.rs", - "clippy_lints/src/lib.register_complexity.rs", - "clippy_lints/src/lib.register_correctness.rs", - "clippy_lints/src/lib.register_internal.rs", - "clippy_lints/src/lib.register_lints.rs", - "clippy_lints/src/lib.register_nursery.rs", - "clippy_lints/src/lib.register_pedantic.rs", - "clippy_lints/src/lib.register_perf.rs", - "clippy_lints/src/lib.register_restriction.rs", - "clippy_lints/src/lib.register_style.rs", - "clippy_lints/src/lib.register_suspicious.rs", - "src/docs.rs", - ]; - - for file in files { - remove_file(Path::new(file)); - } - - if let Ok(docs_dir) = fs::read_dir("src/docs") { - for doc_file in docs_dir { - let path = doc_file.unwrap().path(); - remove_file(&path); - } - } - - if failed { - exit_with_failure(); - } } fn generate_lint_files( From d2061faf9e7774bf8bc3ac6842cd2a095e1f2597 Mon Sep 17 00:00:00 2001 From: Josh Soref <2119212+jsoref@users.noreply.github.com> Date: Thu, 13 Apr 2023 17:59:01 -0400 Subject: [PATCH 39/86] Spelling * applying * binding * complex * constituent * demonstrate * desugaring * exact * expression * for * functionalities * github * implementation * infers * multiple conflicting traits * mutable * necessarily * nightly * nonexistent * optional * parameter * reassignments * resources * substitution * suggestion * that * that array is * using the Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> --- book/src/development/proposals/syntax-tree-patterns.md | 2 +- clippy_lints/src/casts/mod.rs | 2 +- clippy_lints/src/copies.rs | 2 +- clippy_lints/src/formatting.rs | 2 +- clippy_lints/src/from_over_into.rs | 2 +- clippy_lints/src/functions/misnamed_getters.rs | 2 +- clippy_lints/src/functions/mod.rs | 2 +- clippy_lints/src/large_futures.rs | 2 +- clippy_lints/src/loops/manual_memcpy.rs | 2 +- clippy_lints/src/manual_assert.rs | 2 +- clippy_lints/src/manual_let_else.rs | 2 +- clippy_lints/src/manual_retain.rs | 2 +- clippy_lints/src/missing_trait_methods.rs | 2 +- clippy_lints/src/slow_vector_initialization.rs | 2 +- clippy_lints/src/trailing_empty_array.rs | 2 +- clippy_lints/src/types/mod.rs | 4 ++-- clippy_lints/src/unnecessary_box_returns.rs | 2 +- clippy_utils/src/ty.rs | 4 ++-- lintcheck/src/main.rs | 2 +- tests/ui/auxiliary/proc_macro_attr.rs | 2 +- tests/ui/cast_slice_different_sizes.rs | 2 +- .../crashes/{ice_exacte_size.rs => ice_exact_size.rs} | 0 tests/ui/from_over_into.stderr | 10 +++++----- tests/ui/from_over_into_unfixable.stderr | 6 +++--- tests/ui/let_with_type_underscore.rs | 2 +- tests/ui/manual_retain.fixed | 4 ++-- tests/ui/manual_retain.rs | 4 ++-- tests/ui/needless_for_each_fixable.fixed | 2 +- tests/ui/needless_for_each_fixable.rs | 2 +- tests/ui/no_mangle_with_rust_abi.rs | 2 +- tests/ui/option_if_let_else.fixed | 2 +- tests/ui/option_if_let_else.rs | 2 +- tests/ui/same_name_method.rs | 2 +- tests/ui/trailing_empty_array.rs | 2 +- tests/ui/uninit.rs | 4 ++-- util/gh-pages/index.html | 2 +- 36 files changed, 46 insertions(+), 46 deletions(-) rename tests/ui/crashes/{ice_exacte_size.rs => ice_exact_size.rs} (100%) diff --git a/book/src/development/proposals/syntax-tree-patterns.md b/book/src/development/proposals/syntax-tree-patterns.md index 36d722609f4ac..285488cec55c2 100644 --- a/book/src/development/proposals/syntax-tree-patterns.md +++ b/book/src/development/proposals/syntax-tree-patterns.md @@ -139,7 +139,7 @@ whether the pattern matched. ## Pattern syntax -The following examples demonstate the pattern syntax: +The following examples demonstrate the pattern syntax: #### Any (`_`) diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs index d74bd57fe45eb..cfeb75eed3bb9 100644 --- a/clippy_lints/src/casts/mod.rs +++ b/clippy_lints/src/casts/mod.rs @@ -638,7 +638,7 @@ declare_clippy_lint! { #[clippy::version = "1.66.0"] pub AS_PTR_CAST_MUT, nursery, - "casting the result of the `&self`-taking `as_ptr` to a mutabe pointer" + "casting the result of the `&self`-taking `as_ptr` to a mutable pointer" } declare_clippy_lint! { diff --git a/clippy_lints/src/copies.rs b/clippy_lints/src/copies.rs index 970f50049935c..1c321f46e2da4 100644 --- a/clippy_lints/src/copies.rs +++ b/clippy_lints/src/copies.rs @@ -591,7 +591,7 @@ fn lint_same_cond(cx: &LateContext<'_>, conds: &[&Expr<'_>], ignored_ty_ids: &De conds, |e| hash_expr(cx, e), |lhs, rhs| { - // Ignore eq_expr side effects iff one of the expressin kind is a method call + // Ignore eq_expr side effects iff one of the expression 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) { diff --git a/clippy_lints/src/formatting.rs b/clippy_lints/src/formatting.rs index 4762b354392b8..62b419a522623 100644 --- a/clippy_lints/src/formatting.rs +++ b/clippy_lints/src/formatting.rs @@ -10,7 +10,7 @@ use rustc_span::source_map::Span; declare_clippy_lint! { /// ### What it does - /// Checks for usage of the non-existent `=*`, `=!` and `=-` + /// Checks for usage of the nonexistent `=*`, `=!` and `=-` /// operators. /// /// ### Why is this bad? diff --git a/clippy_lints/src/from_over_into.rs b/clippy_lints/src/from_over_into.rs index bd66ace4500a8..10ce2a0f0c7ec 100644 --- a/clippy_lints/src/from_over_into.rs +++ b/clippy_lints/src/from_over_into.rs @@ -94,7 +94,7 @@ impl<'tcx> LateLintPass<'tcx> for FromOverInto { ); } - let message = format!("replace the `Into` implentation with `From<{}>`", middle_trait_ref.self_ty()); + let message = format!("replace the `Into` implementation with `From<{}>`", middle_trait_ref.self_ty()); if let Some(suggestions) = convert_to_from(cx, into_trait_seg, target_ty, self_ty, impl_item_ref) { diag.multipart_suggestion(message, suggestions, Applicability::MachineApplicable); } else { diff --git a/clippy_lints/src/functions/misnamed_getters.rs b/clippy_lints/src/functions/misnamed_getters.rs index e5945939e60b9..b244b91331436 100644 --- a/clippy_lints/src/functions/misnamed_getters.rs +++ b/clippy_lints/src/functions/misnamed_getters.rs @@ -40,7 +40,7 @@ pub fn check_fn(cx: &LateContext<'_>, kind: FnKind<'_>, decl: &FnDecl<'_>, body: }; // Body must be &(mut) .name - // self_data is not neccessarilly self, to also lint sub-getters, etc… + // self_data is not necessarily self, to also lint sub-getters, etc… let block_expr = if_chain! { if let ExprKind::Block(block,_) = body.value.kind; diff --git a/clippy_lints/src/functions/mod.rs b/clippy_lints/src/functions/mod.rs index 7c5e44bb7dcad..c485bf8a4732f 100644 --- a/clippy_lints/src/functions/mod.rs +++ b/clippy_lints/src/functions/mod.rs @@ -330,7 +330,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Lints when `impl Trait` is being used in a function's paremeters. + /// Lints when `impl Trait` is being used in a function's parameters. /// ### Why is this bad? /// Turbofish syntax (`::<>`) cannot be used when `impl Trait` is being used, making `impl Trait` less powerful. Readability may also be a factor. /// diff --git a/clippy_lints/src/large_futures.rs b/clippy_lints/src/large_futures.rs index 1b0544813718a..0ca31033b169b 100644 --- a/clippy_lints/src/large_futures.rs +++ b/clippy_lints/src/large_futures.rs @@ -11,7 +11,7 @@ declare_clippy_lint! { /// It checks for the size of a `Future` created by `async fn` or `async {}`. /// /// ### Why is this bad? - /// Due to the current [unideal implemention](https://github.com/rust-lang/rust/issues/69826) of `Generator`, + /// Due to the current [unideal implementation](https://github.com/rust-lang/rust/issues/69826) of `Generator`, /// large size of a `Future` may cause stack overflows. /// /// ### Example diff --git a/clippy_lints/src/loops/manual_memcpy.rs b/clippy_lints/src/loops/manual_memcpy.rs index c87fc4f90e216..d4c3f76b86417 100644 --- a/clippy_lints/src/loops/manual_memcpy.rs +++ b/clippy_lints/src/loops/manual_memcpy.rs @@ -15,7 +15,7 @@ use rustc_span::symbol::sym; use std::fmt::Display; use std::iter::Iterator; -/// Checks for for loops that sequentially copy items from one slice-like +/// Checks for `for` loops that sequentially copy items from one slice-like /// object to another. pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, diff --git a/clippy_lints/src/manual_assert.rs b/clippy_lints/src/manual_assert.rs index ce5d657bcf0e3..45ea5aab4c2a2 100644 --- a/clippy_lints/src/manual_assert.rs +++ b/clippy_lints/src/manual_assert.rs @@ -64,7 +64,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualAssert { }; let cond_sugg = sugg::Sugg::hir_with_applicability(cx, cond, "..", &mut applicability).maybe_par(); let sugg = format!("assert!({not}{cond_sugg}, {format_args_snip});"); - // we show to the user the suggestion without the comments, but when applicating the fix, include the comments in the block + // we show to the user the suggestion without the comments, but when applying the fix, include the comments in the block span_lint_and_then( cx, MANUAL_ASSERT, diff --git a/clippy_lints/src/manual_let_else.rs b/clippy_lints/src/manual_let_else.rs index 98e698c6c2a0c..1247370b74a2f 100644 --- a/clippy_lints/src/manual_let_else.rs +++ b/clippy_lints/src/manual_let_else.rs @@ -101,7 +101,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualLetElse { if source != MatchSource::Normal { return; } - // Any other number than two arms doesn't (neccessarily) + // Any other number than two arms doesn't (necessarily) // have a trivial mapping to let else. if arms.len() != 2 { return; diff --git a/clippy_lints/src/manual_retain.rs b/clippy_lints/src/manual_retain.rs index 72cdb9c173616..5259066eb713c 100644 --- a/clippy_lints/src/manual_retain.rs +++ b/clippy_lints/src/manual_retain.rs @@ -46,7 +46,7 @@ declare_clippy_lint! { #[clippy::version = "1.64.0"] pub MANUAL_RETAIN, perf, - "`retain()` is simpler and the same functionalitys" + "`retain()` is simpler and the same functionalities" } pub struct ManualRetain { diff --git a/clippy_lints/src/missing_trait_methods.rs b/clippy_lints/src/missing_trait_methods.rs index e99081ad06202..1adecd2caacad 100644 --- a/clippy_lints/src/missing_trait_methods.rs +++ b/clippy_lints/src/missing_trait_methods.rs @@ -12,7 +12,7 @@ declare_clippy_lint! { /// Checks if a provided method is used implicitly by a trait /// implementation. A usage example would be a wrapper where every method /// should perform some operation before delegating to the inner type's - /// implemenation. + /// implementation. /// /// This lint should typically be enabled on a specific trait `impl` item /// rather than globally. diff --git a/clippy_lints/src/slow_vector_initialization.rs b/clippy_lints/src/slow_vector_initialization.rs index a2109038a0578..858135c8d4647 100644 --- a/clippy_lints/src/slow_vector_initialization.rs +++ b/clippy_lints/src/slow_vector_initialization.rs @@ -74,7 +74,7 @@ enum InitializationType<'tcx> { impl<'tcx> LateLintPass<'tcx> for SlowVectorInit { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - // Matches initialization on reassignements. For example: `vec = Vec::with_capacity(100)` + // Matches initialization on reassignments. For example: `vec = Vec::with_capacity(100)` if_chain! { if let ExprKind::Assign(left, right, _) = expr.kind; diff --git a/clippy_lints/src/trailing_empty_array.rs b/clippy_lints/src/trailing_empty_array.rs index 1382c1a40da24..f40229e03a226 100644 --- a/clippy_lints/src/trailing_empty_array.rs +++ b/clippy_lints/src/trailing_empty_array.rs @@ -60,7 +60,7 @@ fn is_struct_with_trailing_zero_sized_array(cx: &LateContext<'_>, item: &Item<'_ if let Some(last_field) = data.fields().last(); if let rustc_hir::TyKind::Array(_, rustc_hir::ArrayLen::Body(length)) = last_field.ty.kind; - // Then check if that that array zero-sized + // Then check if that array is zero-sized let length = Const::from_anon_const(cx.tcx, length.def_id); let length = length.try_eval_target_usize(cx.tcx, cx.param_env); if let Some(length) = length; diff --git a/clippy_lints/src/types/mod.rs b/clippy_lints/src/types/mod.rs index c6834a8fdaa24..3c873a5901d42 100644 --- a/clippy_lints/src/types/mod.rs +++ b/clippy_lints/src/types/mod.rs @@ -90,8 +90,8 @@ declare_clippy_lint! { /// /// ### Why is this bad? /// `Option<_>` represents an optional value. `Option>` - /// represents an optional optional value which is logically the same thing as an optional - /// value but has an unneeded extra level of wrapping. + /// represents an optional value which itself wraps an optional. This is logically the + /// same thing as an optional value but has an unneeded extra level of wrapping. /// /// If you have a case where `Some(Some(_))`, `Some(None)` and `None` are distinct cases, /// consider a custom `enum` instead, with clear names for each case. diff --git a/clippy_lints/src/unnecessary_box_returns.rs b/clippy_lints/src/unnecessary_box_returns.rs index 912bcda630b83..407a38779aae2 100644 --- a/clippy_lints/src/unnecessary_box_returns.rs +++ b/clippy_lints/src/unnecessary_box_returns.rs @@ -102,7 +102,7 @@ impl LateLintPass<'_> for UnnecessaryBoxReturns { fn check_impl_item(&mut self, cx: &LateContext<'_>, item: &rustc_hir::ImplItem<'_>) { // Ignore implementations of traits, because the lint should be on the - // trait, not on the implmentation of it. + // trait, not on the implementation of it. let Node::Item(parent) = cx.tcx.hir().get_parent(item.hir_id()) else { return }; let ItemKind::Impl(parent) = parent.kind else { return }; if parent.of_trait.is_some() { diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index 9449f0b55674d..3fcab34047e06 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -93,7 +93,7 @@ pub fn contains_ty_adt_constructor_opaque<'tcx>(cx: &LateContext<'tcx>, ty: Ty<' for &(predicate, _span) in cx.tcx.explicit_item_bounds(def_id) { match predicate.kind().skip_binder() { // For `impl Trait`, it will register a predicate of `T: Trait`, so we go through - // and check substituions to find `U`. + // and check substitutions to find `U`. ty::PredicateKind::Clause(ty::Clause::Trait(trait_predicate)) => { if trait_predicate .trait_ref @@ -1101,7 +1101,7 @@ pub fn make_projection<'tcx>( /// /// This function is for associated types which are "known" to be valid with the given /// substitutions, and as such, will only return `None` when debug assertions are disabled in order -/// to prevent ICE's. With debug assertions enabled this will check that that type normalization +/// to prevent ICE's. With debug assertions enabled this will check that type normalization /// succeeds as well as everything checked by `make_projection`. pub fn make_normalized_projection<'tcx>( tcx: TyCtxt<'tcx>, diff --git a/lintcheck/src/main.rs b/lintcheck/src/main.rs index 23c8529802759..03d1877d6c644 100644 --- a/lintcheck/src/main.rs +++ b/lintcheck/src/main.rs @@ -421,7 +421,7 @@ impl Crate { { let subcrate = &stderr[63..]; println!( - "ERROR: failed to apply some suggetion to {} / to (sub)crate {subcrate}", + "ERROR: failed to apply some suggestion to {} / to (sub)crate {subcrate}", self.name ); } diff --git a/tests/ui/auxiliary/proc_macro_attr.rs b/tests/ui/auxiliary/proc_macro_attr.rs index b498fece51322..9b4b3aef64a8d 100644 --- a/tests/ui/auxiliary/proc_macro_attr.rs +++ b/tests/ui/auxiliary/proc_macro_attr.rs @@ -82,7 +82,7 @@ pub fn rename_my_lifetimes(_args: TokenStream, input: TokenStream) -> TokenStrea elided += 1; // HACK: Syn uses `Span` from the proc_macro2 crate, and does not seem to reexport it. - // In order to avoid adding the dependency, get a default span from a non-existent token. + // In order to avoid adding the dependency, get a default span from a nonexistent token. // A default span is needed to mark the code as coming from expansion. let span = Star::default().span(); diff --git a/tests/ui/cast_slice_different_sizes.rs b/tests/ui/cast_slice_different_sizes.rs index 24d7eb28a197a..b77f01883bf38 100644 --- a/tests/ui/cast_slice_different_sizes.rs +++ b/tests/ui/cast_slice_different_sizes.rs @@ -23,7 +23,7 @@ fn main() { r_x as *const [i32] } as *const [u8]; - // Check that resores of the same size are detected through blocks + // Check that resources of the same size are detected through blocks let restore_block_1 = { r_x as *const [i32] } as *const [u8] as *const [u32]; let restore_block_2 = { ({ r_x as *const [i32] }) as *const [u8] } as *const [u32]; let restore_block_3 = { diff --git a/tests/ui/crashes/ice_exacte_size.rs b/tests/ui/crashes/ice_exact_size.rs similarity index 100% rename from tests/ui/crashes/ice_exacte_size.rs rename to tests/ui/crashes/ice_exact_size.rs diff --git a/tests/ui/from_over_into.stderr b/tests/ui/from_over_into.stderr index 3c4d011d6fb46..990b905c1b158 100644 --- a/tests/ui/from_over_into.stderr +++ b/tests/ui/from_over_into.stderr @@ -5,7 +5,7 @@ LL | impl Into for String { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::from-over-into` implied by `-D warnings` -help: replace the `Into` implentation with `From` +help: replace the `Into` implementation with `From` | LL ~ impl From for StringWrapper { LL ~ fn from(val: String) -> Self { @@ -18,7 +18,7 @@ error: an implementation of `From` is preferred since it gives you `Into<_>` for LL | impl Into for String { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: replace the `Into` implentation with `From` +help: replace the `Into` implementation with `From` | LL ~ impl From for SelfType { LL ~ fn from(val: String) -> Self { @@ -31,7 +31,7 @@ error: an implementation of `From` is preferred since it gives you `Into<_>` for LL | impl Into for X { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: replace the `Into` implentation with `From` +help: replace the `Into` implementation with `From` | LL ~ impl From for SelfKeywords { LL ~ fn from(val: X) -> Self { @@ -48,7 +48,7 @@ LL | impl core::convert::Into for crate::ExplicitPaths { | = help: `impl From for Foreign` is allowed by the orphan rules, for more information see https://doc.rust-lang.org/reference/items/implementations.html#trait-implementation-coherence -help: replace the `Into` implentation with `From` +help: replace the `Into` implementation with `From` | LL ~ impl core::convert::From for bool { LL ~ fn from(mut val: crate::ExplicitPaths) -> Self { @@ -64,7 +64,7 @@ error: an implementation of `From` is preferred since it gives you `Into<_>` for LL | impl Into> for Vec { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: replace the `Into` implentation with `From>` +help: replace the `Into` implementation with `From>` | LL ~ impl From> for FromOverInto { LL ~ fn from(val: Vec) -> Self { diff --git a/tests/ui/from_over_into_unfixable.stderr b/tests/ui/from_over_into_unfixable.stderr index 6f6ce351921be..251f1d84e74e3 100644 --- a/tests/ui/from_over_into_unfixable.stderr +++ b/tests/ui/from_over_into_unfixable.stderr @@ -4,7 +4,7 @@ error: an implementation of `From` is preferred since it gives you `Into<_>` for LL | impl Into for String { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: replace the `Into` implentation with `From` + = help: replace the `Into` implementation with `From` = note: `-D clippy::from-over-into` implied by `-D warnings` error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true @@ -13,7 +13,7 @@ error: an implementation of `From` is preferred since it gives you `Into<_>` for LL | impl Into for &'static [u8] { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: replace the `Into` implentation with `From<&'static [u8]>` + = help: replace the `Into` implementation with `From<&'static [u8]>` error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true --> $DIR/from_over_into_unfixable.rs:28:1 @@ -23,7 +23,7 @@ LL | impl Into for ContainsVal { | = help: `impl From for Foreign` is allowed by the orphan rules, for more information see https://doc.rust-lang.org/reference/items/implementations.html#trait-implementation-coherence - = help: replace the `Into` implentation with `From` + = help: replace the `Into` implementation with `From` error: aborting due to 3 previous errors diff --git a/tests/ui/let_with_type_underscore.rs b/tests/ui/let_with_type_underscore.rs index 175718b94c8e6..7c1835e8cd18f 100644 --- a/tests/ui/let_with_type_underscore.rs +++ b/tests/ui/let_with_type_underscore.rs @@ -12,7 +12,7 @@ fn main() { let _: _ = 2; let x: _ = func(); - let x = 1; // Will not lint, Rust inferres this to an integer before Clippy + let x = 1; // Will not lint, Rust infers this to an integer before Clippy let x = func(); let x: Vec<_> = Vec::::new(); let x: [_; 1] = [1]; diff --git a/tests/ui/manual_retain.fixed b/tests/ui/manual_retain.fixed index 8f25fea678f19..fa3773dc90899 100644 --- a/tests/ui/manual_retain.fixed +++ b/tests/ui/manual_retain.fixed @@ -23,8 +23,8 @@ fn main() { } fn binary_heap_retain() { - // NOTE: Do not lint now, because binary_heap_retain is nighyly API. - // And we need to add a test case for msrv if we update this implmention. + // NOTE: Do not lint now, because binary_heap_retain is nightly API. + // And we need to add a test case for msrv if we update this implementation. // https://github.com/rust-lang/rust/issues/71503 let mut heap = BinaryHeap::from([1, 2, 3]); heap = heap.into_iter().filter(|x| x % 2 == 0).collect(); diff --git a/tests/ui/manual_retain.rs b/tests/ui/manual_retain.rs index e6b3995a689b3..f982a105597a8 100644 --- a/tests/ui/manual_retain.rs +++ b/tests/ui/manual_retain.rs @@ -23,8 +23,8 @@ fn main() { } fn binary_heap_retain() { - // NOTE: Do not lint now, because binary_heap_retain is nighyly API. - // And we need to add a test case for msrv if we update this implmention. + // NOTE: Do not lint now, because binary_heap_retain is nightly API. + // And we need to add a test case for msrv if we update this implementation. // https://github.com/rust-lang/rust/issues/71503 let mut heap = BinaryHeap::from([1, 2, 3]); heap = heap.into_iter().filter(|x| x % 2 == 0).collect(); diff --git a/tests/ui/needless_for_each_fixable.fixed b/tests/ui/needless_for_each_fixable.fixed index 09e671b88e1aa..5ee7f1fb2b63b 100644 --- a/tests/ui/needless_for_each_fixable.fixed +++ b/tests/ui/needless_for_each_fixable.fixed @@ -110,7 +110,7 @@ fn should_not_lint() { }), } - // `for_each` is in a let bingind. + // `for_each` is in a let binding. let _ = v.iter().for_each(|elem| { acc += elem; }); diff --git a/tests/ui/needless_for_each_fixable.rs b/tests/ui/needless_for_each_fixable.rs index abb4045b9197d..ec4da9eb9974d 100644 --- a/tests/ui/needless_for_each_fixable.rs +++ b/tests/ui/needless_for_each_fixable.rs @@ -110,7 +110,7 @@ fn should_not_lint() { }), } - // `for_each` is in a let bingind. + // `for_each` is in a let binding. let _ = v.iter().for_each(|elem| { acc += elem; }); diff --git a/tests/ui/no_mangle_with_rust_abi.rs b/tests/ui/no_mangle_with_rust_abi.rs index b32e721110e0b..818119f7be579 100644 --- a/tests/ui/no_mangle_with_rust_abi.rs +++ b/tests/ui/no_mangle_with_rust_abi.rs @@ -25,7 +25,7 @@ fn rust_abi_multiline_function_really_long_name_to_overflow_args_to_multiple_lin 0 } -// Must not run on functions that explicitly opt in to Rust ABI with `extern "Rust"` +// Must not run on functions that explicitly opt in to using the Rust ABI with `extern "Rust"` #[no_mangle] #[rustfmt::skip] extern "Rust" fn rust_abi_fn_explicit_opt_in(arg_one: u32, arg_two: usize) {} diff --git a/tests/ui/option_if_let_else.fixed b/tests/ui/option_if_let_else.fixed index 0456005dce496..d4343c98d27ea 100644 --- a/tests/ui/option_if_let_else.fixed +++ b/tests/ui/option_if_let_else.fixed @@ -97,7 +97,7 @@ enum DummyEnum { Two, } -// should not warn since there is a compled complex subpat +// should not warn since there is a complex subpat // see #7991 fn complex_subpat() -> DummyEnum { let x = Some(DummyEnum::One(1)); diff --git a/tests/ui/option_if_let_else.rs b/tests/ui/option_if_let_else.rs index 23b148752cbfa..c78e31fed9633 100644 --- a/tests/ui/option_if_let_else.rs +++ b/tests/ui/option_if_let_else.rs @@ -120,7 +120,7 @@ enum DummyEnum { Two, } -// should not warn since there is a compled complex subpat +// should not warn since there is a complex subpat // see #7991 fn complex_subpat() -> DummyEnum { let x = Some(DummyEnum::One(1)); diff --git a/tests/ui/same_name_method.rs b/tests/ui/same_name_method.rs index daef95a425c92..f31a7e33c4b9e 100644 --- a/tests/ui/same_name_method.rs +++ b/tests/ui/same_name_method.rs @@ -62,7 +62,7 @@ mod should_lint { impl T1 for S {} } - mod multiply_conflicit_trait { + mod multiple_conflicting_traits { use crate::{T1, T2}; struct S; diff --git a/tests/ui/trailing_empty_array.rs b/tests/ui/trailing_empty_array.rs index 8e3749eef351f..928475b5f35ea 100644 --- a/tests/ui/trailing_empty_array.rs +++ b/tests/ui/trailing_empty_array.rs @@ -144,7 +144,7 @@ struct ReprCAlign { // NOTE: because of https://doc.rust-lang.org/stable/reference/type-layout.html#primitive-representation-of-enums-with-fields and I'm not sure when in the compilation pipeline that would happen #[repr(C)] -enum DontLintAnonymousStructsFromDesuraging { +enum DontLintAnonymousStructsFromDesugaring { A(u32), B(f32, [u64; 0]), C { x: u32, y: [u64; 0] }, diff --git a/tests/ui/uninit.rs b/tests/ui/uninit.rs index c996de89422b5..2d567630e15de 100644 --- a/tests/ui/uninit.rs +++ b/tests/ui/uninit.rs @@ -17,10 +17,10 @@ fn main() { // This is OK, because `MaybeUninit` allows uninitialized data. let _: MaybeUninit = unsafe { MaybeUninit::uninit().assume_init() }; - // This is OK, because all constitutent types are uninit-compatible. + // This is OK, because all constituent types are uninit-compatible. let _: (MaybeUninit, MaybeUninit) = unsafe { MaybeUninit::uninit().assume_init() }; - // This is OK, because all constitutent types are uninit-compatible. + // This is OK, because all constituent 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. diff --git a/util/gh-pages/index.html b/util/gh-pages/index.html index e46ad2c6e0eec..8791debad7231 100644 --- a/util/gh-pages/index.html +++ b/util/gh-pages/index.html @@ -564,7 +564,7 @@

- Fork me on Github + Fork me on GitHub From 6f7801f810644c22dfe8c089b5ccc32c9de833d7 Mon Sep 17 00:00:00 2001 From: Josh Soref <2119212+jsoref@users.noreply.github.com> Date: Mon, 17 Apr 2023 15:22:43 -0400 Subject: [PATCH 40/86] Rewrite search_same description --- clippy_utils/src/lib.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index f1d2ae220f81d..35378143a7931 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -2233,8 +2233,12 @@ pub fn is_slice_of_primitives(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option(exprs: &[T], hash: Hash, eq: Eq) -> Vec<(&T, &T)> where Hash: Fn(&T) -> u64, From e8726b20b2a64b4553c87d02a330fd2bc62064bd Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Sun, 23 Apr 2023 21:34:42 +0200 Subject: [PATCH 41/86] also check for rest pat in `redundant_pattern_matching` --- clippy_lints/src/indexing_slicing.rs | 2 +- .../src/matches/redundant_pattern_match.rs | 7 ++++-- .../redundant_pattern_matching_option.fixed | 2 ++ tests/ui/redundant_pattern_matching_option.rs | 2 ++ .../redundant_pattern_matching_option.stderr | 24 ++++++++++++------- 5 files changed, 25 insertions(+), 12 deletions(-) diff --git a/clippy_lints/src/indexing_slicing.rs b/clippy_lints/src/indexing_slicing.rs index c384172fbde83..924a361c0f6a8 100644 --- a/clippy_lints/src/indexing_slicing.rs +++ b/clippy_lints/src/indexing_slicing.rs @@ -170,7 +170,7 @@ impl<'tcx> LateLintPass<'tcx> for IndexingSlicing { return; } // Index is a constant uint. - if let Some(..) = constant(cx, cx.typeck_results(), index) { + if constant(cx, cx.typeck_results(), index).is_some() { // Let rustc's `const_err` lint handle constant `usize` indexing on arrays. return; } diff --git a/clippy_lints/src/matches/redundant_pattern_match.rs b/clippy_lints/src/matches/redundant_pattern_match.rs index fb9f9c1122f27..af121f317cd18 100644 --- a/clippy_lints/src/matches/redundant_pattern_match.rs +++ b/clippy_lints/src/matches/redundant_pattern_match.rs @@ -63,8 +63,11 @@ fn find_sugg_for_if_let<'tcx>( // Determine which function should be used, and the type contained by the corresponding // variant. let (good_method, inner_ty) = match check_pat.kind { - PatKind::TupleStruct(ref qpath, [sub_pat], _) => { - if let PatKind::Wild = sub_pat.kind { + PatKind::TupleStruct(ref qpath, args, rest) => { + let is_wildcard = matches!(args.first().map(|p| &p.kind), Some(PatKind::Wild)); + let is_rest = matches!((args, rest.as_opt_usize()), ([], Some(_))); + + if is_wildcard || is_rest { let res = cx.typeck_results().qpath_res(qpath, check_pat.hir_id); let Some(id) = res.opt_def_id().map(|ctor_id| cx.tcx.parent(ctor_id)) else { return }; let lang_items = cx.tcx.lang_items(); diff --git a/tests/ui/redundant_pattern_matching_option.fixed b/tests/ui/redundant_pattern_matching_option.fixed index 87100b972880c..d62f7d26a35cc 100644 --- a/tests/ui/redundant_pattern_matching_option.fixed +++ b/tests/ui/redundant_pattern_matching_option.fixed @@ -54,6 +54,8 @@ fn main() { } else { 3 }; + + if gen_opt().is_some() {} } fn gen_opt() -> Option<()> { diff --git a/tests/ui/redundant_pattern_matching_option.rs b/tests/ui/redundant_pattern_matching_option.rs index 0b69e13f65590..d64294265731b 100644 --- a/tests/ui/redundant_pattern_matching_option.rs +++ b/tests/ui/redundant_pattern_matching_option.rs @@ -63,6 +63,8 @@ fn main() { } else { 3 }; + + if let Some(..) = gen_opt() {} } fn gen_opt() -> Option<()> { diff --git a/tests/ui/redundant_pattern_matching_option.stderr b/tests/ui/redundant_pattern_matching_option.stderr index 27ff812ba45ec..7c5a047e455cf 100644 --- a/tests/ui/redundant_pattern_matching_option.stderr +++ b/tests/ui/redundant_pattern_matching_option.stderr @@ -89,31 +89,37 @@ LL | } else if let None = gen_opt() { | -------^^^^------------ help: try this: `if gen_opt().is_none()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:80:12 + --> $DIR/redundant_pattern_matching_option.rs:67:12 + | +LL | if let Some(..) = gen_opt() {} + | -------^^^^^^^^------------ help: try this: `if gen_opt().is_some()` + +error: redundant pattern matching, consider using `is_some()` + --> $DIR/redundant_pattern_matching_option.rs:82:12 | LL | if let Some(_) = Some(42) {} | -------^^^^^^^----------- help: try this: `if Some(42).is_some()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:82:12 + --> $DIR/redundant_pattern_matching_option.rs:84:12 | LL | if let None = None::<()> {} | -------^^^^------------- help: try this: `if None::<()>.is_none()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:84:15 + --> $DIR/redundant_pattern_matching_option.rs:86:15 | LL | while let Some(_) = Some(42) {} | ----------^^^^^^^----------- help: try this: `while Some(42).is_some()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:86:15 + --> $DIR/redundant_pattern_matching_option.rs:88:15 | LL | while let None = None::<()> {} | ----------^^^^------------- help: try this: `while None::<()>.is_none()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:88:5 + --> $DIR/redundant_pattern_matching_option.rs:90:5 | LL | / match Some(42) { LL | | Some(_) => true, @@ -122,7 +128,7 @@ LL | | }; | |_____^ help: try this: `Some(42).is_some()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:93:5 + --> $DIR/redundant_pattern_matching_option.rs:95:5 | LL | / match None::<()> { LL | | Some(_) => false, @@ -131,16 +137,16 @@ LL | | }; | |_____^ help: try this: `None::<()>.is_none()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:101:12 + --> $DIR/redundant_pattern_matching_option.rs:103:12 | LL | if let None = *(&None::<()>) {} | -------^^^^----------------- help: try this: `if (&None::<()>).is_none()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:102:12 + --> $DIR/redundant_pattern_matching_option.rs:104:12 | LL | if let None = *&None::<()> {} | -------^^^^--------------- help: try this: `if (&None::<()>).is_none()` -error: aborting due to 21 previous errors +error: aborting due to 22 previous errors From 6c859b6d2e8c14cb83dde578884f31596a869182 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Mon, 24 Apr 2023 09:47:54 +0200 Subject: [PATCH 42/86] Clippy book: hotfix for broken link --- book/src/development/lint_passes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/book/src/development/lint_passes.md b/book/src/development/lint_passes.md index c41b6ea0de8fe..131f6455fdeae 100644 --- a/book/src/development/lint_passes.md +++ b/book/src/development/lint_passes.md @@ -50,7 +50,7 @@ questions already, but the parser is okay with it. This is what we mean when we say `EarlyLintPass` deals with only syntax on the AST level. Alternatively, think of the `foo_functions` lint we mentioned in -[define new lints](define_lints.md#name-the-lint) chapter. +define new lints chapter. We want the `foo_functions` lint to detect functions with `foo` as their name. Writing a lint that only checks for the name of a function means that we only From 3045998bcc2f6cea7611bb02455faa8a9cf081bf Mon Sep 17 00:00:00 2001 From: Centri3 <114838443+Centri3@users.noreply.github.com> Date: Mon, 24 Apr 2023 12:01:29 -0500 Subject: [PATCH 43/86] Update allow_attributes_false_positive.rs --- tests/ui/allow_attributes_false_positive.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/ui/allow_attributes_false_positive.rs b/tests/ui/allow_attributes_false_positive.rs index a34a5d91ef5a1..5c3407628be27 100644 --- a/tests/ui/allow_attributes_false_positive.rs +++ b/tests/ui/allow_attributes_false_positive.rs @@ -1,4 +1,3 @@ -#![allow(unused)] #![warn(clippy::allow_attributes)] #![feature(lint_reasons)] #![crate_type = "proc-macro"] From 4a76b6f04f9731ab1c106f33a1023658e7d06107 Mon Sep 17 00:00:00 2001 From: blyxyas Date: Tue, 25 Apr 2023 00:14:26 +0200 Subject: [PATCH 44/86] Add the warning to all documentation. --- README.md | 3 ++- book/src/usage.md | 3 ++- lintcheck/README.md | 4 +++- src/main.rs | 2 +- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 85798e0e80c15..6745e15c00657 100644 --- a/README.md +++ b/README.md @@ -91,7 +91,8 @@ cargo clippy #### Automatically applying Clippy suggestions -Clippy can automatically apply some lint suggestions, just like the compiler. +Clippy can automatically apply some lint suggestions, just like the compiler. Note that `--fix` implies +`--all-targets`, so it can fix as much code as it can. ```terminal cargo clippy --fix diff --git a/book/src/usage.md b/book/src/usage.md index 32084a9199b73..36448e4cccfa4 100644 --- a/book/src/usage.md +++ b/book/src/usage.md @@ -111,7 +111,8 @@ fn main() { ### Automatically applying Clippy suggestions -Clippy can automatically apply some lint suggestions, just like the compiler. +Clippy can automatically apply some lint suggestions, just like the compiler. Note that `--fix` implies +`--all-targets`, so it can fix as much code as it can. ```terminal cargo clippy --fix diff --git a/lintcheck/README.md b/lintcheck/README.md index faf3ce9093a21..37cc045380949 100644 --- a/lintcheck/README.md +++ b/lintcheck/README.md @@ -79,9 +79,11 @@ is explicitly specified in the options. ### Fix mode You can run `cargo lintcheck --fix` which will run Clippy with `--fix` and -print a warning if Clippy's suggestions fail to apply (if the resulting code does not build). +print a warning if Clippy's suggestions fail to apply (if the resulting code does not build). This lets us spot bad suggestions or false positives automatically in some cases. +> Note: Fix mode implies `--all-targets`, so it can fix as much code as it can. + Please note that the target dir should be cleaned afterwards since clippy will modify the downloaded sources which can lead to unexpected results when running lintcheck again afterwards. diff --git a/src/main.rs b/src/main.rs index c5e9b96cf3fcc..188ff87abfc53 100644 --- a/src/main.rs +++ b/src/main.rs @@ -13,7 +13,7 @@ Usage: Common options: --no-deps Run Clippy only on the given crate, without linting the dependencies - --fix Automatically apply lint suggestions. This flag implies `--no-deps` + --fix Automatically apply lint suggestions. This flag implies `--no-deps` and `--all-targets` -h, --help Print this message -V, --version Print version info and exit --explain LINT Print the documentation for a given lint From acfb2c45ba337b3265ab35dee5c94d3641c3ccf7 Mon Sep 17 00:00:00 2001 From: Centri3 <114838443+Centri3@users.noreply.github.com> Date: Tue, 18 Apr 2023 02:14:00 -0500 Subject: [PATCH 45/86] don't check if from macro invocation --- clippy_lints/src/strings.rs | 4 ++++ tests/ui/string_lit_as_bytes.fixed | 8 ++++++++ tests/ui/string_lit_as_bytes.rs | 8 ++++++++ tests/ui/string_lit_as_bytes.stderr | 12 ++++++------ 4 files changed, 26 insertions(+), 6 deletions(-) diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs index b2f4b310915a6..c8ea151ffce26 100644 --- a/clippy_lints/src/strings.rs +++ b/clippy_lints/src/strings.rs @@ -253,6 +253,10 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes { fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { use rustc_ast::LitKind; + if e.span.from_expansion() { + return; + } + if_chain! { // Find std::str::converts::from_utf8 if let Some(args) = match_function_call(cx, e, &paths::STR_FROM_UTF8); diff --git a/tests/ui/string_lit_as_bytes.fixed b/tests/ui/string_lit_as_bytes.fixed index 058f2aa54daaa..14cb799d91637 100644 --- a/tests/ui/string_lit_as_bytes.fixed +++ b/tests/ui/string_lit_as_bytes.fixed @@ -3,6 +3,12 @@ #![allow(dead_code, unused_variables)] #![warn(clippy::string_lit_as_bytes)] +macro_rules! b { + ($b:literal) => { + const C: &[u8] = $b.as_bytes(); + } +} + fn str_lit_as_bytes() { let bs = b"hello there"; @@ -11,6 +17,8 @@ fn str_lit_as_bytes() { let bs = b"lit to string".to_vec(); let bs = b"lit to owned".to_vec(); + b!("aaa"); + // no warning, because these cannot be written as byte string literals: let ubs = "☃".as_bytes(); let ubs = "hello there! this is a very long string".as_bytes(); diff --git a/tests/ui/string_lit_as_bytes.rs b/tests/ui/string_lit_as_bytes.rs index b550bea001f47..44b468e6bf0c4 100644 --- a/tests/ui/string_lit_as_bytes.rs +++ b/tests/ui/string_lit_as_bytes.rs @@ -3,6 +3,12 @@ #![allow(dead_code, unused_variables)] #![warn(clippy::string_lit_as_bytes)] +macro_rules! b { + ($b:literal) => { + const C: &[u8] = $b.as_bytes(); + } +} + fn str_lit_as_bytes() { let bs = "hello there".as_bytes(); @@ -11,6 +17,8 @@ fn str_lit_as_bytes() { let bs = "lit to string".to_string().into_bytes(); let bs = "lit to owned".to_owned().into_bytes(); + b!("aaa"); + // no warning, because these cannot be written as byte string literals: let ubs = "☃".as_bytes(); let ubs = "hello there! this is a very long string".as_bytes(); diff --git a/tests/ui/string_lit_as_bytes.stderr b/tests/ui/string_lit_as_bytes.stderr index f47d6161c6cf2..5be3eb9f2fff6 100644 --- a/tests/ui/string_lit_as_bytes.stderr +++ b/tests/ui/string_lit_as_bytes.stderr @@ -1,5 +1,5 @@ error: calling `as_bytes()` on a string literal - --> $DIR/string_lit_as_bytes.rs:7:14 + --> $DIR/string_lit_as_bytes.rs:13:14 | LL | let bs = "hello there".as_bytes(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using a byte string literal instead: `b"hello there"` @@ -7,31 +7,31 @@ LL | let bs = "hello there".as_bytes(); = note: `-D clippy::string-lit-as-bytes` implied by `-D warnings` error: calling `as_bytes()` on a string literal - --> $DIR/string_lit_as_bytes.rs:9:14 + --> $DIR/string_lit_as_bytes.rs:15:14 | LL | let bs = r###"raw string with 3# plus " ""###.as_bytes(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using a byte string literal instead: `br###"raw string with 3# plus " ""###` error: calling `into_bytes()` on a string literal - --> $DIR/string_lit_as_bytes.rs:11:14 + --> $DIR/string_lit_as_bytes.rs:17:14 | LL | let bs = "lit to string".to_string().into_bytes(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using a byte string literal instead: `b"lit to string".to_vec()` error: calling `into_bytes()` on a string literal - --> $DIR/string_lit_as_bytes.rs:12:14 + --> $DIR/string_lit_as_bytes.rs:18:14 | LL | let bs = "lit to owned".to_owned().into_bytes(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using a byte string literal instead: `b"lit to owned".to_vec()` error: calling `as_bytes()` on `include_str!(..)` - --> $DIR/string_lit_as_bytes.rs:25:22 + --> $DIR/string_lit_as_bytes.rs:33:22 | LL | let includestr = include_str!("string_lit_as_bytes.rs").as_bytes(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `include_bytes!(..)` instead: `include_bytes!("string_lit_as_bytes.rs")` error: calling `as_bytes()` on a string literal - --> $DIR/string_lit_as_bytes.rs:27:13 + --> $DIR/string_lit_as_bytes.rs:35:13 | LL | let _ = "string with newline/t/n".as_bytes(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using a byte string literal instead: `b"string with newline/t/n"` From 8efe9ff9fb5bd6c661f7d57d4069b127544ebe8d Mon Sep 17 00:00:00 2001 From: Centri3 <114838443+Centri3@users.noreply.github.com> Date: Tue, 18 Apr 2023 10:12:34 -0500 Subject: [PATCH 46/86] run cargo dev fmt --- tests/ui/string_lit_as_bytes.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ui/string_lit_as_bytes.rs b/tests/ui/string_lit_as_bytes.rs index 44b468e6bf0c4..7ca383567a32d 100644 --- a/tests/ui/string_lit_as_bytes.rs +++ b/tests/ui/string_lit_as_bytes.rs @@ -6,7 +6,7 @@ macro_rules! b { ($b:literal) => { const C: &[u8] = $b.as_bytes(); - } + }; } fn str_lit_as_bytes() { From 1ac30d3c860a5ed67c3d31b9d93c251a19af9c6f Mon Sep 17 00:00:00 2001 From: Centri3 <114838443+Centri3@users.noreply.github.com> Date: Tue, 18 Apr 2023 10:16:10 -0500 Subject: [PATCH 47/86] make cargo test pass --- tests/ui/string_lit_as_bytes.fixed | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ui/string_lit_as_bytes.fixed b/tests/ui/string_lit_as_bytes.fixed index 14cb799d91637..91cdf179b8234 100644 --- a/tests/ui/string_lit_as_bytes.fixed +++ b/tests/ui/string_lit_as_bytes.fixed @@ -6,7 +6,7 @@ macro_rules! b { ($b:literal) => { const C: &[u8] = $b.as_bytes(); - } + }; } fn str_lit_as_bytes() { From 14a6fa4a34d24ec81fe562b71966471efcbb32b2 Mon Sep 17 00:00:00 2001 From: Centri3 <114838443+Centri3@users.noreply.github.com> Date: Wed, 19 Apr 2023 21:09:27 -0500 Subject: [PATCH 48/86] use in_external_macro --- clippy_lints/src/strings.rs | 5 +---- tests/ui/auxiliary/macro_rules.rs | 7 +++++++ tests/ui/string_lit_as_bytes.fixed | 10 ++++++++-- tests/ui/string_lit_as_bytes.rs | 10 ++++++++-- tests/ui/string_lit_as_bytes.stderr | 25 ++++++++++++++++++------- 5 files changed, 42 insertions(+), 15 deletions(-) diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs index c8ea151ffce26..5b588e914fdf8 100644 --- a/clippy_lints/src/strings.rs +++ b/clippy_lints/src/strings.rs @@ -253,10 +253,6 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes { fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { use rustc_ast::LitKind; - if e.span.from_expansion() { - return; - } - if_chain! { // Find std::str::converts::from_utf8 if let Some(args) = match_function_call(cx, e, &paths::STR_FROM_UTF8); @@ -296,6 +292,7 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes { } if_chain! { + if !in_external_macro(cx.sess(), e.span); if let ExprKind::MethodCall(path, receiver, ..) = &e.kind; if path.ident.name == sym!(as_bytes); if let ExprKind::Lit(lit) = &receiver.kind; diff --git a/tests/ui/auxiliary/macro_rules.rs b/tests/ui/auxiliary/macro_rules.rs index a9bb61451dca6..e5bb906663c56 100644 --- a/tests/ui/auxiliary/macro_rules.rs +++ b/tests/ui/auxiliary/macro_rules.rs @@ -21,6 +21,13 @@ macro_rules! string_add { }; } +#[macro_export] +macro_rules! string_lit_as_bytes { + ($s:literal) => { + const C: &[u8] = $s.as_bytes(); + }; +} + #[macro_export] macro_rules! mut_mut { () => { diff --git a/tests/ui/string_lit_as_bytes.fixed b/tests/ui/string_lit_as_bytes.fixed index 91cdf179b8234..3fc11b8b0885e 100644 --- a/tests/ui/string_lit_as_bytes.fixed +++ b/tests/ui/string_lit_as_bytes.fixed @@ -1,11 +1,15 @@ //@run-rustfix +//@aux-build:macro_rules.rs #![allow(dead_code, unused_variables)] #![warn(clippy::string_lit_as_bytes)] +#[macro_use] +extern crate macro_rules; + macro_rules! b { ($b:literal) => { - const C: &[u8] = $b.as_bytes(); + const B: &[u8] = b"warning"; }; } @@ -17,7 +21,9 @@ fn str_lit_as_bytes() { let bs = b"lit to string".to_vec(); let bs = b"lit to owned".to_vec(); - b!("aaa"); + b!("warning"); + + string_lit_as_bytes!("no warning"); // no warning, because these cannot be written as byte string literals: let ubs = "☃".as_bytes(); diff --git a/tests/ui/string_lit_as_bytes.rs b/tests/ui/string_lit_as_bytes.rs index 7ca383567a32d..7d54acf630e6c 100644 --- a/tests/ui/string_lit_as_bytes.rs +++ b/tests/ui/string_lit_as_bytes.rs @@ -1,11 +1,15 @@ //@run-rustfix +//@aux-build:macro_rules.rs #![allow(dead_code, unused_variables)] #![warn(clippy::string_lit_as_bytes)] +#[macro_use] +extern crate macro_rules; + macro_rules! b { ($b:literal) => { - const C: &[u8] = $b.as_bytes(); + const B: &[u8] = $b.as_bytes(); }; } @@ -17,7 +21,9 @@ fn str_lit_as_bytes() { let bs = "lit to string".to_string().into_bytes(); let bs = "lit to owned".to_owned().into_bytes(); - b!("aaa"); + b!("warning"); + + string_lit_as_bytes!("no warning"); // no warning, because these cannot be written as byte string literals: let ubs = "☃".as_bytes(); diff --git a/tests/ui/string_lit_as_bytes.stderr b/tests/ui/string_lit_as_bytes.stderr index 5be3eb9f2fff6..61b4e210e0fb9 100644 --- a/tests/ui/string_lit_as_bytes.stderr +++ b/tests/ui/string_lit_as_bytes.stderr @@ -1,5 +1,5 @@ error: calling `as_bytes()` on a string literal - --> $DIR/string_lit_as_bytes.rs:13:14 + --> $DIR/string_lit_as_bytes.rs:17:14 | LL | let bs = "hello there".as_bytes(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using a byte string literal instead: `b"hello there"` @@ -7,34 +7,45 @@ LL | let bs = "hello there".as_bytes(); = note: `-D clippy::string-lit-as-bytes` implied by `-D warnings` error: calling `as_bytes()` on a string literal - --> $DIR/string_lit_as_bytes.rs:15:14 + --> $DIR/string_lit_as_bytes.rs:19:14 | LL | let bs = r###"raw string with 3# plus " ""###.as_bytes(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using a byte string literal instead: `br###"raw string with 3# plus " ""###` error: calling `into_bytes()` on a string literal - --> $DIR/string_lit_as_bytes.rs:17:14 + --> $DIR/string_lit_as_bytes.rs:21:14 | LL | let bs = "lit to string".to_string().into_bytes(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using a byte string literal instead: `b"lit to string".to_vec()` error: calling `into_bytes()` on a string literal - --> $DIR/string_lit_as_bytes.rs:18:14 + --> $DIR/string_lit_as_bytes.rs:22:14 | LL | let bs = "lit to owned".to_owned().into_bytes(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using a byte string literal instead: `b"lit to owned".to_vec()` +error: calling `as_bytes()` on a string literal + --> $DIR/string_lit_as_bytes.rs:12:26 + | +LL | const B: &[u8] = $b.as_bytes(); + | ^^^^^^^^^^^^^ help: consider using a byte string literal instead: `b"warning"` +... +LL | b!("warning"); + | ------------- in this macro invocation + | + = note: this error originates in the macro `b` (in Nightly builds, run with -Z macro-backtrace for more info) + error: calling `as_bytes()` on `include_str!(..)` - --> $DIR/string_lit_as_bytes.rs:33:22 + --> $DIR/string_lit_as_bytes.rs:39:22 | LL | let includestr = include_str!("string_lit_as_bytes.rs").as_bytes(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `include_bytes!(..)` instead: `include_bytes!("string_lit_as_bytes.rs")` error: calling `as_bytes()` on a string literal - --> $DIR/string_lit_as_bytes.rs:35:13 + --> $DIR/string_lit_as_bytes.rs:41:13 | LL | let _ = "string with newline/t/n".as_bytes(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using a byte string literal instead: `b"string with newline/t/n"` -error: aborting due to 6 previous errors +error: aborting due to 7 previous errors From 637d10b292bad1417c6661c22ddb7c9b7ca8afac Mon Sep 17 00:00:00 2001 From: xFrednet Date: Tue, 25 Apr 2023 17:32:50 +0200 Subject: [PATCH 49/86] Catching, stray, commas, (I'll, never, learn, to, use, them, correctly) :sweat_smile: --- CHANGELOG.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b3a340d0cc831..23f4f97ee07c5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,7 +44,7 @@ Current stable, released 2023-04-20 ### Enhancements -* [`arithmetic_side_effects`]: No longer lints, if safe constant values are used. +* [`arithmetic_side_effects`]: No longer lints if safe constant values are used. [#10310](https://github.com/rust-lang/rust-clippy/pull/10310) * [`needless_lifetimes`]: Now works in local macros [#10257](https://github.com/rust-lang/rust-clippy/pull/10257) @@ -60,39 +60,39 @@ Current stable, released 2023-04-20 ### False Positive Fixes -* [`explicit_auto_deref`]: Now considers projections, when determining if auto deref is applicable +* [`explicit_auto_deref`]: Now considers projections when determining if auto deref is applicable [#10386](https://github.com/rust-lang/rust-clippy/pull/10386) -* [`manual_let_else`]: Now considers side effects of branches, before linting +* [`manual_let_else`]: Now considers side effects of branches before linting [#10336](https://github.com/rust-lang/rust-clippy/pull/10336) * [`uninlined_format_args`]: No longer lints for arguments with generic parameters [#10343](https://github.com/rust-lang/rust-clippy/pull/10343) -* [`needless_lifetimes`]: No longer lints signatures in macros, if the lifetime is a metavariable +* [`needless_lifetimes`]: No longer lints signatures in macros if the lifetime is a metavariable [#10380](https://github.com/rust-lang/rust-clippy/pull/10380) -* [`len_without_is_empty`]: No longer lints, if `len` as a non-default signature +* [`len_without_is_empty`]: No longer lints if `len` as a non-default signature [#10255](https://github.com/rust-lang/rust-clippy/pull/10255) -* [`unusual_byte_groupings`]: Relaxed the required restrictions for specific sizes, to reduce false +* [`unusual_byte_groupings`]: Relaxed the required restrictions for specific sizes to reduce false positives [#10353](https://github.com/rust-lang/rust-clippy/pull/10353) * [`manual_let_else`]: No longer lints `if-else` blocks if they can divergent [#10332](https://github.com/rust-lang/rust-clippy/pull/10332) * [`expect_used`], [`unwrap_used`], [`dbg_macro`], [`print_stdout`], [`print_stderr`]: No longer lint - in test functions, if `allow-expect-in-tests` is set + in test functions if `allow-expect-in-tests` is set [#10391](https://github.com/rust-lang/rust-clippy/pull/10391) * [`unnecessary_safety_comment`]: No longer lints code inside macros [#10106](https://github.com/rust-lang/rust-clippy/pull/10106) -* [`never_loop`]: No longer lints, for statements following break statements for outer blocks. +* [`never_loop`]: No longer lints statements following break statements for outer blocks. [#10311](https://github.com/rust-lang/rust-clippy/pull/10311) ### Suggestion Fixes/Improvements -* [`box_default`]: The suggestion now includes the type for trait objects, when needed +* [`box_default`]: The suggestion now includes the type for trait objects when needed [#10382](https://github.com/rust-lang/rust-clippy/pull/10382) * [`cast_possible_truncation`]: Now suggests using `try_from` or allowing the lint [#10038](https://github.com/rust-lang/rust-clippy/pull/10038) * [`invalid_regex`]: Regex errors for non-literals or regular strings containing escape sequences will now show the complete error [#10231](https://github.com/rust-lang/rust-clippy/pull/10231) -* [`transmutes_expressible_as_ptr_casts`]: The suggestion now works, if the base type is borrowed +* [`transmutes_expressible_as_ptr_casts`]: The suggestion now works if the base type is borrowed [#10193](https://github.com/rust-lang/rust-clippy/pull/10193) * [`needless_return`]: Now removes all semicolons on the same line [#10187](https://github.com/rust-lang/rust-clippy/pull/10187) @@ -113,7 +113,7 @@ Current stable, released 2023-04-20 ### ICE Fixes -* [`needless_pass_by_value`]: Fixed an ICE, caused by how late bounds were handled +* [`needless_pass_by_value`]: Fixed an ICE caused by how late bounds were handled [#10328](https://github.com/rust-lang/rust-clippy/pull/10328) * [`needless_borrow`]: No longer panics on ambiguous projections [#10403](https://github.com/rust-lang/rust-clippy/pull/10403) From aa6c27a74e00e8e98cd3ce3e0db6149bb5bc7bcf Mon Sep 17 00:00:00 2001 From: Centri3 <114838443+Centri3@users.noreply.github.com> Date: Tue, 25 Apr 2023 11:14:52 -0500 Subject: [PATCH 50/86] change names to not be implicitly negative --- clippy_lints/src/lib.rs | 8 +- clippy_lints/src/semicolon_block.rs | 132 +++++++++--------- clippy_lints/src/utils/conf.rs | 4 +- tests/ui-toml/semicolon_block/clippy.toml | 4 +- .../toml_unknown_key/conf_unknown_key.stderr | 4 +- 5 files changed, 73 insertions(+), 79 deletions(-) diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index cb223ce9d16af..d8bfb84537d70 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -932,12 +932,12 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|_| Box::new(from_raw_with_void_ptr::FromRawWithVoidPtr)); store.register_late_pass(|_| Box::new(suspicious_xor_used_as_pow::ConfusingXorAndPow)); store.register_late_pass(move |_| Box::new(manual_is_ascii_check::ManualIsAsciiCheck::new(msrv()))); - let semicolon_inside_block_if_multiline = conf.semicolon_inside_block_if_multiline; - let semicolon_outside_block_if_singleline = conf.semicolon_outside_block_if_singleline; + let semicolon_inside_block_ignore_singleline = conf.semicolon_inside_block_ignore_singleline; + let semicolon_outside_block_ignore_multiline = conf.semicolon_outside_block_ignore_multiline; store.register_late_pass(move |_| { Box::new(semicolon_block::SemicolonBlock::new( - semicolon_inside_block_if_multiline, - semicolon_outside_block_if_singleline, + semicolon_inside_block_ignore_singleline, + semicolon_outside_block_ignore_multiline, )) }); store.register_late_pass(|_| Box::new(fn_null_check::FnNullCheck)); diff --git a/clippy_lints/src/semicolon_block.rs b/clippy_lints/src/semicolon_block.rs index c1c0325b786b7..419d7991f0ec0 100644 --- a/clippy_lints/src/semicolon_block.rs +++ b/clippy_lints/src/semicolon_block.rs @@ -68,17 +68,73 @@ impl_lint_pass!(SemicolonBlock => [SEMICOLON_INSIDE_BLOCK, SEMICOLON_OUTSIDE_BLO #[derive(Copy, Clone)] pub struct SemicolonBlock { - semicolon_inside_block_if_multiline: bool, - semicolon_outside_block_if_singleline: bool, + semicolon_inside_block_ignore_singleline: bool, + semicolon_outside_block_ignore_multiline: bool, } impl SemicolonBlock { - pub fn new(semicolon_inside_block_if_multiline: bool, semicolon_outside_block_if_singleline: bool) -> Self { + pub fn new(semicolon_inside_block_ignore_singleline: bool, semicolon_outside_block_ignore_multiline: bool) -> Self { Self { - semicolon_inside_block_if_multiline, - semicolon_outside_block_if_singleline, + semicolon_inside_block_ignore_singleline, + semicolon_outside_block_ignore_multiline, } } + + fn semicolon_inside_block(self, cx: &LateContext<'_>, block: &Block<'_>, tail: &Expr<'_>, semi_span: Span) { + let insert_span = tail.span.source_callsite().shrink_to_hi(); + let remove_span = semi_span.with_lo(block.span.hi()); + + if self.semicolon_inside_block_ignore_singleline && get_line(cx, remove_span) == get_line(cx, insert_span) { + return; + } + + span_lint_and_then( + cx, + SEMICOLON_INSIDE_BLOCK, + semi_span, + "consider moving the `;` inside the block for consistent formatting", + |diag| { + multispan_sugg_with_applicability( + diag, + "put the `;` here", + Applicability::MachineApplicable, + [(remove_span, String::new()), (insert_span, ";".to_owned())], + ); + }, + ); + } + + fn semicolon_outside_block( + self, + cx: &LateContext<'_>, + block: &Block<'_>, + tail_stmt_expr: &Expr<'_>, + semi_span: Span, + ) { + let insert_span = block.span.with_lo(block.span.hi()); + // account for macro calls + let semi_span = cx.sess().source_map().stmt_span(semi_span, block.span); + let remove_span = semi_span.with_lo(tail_stmt_expr.span.source_callsite().hi()); + + if self.semicolon_outside_block_ignore_multiline && get_line(cx, remove_span) != get_line(cx, insert_span) { + return; + } + + span_lint_and_then( + cx, + SEMICOLON_OUTSIDE_BLOCK, + block.span, + "consider moving the `;` outside the block for consistent formatting", + |diag| { + multispan_sugg_with_applicability( + diag, + "put the `;` here", + Applicability::MachineApplicable, + [(remove_span, String::new()), (insert_span, ";".to_owned())], + ); + }, + ); + } } impl LateLintPass<'_> for SemicolonBlock { @@ -98,81 +154,19 @@ impl LateLintPass<'_> for SemicolonBlock { span, .. } = stmt else { return }; - semicolon_outside_block(self, cx, block, expr, span); + self.semicolon_outside_block(cx, block, expr, span); }, StmtKind::Semi(Expr { kind: ExprKind::Block(block @ Block { expr: Some(tail), .. }, _), .. }) if !block.span.from_expansion() => { - semicolon_inside_block(self, cx, block, tail, stmt.span); + self.semicolon_inside_block(cx, block, tail, stmt.span); }, _ => (), } } } -fn semicolon_inside_block( - conf: &mut SemicolonBlock, - cx: &LateContext<'_>, - block: &Block<'_>, - tail: &Expr<'_>, - semi_span: Span, -) { - let insert_span = tail.span.source_callsite().shrink_to_hi(); - let remove_span = semi_span.with_lo(block.span.hi()); - - if conf.semicolon_inside_block_if_multiline && get_line(cx, remove_span) == get_line(cx, insert_span) { - return; - } - - span_lint_and_then( - cx, - SEMICOLON_INSIDE_BLOCK, - semi_span, - "consider moving the `;` inside the block for consistent formatting", - |diag| { - multispan_sugg_with_applicability( - diag, - "put the `;` here", - Applicability::MachineApplicable, - [(remove_span, String::new()), (insert_span, ";".to_owned())], - ); - }, - ); -} - -fn semicolon_outside_block( - conf: &mut SemicolonBlock, - cx: &LateContext<'_>, - block: &Block<'_>, - tail_stmt_expr: &Expr<'_>, - semi_span: Span, -) { - let insert_span = block.span.with_lo(block.span.hi()); - // account for macro calls - let semi_span = cx.sess().source_map().stmt_span(semi_span, block.span); - let remove_span = semi_span.with_lo(tail_stmt_expr.span.source_callsite().hi()); - - if conf.semicolon_outside_block_if_singleline && get_line(cx, remove_span) != get_line(cx, insert_span) { - return; - } - - span_lint_and_then( - cx, - SEMICOLON_OUTSIDE_BLOCK, - block.span, - "consider moving the `;` outside the block for consistent formatting", - |diag| { - multispan_sugg_with_applicability( - diag, - "put the `;` here", - Applicability::MachineApplicable, - [(remove_span, String::new()), (insert_span, ";".to_owned())], - ); - }, - ); -} - fn get_line(cx: &LateContext<'_>, span: Span) -> Option { if let Ok(line) = cx.sess().source_map().lookup_line(span.lo()) { return Some(line.line); diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index 939f6cd5f1fcf..18a6e2a4a3a61 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -280,11 +280,11 @@ define_Conf! { /// Lint: SEMICOLON_INSIDE_BLOCK. /// /// Whether to lint only if it's multiline. - (semicolon_inside_block_if_multiline: bool = false), + (semicolon_inside_block_ignore_singleline: bool = false), /// Lint: SEMICOLON_OUTSIDE_BLOCK. /// /// Whether to lint only if it's singleline. - (semicolon_outside_block_if_singleline: bool = false), + (semicolon_outside_block_ignore_multiline: bool = false), /// Lint: DOC_MARKDOWN. /// /// The list of words this lint should not consider as identifiers needing ticks. The value diff --git a/tests/ui-toml/semicolon_block/clippy.toml b/tests/ui-toml/semicolon_block/clippy.toml index cc3bc8cae14be..4d03e88deba8a 100644 --- a/tests/ui-toml/semicolon_block/clippy.toml +++ b/tests/ui-toml/semicolon_block/clippy.toml @@ -1,2 +1,2 @@ -semicolon-inside-block-if-multiline = true -semicolon-outside-block-if-singleline = true +semicolon-inside-block-ignore-singleline = true +semicolon-outside-block-ignore-multiline = true diff --git a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr index c49c9087946da..1e0d7499c7e7f 100644 --- a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr +++ b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr @@ -37,8 +37,8 @@ error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown fie missing-docs-in-crate-items msrv pass-by-value-size-limit - semicolon-inside-block-if-multiline - semicolon-outside-block-if-singleline + semicolon-inside-block-ignore-singleline + semicolon-outside-block-ignore-multiline single-char-binding-names-threshold standard-macro-braces suppress-restriction-lint-in-const From e3ee10d42851fa2fd88216773b6835b5125e1ddc Mon Sep 17 00:00:00 2001 From: Centri3 <114838443+Centri3@users.noreply.github.com> Date: Tue, 25 Apr 2023 11:23:02 -0500 Subject: [PATCH 51/86] use `//@` for commands in tests --- tests/ui-toml/semicolon_block/both.fixed | 2 +- tests/ui-toml/semicolon_block/both.rs | 2 +- tests/ui-toml/semicolon_block/semicolon_inside_block.fixed | 2 +- tests/ui-toml/semicolon_block/semicolon_inside_block.rs | 2 +- tests/ui-toml/semicolon_block/semicolon_outside_block.fixed | 2 +- tests/ui-toml/semicolon_block/semicolon_outside_block.rs | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/ui-toml/semicolon_block/both.fixed b/tests/ui-toml/semicolon_block/both.fixed index 981b661bc7862..fc8038a090715 100644 --- a/tests/ui-toml/semicolon_block/both.fixed +++ b/tests/ui-toml/semicolon_block/both.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow( unused, clippy::unused_unit, diff --git a/tests/ui-toml/semicolon_block/both.rs b/tests/ui-toml/semicolon_block/both.rs index d4dcd6e7240e7..52ce1f0387ee1 100644 --- a/tests/ui-toml/semicolon_block/both.rs +++ b/tests/ui-toml/semicolon_block/both.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow( unused, clippy::unused_unit, diff --git a/tests/ui-toml/semicolon_block/semicolon_inside_block.fixed b/tests/ui-toml/semicolon_block/semicolon_inside_block.fixed index 6a08bc905b112..23df983017735 100644 --- a/tests/ui-toml/semicolon_block/semicolon_inside_block.fixed +++ b/tests/ui-toml/semicolon_block/semicolon_inside_block.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow( unused, clippy::unused_unit, diff --git a/tests/ui-toml/semicolon_block/semicolon_inside_block.rs b/tests/ui-toml/semicolon_block/semicolon_inside_block.rs index f40848f702e1c..e8516f79b20cd 100644 --- a/tests/ui-toml/semicolon_block/semicolon_inside_block.rs +++ b/tests/ui-toml/semicolon_block/semicolon_inside_block.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow( unused, clippy::unused_unit, diff --git a/tests/ui-toml/semicolon_block/semicolon_outside_block.fixed b/tests/ui-toml/semicolon_block/semicolon_outside_block.fixed index e2d653dc3c35c..7e9055e71106a 100644 --- a/tests/ui-toml/semicolon_block/semicolon_outside_block.fixed +++ b/tests/ui-toml/semicolon_block/semicolon_outside_block.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow( unused, clippy::unused_unit, diff --git a/tests/ui-toml/semicolon_block/semicolon_outside_block.rs b/tests/ui-toml/semicolon_block/semicolon_outside_block.rs index 7ce46431fac9a..4dc956d8a4b51 100644 --- a/tests/ui-toml/semicolon_block/semicolon_outside_block.rs +++ b/tests/ui-toml/semicolon_block/semicolon_outside_block.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow( unused, clippy::unused_unit, From 9cf96429a7ae13f89def17def0b70aa61d2672eb Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Tue, 25 Apr 2023 16:31:51 +0000 Subject: [PATCH 52/86] Use `ty::TraitRef::new` in clippy --- clippy_lints/src/derive.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/derive.rs b/clippy_lints/src/derive.rs index f425dd5fb70b5..8f5d319cd4fc1 100644 --- a/clippy_lints/src/derive.rs +++ b/clippy_lints/src/derive.rs @@ -517,7 +517,7 @@ fn param_env_for_derived_eq(tcx: TyCtxt<'_>, did: DefId, eq_trait_id: DefId) -> tcx.mk_predicates_from_iter(ty_predicates.iter().map(|&(p, _)| p).chain( params.iter().filter(|&&(_, needs_eq)| needs_eq).map(|&(param, _)| { tcx.mk_predicate(Binder::dummy(PredicateKind::Clause(Clause::Trait(TraitPredicate { - trait_ref: tcx.mk_trait_ref(eq_trait_id, [tcx.mk_param_from_def(param)]), + trait_ref: ty::TraitRef::new(tcx, eq_trait_id, [tcx.mk_param_from_def(param)]), constness: BoundConstness::NotConst, polarity: ImplPolarity::Positive, })))) From 8c8cf407074b2a1d56a285a575035e1c454c3195 Mon Sep 17 00:00:00 2001 From: Centri3 <114838443+Centri3@users.noreply.github.com> Date: Tue, 25 Apr 2023 14:44:56 -0500 Subject: [PATCH 53/86] Update lint_configuration.md --- book/src/lint_configuration.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md index 78e1a55cff32e..16d19965868c0 100644 --- a/book/src/lint_configuration.md +++ b/book/src/lint_configuration.md @@ -13,6 +13,8 @@ Please use that command to update the file and do not edit it by hand. | [msrv](#msrv) | `None` | | [cognitive-complexity-threshold](#cognitive-complexity-threshold) | `25` | | [disallowed-names](#disallowed-names) | `["foo", "baz", "quux"]` | +| [semicolon-inside-block-ignore-singleline](#semicolon-inside-block-ignore-singleline) | `false` | +| [semicolon-outside-block-ignore-multiline](#semicolon-outside-block-ignore-multiline) | `false` | | [doc-valid-idents](#doc-valid-idents) | `["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "DirectX", "ECMAScript", "GPLv2", "GPLv3", "GitHub", "GitLab", "IPv4", "IPv6", "ClojureScript", "CoffeeScript", "JavaScript", "PureScript", "TypeScript", "NaN", "NaNs", "OAuth", "GraphQL", "OCaml", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenDNS", "WebGL", "TensorFlow", "TrueType", "iOS", "macOS", "FreeBSD", "TeX", "LaTeX", "BibTeX", "BibLaTeX", "MinGW", "CamelCase"]` | | [too-many-arguments-threshold](#too-many-arguments-threshold) | `7` | | [type-complexity-threshold](#type-complexity-threshold) | `250` | @@ -202,6 +204,22 @@ default configuration of Clippy. By default, any configuration will replace the * [disallowed_names](https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_names) +### semicolon-inside-block-ignore-singleline +Whether to lint only if it's multiline. + +**Default Value:** `false` (`bool`) + +* [semicolon_inside_block](https://rust-lang.github.io/rust-clippy/master/index.html#semicolon_inside_block) + + +### semicolon-outside-block-ignore-multiline +Whether to lint only if it's singleline. + +**Default Value:** `false` (`bool`) + +* [semicolon_outside_block](https://rust-lang.github.io/rust-clippy/master/index.html#semicolon_outside_block) + + ### doc-valid-idents The list of words this lint should not consider as identifiers needing ticks. The value `".."` can be used as part of the list to indicate, that the configured values should be appended to the From 95648951ea98f4c59f923f7c10b8742df841d66d Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Wed, 26 Apr 2023 13:48:56 +0000 Subject: [PATCH 54/86] Fix uses of `TraitRef::identity` in clippy and rustdoc --- clippy_lints/src/escape.rs | 3 +-- clippy_lints/src/methods/mod.rs | 6 ++---- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/clippy_lints/src/escape.rs b/clippy_lints/src/escape.rs index d6ab4c25e83ef..6615f9c995375 100644 --- a/clippy_lints/src/escape.rs +++ b/clippy_lints/src/escape.rs @@ -94,8 +94,7 @@ impl<'tcx> LateLintPass<'tcx> for BoxedLocal { if trait_item.kind == (AssocItemKind::Fn { has_self: true }) { trait_self_ty = Some( TraitRef::identity(cx.tcx, trait_item.id.owner_id.to_def_id()) - .self_ty() - .skip_binder(), + .self_ty(), ); } } diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 9cafbc2e5f5a6..09e097285730a 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3500,8 +3500,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { let first_arg_span = first_arg_ty.span; let first_arg_ty = hir_ty_to_ty(cx.tcx, first_arg_ty); let self_ty = TraitRef::identity(cx.tcx, item.owner_id.to_def_id()) - .self_ty() - .skip_binder(); + .self_ty(); wrong_self_convention::check( cx, item.ident.name.as_str(), @@ -3519,8 +3518,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { if let TraitItemKind::Fn(_, _) = item.kind; let ret_ty = return_ty(cx, item.owner_id); let self_ty = TraitRef::identity(cx.tcx, item.owner_id.to_def_id()) - .self_ty() - .skip_binder(); + .self_ty(); if !ret_ty.contains(self_ty); then { From 9428138562bad89fc2d7d011fe276cd198e6155a Mon Sep 17 00:00:00 2001 From: Icxolu <10486322+Icxolu@users.noreply.github.com> Date: Tue, 25 Apr 2023 20:44:09 +0200 Subject: [PATCH 55/86] adds lint to detect construction of unit struct using `default` Using `default` to construct a unit struct increases code complexity and adds a function call. This can be avoided by simply removing the call to `default` and simply construct by name. --- CHANGELOG.md | 1 + clippy_lints/src/declared_lints.rs | 1 + .../src/default_constructed_unit_struct.rs | 66 +++++++++++++++++ clippy_lints/src/lib.rs | 2 + tests/ui/default_constructed_unit_struct.rs | 72 +++++++++++++++++++ .../ui/default_constructed_unit_struct.stderr | 28 ++++++++ 6 files changed, 170 insertions(+) create mode 100644 clippy_lints/src/default_constructed_unit_struct.rs create mode 100644 tests/ui/default_constructed_unit_struct.rs create mode 100644 tests/ui/default_constructed_unit_struct.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 23f4f97ee07c5..735ac59758a64 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4582,6 +4582,7 @@ Released 2018-09-13 [`debug_assert_with_mut_call`]: https://rust-lang.github.io/rust-clippy/master/index.html#debug_assert_with_mut_call [`decimal_literal_representation`]: https://rust-lang.github.io/rust-clippy/master/index.html#decimal_literal_representation [`declare_interior_mutable_const`]: https://rust-lang.github.io/rust-clippy/master/index.html#declare_interior_mutable_const +[`default_constructed_unit_struct`]: https://rust-lang.github.io/rust-clippy/master/index.html#default_constructed_unit_struct [`default_instead_of_iter_empty`]: https://rust-lang.github.io/rust-clippy/master/index.html#default_instead_of_iter_empty [`default_numeric_fallback`]: https://rust-lang.github.io/rust-clippy/master/index.html#default_numeric_fallback [`default_trait_access`]: https://rust-lang.github.io/rust-clippy/master/index.html#default_trait_access diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 4aebd0b7d011f..bf30f5b52f7d2 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -105,6 +105,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::dbg_macro::DBG_MACRO_INFO, crate::default::DEFAULT_TRAIT_ACCESS_INFO, crate::default::FIELD_REASSIGN_WITH_DEFAULT_INFO, + crate::default_constructed_unit_struct::DEFAULT_CONSTRUCTED_UNIT_STRUCT_INFO, crate::default_instead_of_iter_empty::DEFAULT_INSTEAD_OF_ITER_EMPTY_INFO, crate::default_numeric_fallback::DEFAULT_NUMERIC_FALLBACK_INFO, crate::default_union_representation::DEFAULT_UNION_REPRESENTATION_INFO, diff --git a/clippy_lints/src/default_constructed_unit_struct.rs b/clippy_lints/src/default_constructed_unit_struct.rs new file mode 100644 index 0000000000000..a04f7b9d9a9fd --- /dev/null +++ b/clippy_lints/src/default_constructed_unit_struct.rs @@ -0,0 +1,66 @@ +use clippy_utils::{diagnostics::span_lint_and_sugg, is_from_proc_macro, match_def_path, paths}; +use hir::{def::Res, ExprKind}; +use rustc_errors::Applicability; +use rustc_hir as hir; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty; +use rustc_session::{declare_lint_pass, declare_tool_lint}; + +declare_clippy_lint! { + /// ### What it does + /// Check for construction on unit struct using `default`. + /// + /// ### Why is this bad? + /// This adds code complexity and an unnecessary function call. + /// + /// ### Example + /// ```rust + /// #[derive(Default)] + /// struct S { + /// _marker: PhantomData + /// } + /// + /// let _: S = S { + /// _marker: PhantomData::default() + /// }; + /// ``` + /// Use instead: + /// ```rust + /// let _: S = Something { + /// _marker: PhantomData + /// } + /// ``` + #[clippy::version = "1.71.0"] + pub DEFAULT_CONSTRUCTED_UNIT_STRUCT, + complexity, + "unit structs can be contructed without calling `default`" +} +declare_lint_pass!(DefaultConstructedUnitStruct => [DEFAULT_CONSTRUCTED_UNIT_STRUCT]); + +impl LateLintPass<'_> for DefaultConstructedUnitStruct { + fn check_expr<'tcx>(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) { + if_chain!( + // make sure we have a call to `Default::default` + if let hir::ExprKind::Call(fn_expr, &[]) = expr.kind; + if let ExprKind::Path(ref qpath) = fn_expr.kind; + if let Res::Def(_, def_id) = cx.qpath_res(qpath, fn_expr.hir_id); + if match_def_path(cx, def_id, &paths::DEFAULT_TRAIT_METHOD); + // make sure we have a struct with no fields (unit struct) + if let ty::Adt(def, ..) = cx.typeck_results().expr_ty(expr).kind(); + if def.is_struct() && def.is_payloadfree() + && !def.non_enum_variant().is_field_list_non_exhaustive() + && !is_from_proc_macro(cx, expr); + then { + span_lint_and_sugg( + cx, + DEFAULT_CONSTRUCTED_UNIT_STRUCT, + qpath.last_segment_span(), + "Use of `default` to create a unit struct.", + "remove this call to `default`", + String::new(), + Applicability::MachineApplicable, + ) + } + ); + } +} diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 48dbecc9f6aa2..9af0b17e27bce 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -94,6 +94,7 @@ mod crate_in_macro_def; mod create_dir; mod dbg_macro; mod default; +mod default_constructed_unit_struct; mod default_instead_of_iter_empty; mod default_numeric_fallback; mod default_union_representation; @@ -970,6 +971,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|_| Box::new(manual_slice_size_calculation::ManualSliceSizeCalculation)); store.register_early_pass(|| Box::new(suspicious_doc_comments::SuspiciousDocComments)); store.register_late_pass(|_| Box::new(items_after_test_module::ItemsAfterTestModule)); + store.register_late_pass(|_| Box::new(default_constructed_unit_struct::DefaultConstructedUnitStruct)); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/tests/ui/default_constructed_unit_struct.rs b/tests/ui/default_constructed_unit_struct.rs new file mode 100644 index 0000000000000..b64da9b863ac4 --- /dev/null +++ b/tests/ui/default_constructed_unit_struct.rs @@ -0,0 +1,72 @@ +#![allow(unused)] +#![warn(clippy::default_constructed_unit_struct)] +use std::marker::PhantomData; + +#[derive(Default)] +struct UnitStruct; + +#[derive(Default)] +struct TupleStruct(usize); + +// no lint for derived impl +#[derive(Default)] +struct NormalStruct { + inner: PhantomData, +} + +struct NonDefaultStruct; + +impl NonDefaultStruct { + fn default() -> Self { + Self + } +} + +#[derive(Default)] +enum SomeEnum { + #[default] + Unit, + Tuple(UnitStruct), + Struct { + inner: usize, + }, +} + +impl NormalStruct { + fn new() -> Self { + // should lint + Self { + inner: PhantomData::default(), + } + } +} + +#[derive(Default)] +struct GenericStruct { + t: T, +} + +impl GenericStruct { + fn new() -> Self { + // should not lint + Self { t: T::default() } + } +} + +#[derive(Default)] +#[non_exhaustive] +struct NonExhaustiveStruct; + +fn main() { + // should lint + let _ = PhantomData::::default(); + let _: PhantomData = PhantomData::default(); + let _ = UnitStruct::default(); + + // should not lint + let _ = TupleStruct::default(); + let _ = NormalStruct::default(); + let _ = NonExhaustiveStruct::default(); + let _ = SomeEnum::default(); + let _ = NonDefaultStruct::default(); +} diff --git a/tests/ui/default_constructed_unit_struct.stderr b/tests/ui/default_constructed_unit_struct.stderr new file mode 100644 index 0000000000000..13439414f4a7b --- /dev/null +++ b/tests/ui/default_constructed_unit_struct.stderr @@ -0,0 +1,28 @@ +error: Use of `default` to create a unit struct. + --> $DIR/default_constructed_unit_struct.rs:39:33 + | +LL | inner: PhantomData::default(), + | ^^^^^^^ help: remove this call to `default` + | + = note: `-D clippy::default-constructed-unit-struct` implied by `-D warnings` + +error: Use of `default` to create a unit struct. + --> $DIR/default_constructed_unit_struct.rs:62:35 + | +LL | let _ = PhantomData::::default(); + | ^^^^^^^ help: remove this call to `default` + +error: Use of `default` to create a unit struct. + --> $DIR/default_constructed_unit_struct.rs:63:44 + | +LL | let _: PhantomData = PhantomData::default(); + | ^^^^^^^ help: remove this call to `default` + +error: Use of `default` to create a unit struct. + --> $DIR/default_constructed_unit_struct.rs:64:25 + | +LL | let _ = UnitStruct::default(); + | ^^^^^^^ help: remove this call to `default` + +error: aborting due to 4 previous errors + From 0339d4e982e21dd29c473f945bf23a0a119648f5 Mon Sep 17 00:00:00 2001 From: Boxy Date: Thu, 27 Apr 2023 08:34:11 +0100 Subject: [PATCH 56/86] rename `needs_infer` to `has_infer` --- clippy_utils/src/ty.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index cb700126c2bd5..a65720116440e 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -226,7 +226,7 @@ pub fn implements_trait_with_env<'tcx>( ty_params: impl IntoIterator>>, ) -> bool { // Clippy shouldn't have infer types - assert!(!ty.needs_infer()); + assert!(!ty.has_infer()); let ty = tcx.erase_regions(ty); if ty.has_escaping_bound_vars() { From 273c898aefeaec89b547f07bce98ad34aee8d38a Mon Sep 17 00:00:00 2001 From: blyxyas Date: Thu, 27 Apr 2023 16:43:51 +0200 Subject: [PATCH 57/86] Fix #10713 and move the tests to a subdir --- clippy_lints/src/items_after_test_module.rs | 15 ++++++++------- .../block_module.rs} | 0 .../block_module.stderr} | 2 +- .../items_after_test_module/imported_module.rs | 17 +++++++++++++++++ .../imported_module.stderr | 0 tests/ui/items_after_test_module/tests/mod.rs | 1 + 6 files changed, 27 insertions(+), 8 deletions(-) rename tests/ui/{items_after_test_module.rs => items_after_test_module/block_module.rs} (100%) rename tests/ui/{items_after_test_module.stderr => items_after_test_module/block_module.stderr} (89%) create mode 100644 tests/ui/items_after_test_module/imported_module.rs create mode 100644 tests/ui/items_after_test_module/imported_module.stderr create mode 100644 tests/ui/items_after_test_module/tests/mod.rs diff --git a/clippy_lints/src/items_after_test_module.rs b/clippy_lints/src/items_after_test_module.rs index 52d716feea02f..96097575c9cb7 100644 --- a/clippy_lints/src/items_after_test_module.rs +++ b/clippy_lints/src/items_after_test_module.rs @@ -64,20 +64,21 @@ impl LateLintPass<'_> for ItemsAfterTestModule { span_lint_and_help(cx, ITEMS_AFTER_TEST_MODULE, test_mod_span.unwrap().with_hi(item.span.hi()), "items were found after the testing module", None, "move the items to before the testing module was defined"); }}; - if matches!(item.kind, ItemKind::Mod(_)) { - for attr in cx.tcx.get_attrs(item.owner_id.to_def_id(), sym::cfg) { - if_chain! { - if attr.has_name(sym::cfg); + if let ItemKind::Mod(module) = item.kind && item.span.hi() == module.spans.inner_span.hi() { + // Check that it works the same way, the only I way I've found for #10713 + for attr in cx.tcx.get_attrs(item.owner_id.to_def_id(), sym::cfg) { + if_chain! { + if attr.has_name(sym::cfg); if let Some(mitems) = attr.meta_item_list(); if let [mitem] = &*mitems; if mitem.has_name(sym::test); then { - was_test_mod_visited = true; - test_mod_span = Some(item.span); + was_test_mod_visited = true; + test_mod_span = Some(module.spans.inner_span.with_lo(item.span.lo())); } } } - } + } } } } diff --git a/tests/ui/items_after_test_module.rs b/tests/ui/items_after_test_module/block_module.rs similarity index 100% rename from tests/ui/items_after_test_module.rs rename to tests/ui/items_after_test_module/block_module.rs diff --git a/tests/ui/items_after_test_module.stderr b/tests/ui/items_after_test_module/block_module.stderr similarity index 89% rename from tests/ui/items_after_test_module.stderr rename to tests/ui/items_after_test_module/block_module.stderr index 8f1616dabc1f0..597f1b9510c56 100644 --- a/tests/ui/items_after_test_module.stderr +++ b/tests/ui/items_after_test_module/block_module.stderr @@ -1,5 +1,5 @@ error: items were found after the testing module - --> $DIR/items_after_test_module.rs:13:1 + --> $DIR/block_module.rs:13:1 | LL | / mod tests { LL | | #[test] diff --git a/tests/ui/items_after_test_module/imported_module.rs b/tests/ui/items_after_test_module/imported_module.rs new file mode 100644 index 0000000000000..819b6c8a9e084 --- /dev/null +++ b/tests/ui/items_after_test_module/imported_module.rs @@ -0,0 +1,17 @@ +//@compile-flags: --test +#![allow(unused)] +#![warn(clippy::items_after_test_module)] + +fn main() {} + +fn should_not_lint() {} + +#[cfg(test)] +mod tests; // Should not lint + +fn should_lint() {} + +const SHOULD_ALSO_LINT: usize = 1; +macro_rules! should_not_lint { + () => {}; +} diff --git a/tests/ui/items_after_test_module/imported_module.stderr b/tests/ui/items_after_test_module/imported_module.stderr new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/tests/ui/items_after_test_module/tests/mod.rs b/tests/ui/items_after_test_module/tests/mod.rs new file mode 100644 index 0000000000000..f328e4d9d04c3 --- /dev/null +++ b/tests/ui/items_after_test_module/tests/mod.rs @@ -0,0 +1 @@ +fn main() {} From 83504fa7638d70aa726b02ec0fd1ad5d170ae1d1 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 25 Apr 2023 19:52:17 +0000 Subject: [PATCH 58/86] Make clippy happy --- .../src/suspicious_operation_groupings.rs | 2 +- clippy_utils/src/ast_utils.rs | 2 +- tests/ui/future_not_send.stderr | 24 +++++++++---------- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/clippy_lints/src/suspicious_operation_groupings.rs b/clippy_lints/src/suspicious_operation_groupings.rs index fab8e9c2ec1c1..e2cdc48b583c8 100644 --- a/clippy_lints/src/suspicious_operation_groupings.rs +++ b/clippy_lints/src/suspicious_operation_groupings.rs @@ -577,7 +577,7 @@ fn ident_difference_expr_with_base_location( | (AssignOp(_, _, _), AssignOp(_, _, _)) | (Assign(_, _, _), Assign(_, _, _)) | (TryBlock(_), TryBlock(_)) - | (Await(_), Await(_)) + | (Await(_, _), Await(_, _)) | (Async(_, _), Async(_, _)) | (Block(_, _), Block(_, _)) | (Closure(_), Closure(_)) diff --git a/clippy_utils/src/ast_utils.rs b/clippy_utils/src/ast_utils.rs index 1f15598db36d9..8cc01f1ef9740 100644 --- a/clippy_utils/src/ast_utils.rs +++ b/clippy_utils/src/ast_utils.rs @@ -143,7 +143,7 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool { (Paren(l), _) => eq_expr(l, r), (_, Paren(r)) => eq_expr(l, r), (Err, Err) => true, - (Try(l), Try(r)) | (Await(l), Await(r)) => eq_expr(l, r), + (Try(l), Try(r)) | (Await(l, _), Await(r, _)) => eq_expr(l, r), (Array(l), Array(r)) => over(l, r, |l, r| eq_expr(l, r)), (Tup(l), Tup(r)) => over(l, r, |l, r| eq_expr(l, r)), (Repeat(le, ls), Repeat(re, rs)) => eq_expr(le, re) && eq_expr(&ls.value, &rs.value), diff --git a/tests/ui/future_not_send.stderr b/tests/ui/future_not_send.stderr index 5b6858e4568b5..5c6348962a5eb 100644 --- a/tests/ui/future_not_send.stderr +++ b/tests/ui/future_not_send.stderr @@ -5,22 +5,22 @@ LL | async fn private_future(rc: Rc<[u8]>, cell: &Cell) -> bool { | ^^^^ future returned by `private_future` is not `Send` | note: future is not `Send` as this value is used across an await - --> $DIR/future_not_send.rs:8:19 + --> $DIR/future_not_send.rs:8:20 | LL | async fn private_future(rc: Rc<[u8]>, cell: &Cell) -> bool { | -- has type `std::rc::Rc<[u8]>` which is not `Send` LL | async { true }.await - | ^^^^^^ await occurs here, with `rc` maybe used later + | ^^^^^ await occurs here, with `rc` maybe used later LL | } | - `rc` is later dropped here = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Send` note: future is not `Send` as this value is used across an await - --> $DIR/future_not_send.rs:8:19 + --> $DIR/future_not_send.rs:8:20 | LL | async fn private_future(rc: Rc<[u8]>, cell: &Cell) -> bool { | ---- has type `&std::cell::Cell` which is not `Send` LL | async { true }.await - | ^^^^^^ await occurs here, with `cell` maybe used later + | ^^^^^ await occurs here, with `cell` maybe used later LL | } | - `cell` is later dropped here = note: `std::cell::Cell` doesn't implement `std::marker::Sync` @@ -33,12 +33,12 @@ LL | pub async fn public_future(rc: Rc<[u8]>) { | ^ future returned by `public_future` is not `Send` | note: future is not `Send` as this value is used across an await - --> $DIR/future_not_send.rs:12:19 + --> $DIR/future_not_send.rs:12:20 | LL | pub async fn public_future(rc: Rc<[u8]>) { | -- has type `std::rc::Rc<[u8]>` which is not `Send` LL | async { true }.await; - | ^^^^^^ await occurs here, with `rc` maybe used later + | ^^^^^ await occurs here, with `rc` maybe used later LL | } | - `rc` is later dropped here = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Send` @@ -82,12 +82,12 @@ LL | async fn private_future(&self) -> usize { | ^^^^^ future returned by `private_future` is not `Send` | note: future is not `Send` as this value is used across an await - --> $DIR/future_not_send.rs:35:23 + --> $DIR/future_not_send.rs:35:24 | LL | async fn private_future(&self) -> usize { | ----- has type `&Dummy` which is not `Send` LL | async { true }.await; - | ^^^^^^ await occurs here, with `&self` maybe used later + | ^^^^^ await occurs here, with `&self` maybe used later LL | self.rc.len() LL | } | - `&self` is later dropped here @@ -100,12 +100,12 @@ LL | pub async fn public_future(&self) { | ^ future returned by `public_future` is not `Send` | note: future is not `Send` as this value is used across an await - --> $DIR/future_not_send.rs:40:30 + --> $DIR/future_not_send.rs:40:31 | LL | pub async fn public_future(&self) { | ----- has type `&Dummy` which is not `Send` LL | self.private_future().await; - | ^^^^^^ await occurs here, with `&self` maybe used later + | ^^^^^ await occurs here, with `&self` maybe used later LL | } | - `&self` is later dropped here = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Sync` @@ -117,12 +117,12 @@ LL | async fn generic_future(t: T) -> T | ^ future returned by `generic_future` is not `Send` | note: future is not `Send` as this value is used across an await - --> $DIR/future_not_send.rs:54:19 + --> $DIR/future_not_send.rs:54:20 | LL | let rt = &t; | -- has type `&T` which is not `Send` LL | async { true }.await; - | ^^^^^^ await occurs here, with `rt` maybe used later + | ^^^^^ await occurs here, with `rt` maybe used later LL | t LL | } | - `rt` is later dropped here From d1f55e6b5313ec389f323a149b7cb4628e97a03a Mon Sep 17 00:00:00 2001 From: Sergen Karaoglan <38327805+SergenKaraoglan@users.noreply.github.com> Date: Thu, 27 Apr 2023 18:43:51 +0100 Subject: [PATCH 59/86] run linkcheck in Remark CI fix new lints link install nightly rust-docs run linkcheck without nightly toolchain remove nightly toolchain, add rust-docs component Test Remark Update basics.md Update basics.md Update basics.md update workflow add rust docs toolchain Update remark.yml workflow test manual test update book path add linkcheck book to CI Update lint_passes.md --- .github/workflows/remark.yml | 6 ++++++ book/src/development/lint_passes.md | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/remark.yml b/.github/workflows/remark.yml index 116058b7c7538..0bc2f49f5e9b5 100644 --- a/.github/workflows/remark.yml +++ b/.github/workflows/remark.yml @@ -36,6 +36,12 @@ jobs: - name: Check *.md files run: git ls-files -z '*.md' | xargs -0 -n 1 -I {} ./node_modules/.bin/remark {} -u lint -f > /dev/null + - name: Linkcheck book + run: | + rustup toolchain install nightly --component rust-docs + curl https://raw.githubusercontent.com/rust-lang/rust/master/src/tools/linkchecker/linkcheck.sh -o linkcheck.sh + sh linkcheck.sh clippy --path ./book + - name: Build mdbook run: mdbook build book diff --git a/book/src/development/lint_passes.md b/book/src/development/lint_passes.md index c41b6ea0de8fe..621fc20972ea1 100644 --- a/book/src/development/lint_passes.md +++ b/book/src/development/lint_passes.md @@ -50,7 +50,7 @@ questions already, but the parser is okay with it. This is what we mean when we say `EarlyLintPass` deals with only syntax on the AST level. Alternatively, think of the `foo_functions` lint we mentioned in -[define new lints](define_lints.md#name-the-lint) chapter. +define new lints chapter. We want the `foo_functions` lint to detect functions with `foo` as their name. Writing a lint that only checks for the name of a function means that we only From 81a614145f689fca24bed3020eb7837aee1d874d Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Fri, 28 Apr 2023 17:17:46 +0000 Subject: [PATCH 60/86] uplift `clippy::clone_double_ref` as `suspicious_double_ref_op` --- clippy_lints/src/declared_lints.rs | 1 - clippy_lints/src/methods/clone_on_copy.rs | 40 +--------- clippy_lints/src/methods/mod.rs | 24 ------ clippy_lints/src/renamed_lints.rs | 1 + tests/ui/explicit_deref_methods.fixed | 2 +- tests/ui/explicit_deref_methods.rs | 2 +- tests/ui/rename.fixed | 2 + tests/ui/rename.rs | 2 + tests/ui/rename.stderr | 92 ++++++++++++----------- tests/ui/unnecessary_clone.rs | 13 ---- tests/ui/unnecessary_clone.stderr | 52 +------------ 11 files changed, 61 insertions(+), 170 deletions(-) diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 0c66d36a1d630..fa726a649370e 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -313,7 +313,6 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::methods::CHARS_NEXT_CMP_INFO, crate::methods::CLEAR_WITH_DRAIN_INFO, crate::methods::CLONED_INSTEAD_OF_COPIED_INFO, - crate::methods::CLONE_DOUBLE_REF_INFO, crate::methods::CLONE_ON_COPY_INFO, crate::methods::CLONE_ON_REF_PTR_INFO, crate::methods::COLLAPSIBLE_STR_REPLACE_INFO, diff --git a/clippy_lints/src/methods/clone_on_copy.rs b/clippy_lints/src/methods/clone_on_copy.rs index 3795c0ec25098..65fd50dff5846 100644 --- a/clippy_lints/src/methods/clone_on_copy.rs +++ b/clippy_lints/src/methods/clone_on_copy.rs @@ -1,7 +1,6 @@ -use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::get_parent_node; use clippy_utils::source::snippet_with_context; -use clippy_utils::sugg; use clippy_utils::ty::is_copy; use rustc_errors::Applicability; use rustc_hir::{BindingAnnotation, ByRef, Expr, ExprKind, MatchSource, Node, PatKind, QPath}; @@ -9,7 +8,6 @@ use rustc_lint::LateContext; use rustc_middle::ty::{self, adjustment::Adjust, print::with_forced_trimmed_paths}; use rustc_span::symbol::{sym, Symbol}; -use super::CLONE_DOUBLE_REF; use super::CLONE_ON_COPY; /// Checks for the `CLONE_ON_COPY` lint. @@ -42,41 +40,7 @@ pub(super) fn check( let ty = cx.typeck_results().expr_ty(expr); if let ty::Ref(_, inner, _) = arg_ty.kind() { - if let ty::Ref(_, innermost, _) = inner.kind() { - span_lint_and_then( - cx, - CLONE_DOUBLE_REF, - expr.span, - &with_forced_trimmed_paths!(format!( - "using `clone` on a double-reference; \ - this will copy the reference of type `{ty}` instead of cloning the inner type" - )), - |diag| { - if let Some(snip) = sugg::Sugg::hir_opt(cx, arg) { - let mut ty = innermost; - let mut n = 0; - while let ty::Ref(_, inner, _) = ty.kind() { - ty = inner; - n += 1; - } - let refs = "&".repeat(n + 1); - let derefs = "*".repeat(n); - let explicit = with_forced_trimmed_paths!(format!("<{refs}{ty}>::clone({snip})")); - diag.span_suggestion( - expr.span, - "try dereferencing it", - with_forced_trimmed_paths!(format!("{refs}({derefs}{}).clone()", snip.deref())), - Applicability::MaybeIncorrect, - ); - diag.span_suggestion( - expr.span, - "or try being explicit if you are sure, that you want to clone a reference", - explicit, - Applicability::MaybeIncorrect, - ); - } - }, - ); + if let ty::Ref(..) = inner.kind() { return; // don't report clone_on_copy } } diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 9cafbc2e5f5a6..e4a659d3ce73c 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -984,29 +984,6 @@ declare_clippy_lint! { "using 'clone' on a ref-counted pointer" } -declare_clippy_lint! { - /// ### What it does - /// Checks for usage of `.clone()` on an `&&T`. - /// - /// ### Why is this bad? - /// Cloning an `&&T` copies the inner `&T`, instead of - /// cloning the underlying `T`. - /// - /// ### Example - /// ```rust - /// fn main() { - /// let x = vec![1]; - /// let y = &&x; - /// let z = y.clone(); - /// println!("{:p} {:p}", *y, z); // prints out the same pointer - /// } - /// ``` - #[clippy::version = "pre 1.29.0"] - pub CLONE_DOUBLE_REF, - correctness, - "using `clone` on `&&T`" -} - declare_clippy_lint! { /// ### What it does /// Checks for usage of `.to_string()` on an `&&T` where @@ -3258,7 +3235,6 @@ impl_lint_pass!(Methods => [ CHARS_LAST_CMP, CLONE_ON_COPY, CLONE_ON_REF_PTR, - CLONE_DOUBLE_REF, COLLAPSIBLE_STR_REPLACE, ITER_OVEREAGER_CLONED, CLONED_INSTEAD_OF_COPIED, diff --git a/clippy_lints/src/renamed_lints.rs b/clippy_lints/src/renamed_lints.rs index 9f487dedb8cb6..5e81a01a461ab 100644 --- a/clippy_lints/src/renamed_lints.rs +++ b/clippy_lints/src/renamed_lints.rs @@ -30,6 +30,7 @@ pub static RENAMED_LINTS: &[(&str, &str)] = &[ ("clippy::stutter", "clippy::module_name_repetitions"), ("clippy::to_string_in_display", "clippy::recursive_format_impl"), ("clippy::zero_width_space", "clippy::invisible_characters"), + ("clippy::clone_double_ref", "suspicious_double_ref_op"), ("clippy::drop_bounds", "drop_bounds"), ("clippy::for_loop_over_option", "for_loops_over_fallibles"), ("clippy::for_loop_over_result", "for_loops_over_fallibles"), diff --git a/tests/ui/explicit_deref_methods.fixed b/tests/ui/explicit_deref_methods.fixed index 77e9f5fc1fdf1..60482c66da7c4 100644 --- a/tests/ui/explicit_deref_methods.fixed +++ b/tests/ui/explicit_deref_methods.fixed @@ -3,7 +3,7 @@ #![allow(unused_variables)] #![allow( clippy::borrow_deref_ref, - clippy::clone_double_ref, + suspicious_double_ref_op, clippy::explicit_auto_deref, clippy::needless_borrow, clippy::uninlined_format_args diff --git a/tests/ui/explicit_deref_methods.rs b/tests/ui/explicit_deref_methods.rs index 0c2cc7c2c3a6a..e3613e216bb22 100644 --- a/tests/ui/explicit_deref_methods.rs +++ b/tests/ui/explicit_deref_methods.rs @@ -3,7 +3,7 @@ #![allow(unused_variables)] #![allow( clippy::borrow_deref_ref, - clippy::clone_double_ref, + suspicious_double_ref_op, clippy::explicit_auto_deref, clippy::needless_borrow, clippy::uninlined_format_args diff --git a/tests/ui/rename.fixed b/tests/ui/rename.fixed index e8a00a9e7f712..ff19a042825d8 100644 --- a/tests/ui/rename.fixed +++ b/tests/ui/rename.fixed @@ -36,6 +36,7 @@ #![allow(enum_intrinsics_non_enums)] #![allow(non_fmt_panics)] #![allow(named_arguments_used_positionally)] +#![allow(suspicious_double_ref_op)] #![allow(temporary_cstring_as_ptr)] #![allow(unknown_lints)] #![allow(unused_labels)] @@ -67,6 +68,7 @@ #![warn(clippy::module_name_repetitions)] #![warn(clippy::recursive_format_impl)] #![warn(clippy::invisible_characters)] +#![warn(suspicious_double_ref_op)] #![warn(drop_bounds)] #![warn(for_loops_over_fallibles)] #![warn(for_loops_over_fallibles)] diff --git a/tests/ui/rename.rs b/tests/ui/rename.rs index c8ea70c2bcb1d..38b1647c0cca0 100644 --- a/tests/ui/rename.rs +++ b/tests/ui/rename.rs @@ -36,6 +36,7 @@ #![allow(enum_intrinsics_non_enums)] #![allow(non_fmt_panics)] #![allow(named_arguments_used_positionally)] +#![allow(suspicious_double_ref_op)] #![allow(temporary_cstring_as_ptr)] #![allow(unknown_lints)] #![allow(unused_labels)] @@ -67,6 +68,7 @@ #![warn(clippy::stutter)] #![warn(clippy::to_string_in_display)] #![warn(clippy::zero_width_space)] +#![warn(clippy::clone_double_ref)] #![warn(clippy::drop_bounds)] #![warn(clippy::for_loop_over_option)] #![warn(clippy::for_loop_over_result)] diff --git a/tests/ui/rename.stderr b/tests/ui/rename.stderr index 27a0263292ef1..70d15408b9fc1 100644 --- a/tests/ui/rename.stderr +++ b/tests/ui/rename.stderr @@ -1,5 +1,5 @@ error: lint `clippy::almost_complete_letter_range` has been renamed to `clippy::almost_complete_range` - --> $DIR/rename.rs:42:9 + --> $DIR/rename.rs:43:9 | LL | #![warn(clippy::almost_complete_letter_range)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::almost_complete_range` @@ -7,250 +7,256 @@ LL | #![warn(clippy::almost_complete_letter_range)] = note: `-D renamed-and-removed-lints` implied by `-D warnings` error: lint `clippy::blacklisted_name` has been renamed to `clippy::disallowed_names` - --> $DIR/rename.rs:43:9 + --> $DIR/rename.rs:44:9 | LL | #![warn(clippy::blacklisted_name)] | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_names` error: lint `clippy::block_in_if_condition_expr` has been renamed to `clippy::blocks_in_if_conditions` - --> $DIR/rename.rs:44:9 + --> $DIR/rename.rs:45:9 | LL | #![warn(clippy::block_in_if_condition_expr)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions` error: lint `clippy::block_in_if_condition_stmt` has been renamed to `clippy::blocks_in_if_conditions` - --> $DIR/rename.rs:45:9 + --> $DIR/rename.rs:46:9 | LL | #![warn(clippy::block_in_if_condition_stmt)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions` error: lint `clippy::box_vec` has been renamed to `clippy::box_collection` - --> $DIR/rename.rs:46:9 + --> $DIR/rename.rs:47:9 | LL | #![warn(clippy::box_vec)] | ^^^^^^^^^^^^^^^ help: use the new name: `clippy::box_collection` error: lint `clippy::const_static_lifetime` has been renamed to `clippy::redundant_static_lifetimes` - --> $DIR/rename.rs:47:9 + --> $DIR/rename.rs:48:9 | LL | #![warn(clippy::const_static_lifetime)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_static_lifetimes` error: lint `clippy::cyclomatic_complexity` has been renamed to `clippy::cognitive_complexity` - --> $DIR/rename.rs:48:9 + --> $DIR/rename.rs:49:9 | LL | #![warn(clippy::cyclomatic_complexity)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::cognitive_complexity` error: lint `clippy::derive_hash_xor_eq` has been renamed to `clippy::derived_hash_with_manual_eq` - --> $DIR/rename.rs:49:9 + --> $DIR/rename.rs:50:9 | LL | #![warn(clippy::derive_hash_xor_eq)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::derived_hash_with_manual_eq` error: lint `clippy::disallowed_method` has been renamed to `clippy::disallowed_methods` - --> $DIR/rename.rs:50:9 + --> $DIR/rename.rs:51:9 | LL | #![warn(clippy::disallowed_method)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_methods` error: lint `clippy::disallowed_type` has been renamed to `clippy::disallowed_types` - --> $DIR/rename.rs:51:9 + --> $DIR/rename.rs:52:9 | LL | #![warn(clippy::disallowed_type)] | ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_types` error: lint `clippy::eval_order_dependence` has been renamed to `clippy::mixed_read_write_in_expression` - --> $DIR/rename.rs:52:9 + --> $DIR/rename.rs:53:9 | LL | #![warn(clippy::eval_order_dependence)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::mixed_read_write_in_expression` error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion` - --> $DIR/rename.rs:53:9 + --> $DIR/rename.rs:54:9 | LL | #![warn(clippy::identity_conversion)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::useless_conversion` error: lint `clippy::if_let_some_result` has been renamed to `clippy::match_result_ok` - --> $DIR/rename.rs:54:9 + --> $DIR/rename.rs:55:9 | LL | #![warn(clippy::if_let_some_result)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::match_result_ok` error: lint `clippy::logic_bug` has been renamed to `clippy::overly_complex_bool_expr` - --> $DIR/rename.rs:55:9 + --> $DIR/rename.rs:56:9 | LL | #![warn(clippy::logic_bug)] | ^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::overly_complex_bool_expr` error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default` - --> $DIR/rename.rs:56:9 + --> $DIR/rename.rs:57:9 | LL | #![warn(clippy::new_without_default_derive)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default` error: lint `clippy::option_and_then_some` has been renamed to `clippy::bind_instead_of_map` - --> $DIR/rename.rs:57:9 + --> $DIR/rename.rs:58:9 | LL | #![warn(clippy::option_and_then_some)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::bind_instead_of_map` error: lint `clippy::option_expect_used` has been renamed to `clippy::expect_used` - --> $DIR/rename.rs:58:9 + --> $DIR/rename.rs:59:9 | LL | #![warn(clippy::option_expect_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used` error: lint `clippy::option_map_unwrap_or` has been renamed to `clippy::map_unwrap_or` - --> $DIR/rename.rs:59:9 + --> $DIR/rename.rs:60:9 | LL | #![warn(clippy::option_map_unwrap_or)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` error: lint `clippy::option_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or` - --> $DIR/rename.rs:60:9 + --> $DIR/rename.rs:61:9 | LL | #![warn(clippy::option_map_unwrap_or_else)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` error: lint `clippy::option_unwrap_used` has been renamed to `clippy::unwrap_used` - --> $DIR/rename.rs:61:9 + --> $DIR/rename.rs:62:9 | LL | #![warn(clippy::option_unwrap_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used` error: lint `clippy::ref_in_deref` has been renamed to `clippy::needless_borrow` - --> $DIR/rename.rs:62:9 + --> $DIR/rename.rs:63:9 | LL | #![warn(clippy::ref_in_deref)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::needless_borrow` error: lint `clippy::result_expect_used` has been renamed to `clippy::expect_used` - --> $DIR/rename.rs:63:9 + --> $DIR/rename.rs:64:9 | LL | #![warn(clippy::result_expect_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used` error: lint `clippy::result_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or` - --> $DIR/rename.rs:64:9 + --> $DIR/rename.rs:65:9 | LL | #![warn(clippy::result_map_unwrap_or_else)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` error: lint `clippy::result_unwrap_used` has been renamed to `clippy::unwrap_used` - --> $DIR/rename.rs:65:9 + --> $DIR/rename.rs:66:9 | LL | #![warn(clippy::result_unwrap_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used` error: lint `clippy::single_char_push_str` has been renamed to `clippy::single_char_add_str` - --> $DIR/rename.rs:66:9 + --> $DIR/rename.rs:67:9 | LL | #![warn(clippy::single_char_push_str)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::single_char_add_str` error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions` - --> $DIR/rename.rs:67:9 + --> $DIR/rename.rs:68:9 | LL | #![warn(clippy::stutter)] | ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions` error: lint `clippy::to_string_in_display` has been renamed to `clippy::recursive_format_impl` - --> $DIR/rename.rs:68:9 + --> $DIR/rename.rs:69:9 | LL | #![warn(clippy::to_string_in_display)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::recursive_format_impl` error: lint `clippy::zero_width_space` has been renamed to `clippy::invisible_characters` - --> $DIR/rename.rs:69:9 + --> $DIR/rename.rs:70:9 | LL | #![warn(clippy::zero_width_space)] | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::invisible_characters` +error: lint `clippy::clone_double_ref` has been renamed to `suspicious_double_ref_op` + --> $DIR/rename.rs:71:9 + | +LL | #![warn(clippy::clone_double_ref)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `suspicious_double_ref_op` + error: lint `clippy::drop_bounds` has been renamed to `drop_bounds` - --> $DIR/rename.rs:70:9 + --> $DIR/rename.rs:72:9 | LL | #![warn(clippy::drop_bounds)] | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds` error: lint `clippy::for_loop_over_option` has been renamed to `for_loops_over_fallibles` - --> $DIR/rename.rs:71:9 + --> $DIR/rename.rs:73:9 | LL | #![warn(clippy::for_loop_over_option)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles` error: lint `clippy::for_loop_over_result` has been renamed to `for_loops_over_fallibles` - --> $DIR/rename.rs:72:9 + --> $DIR/rename.rs:74:9 | LL | #![warn(clippy::for_loop_over_result)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles` error: lint `clippy::for_loops_over_fallibles` has been renamed to `for_loops_over_fallibles` - --> $DIR/rename.rs:73:9 + --> $DIR/rename.rs:75:9 | LL | #![warn(clippy::for_loops_over_fallibles)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles` error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter` - --> $DIR/rename.rs:74:9 + --> $DIR/rename.rs:76:9 | LL | #![warn(clippy::into_iter_on_array)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter` error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering` - --> $DIR/rename.rs:75:9 + --> $DIR/rename.rs:77:9 | LL | #![warn(clippy::invalid_atomic_ordering)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering` error: lint `clippy::invalid_ref` has been renamed to `invalid_value` - --> $DIR/rename.rs:76:9 + --> $DIR/rename.rs:78:9 | LL | #![warn(clippy::invalid_ref)] | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value` error: lint `clippy::let_underscore_drop` has been renamed to `let_underscore_drop` - --> $DIR/rename.rs:77:9 + --> $DIR/rename.rs:79:9 | LL | #![warn(clippy::let_underscore_drop)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `let_underscore_drop` error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums` - --> $DIR/rename.rs:78:9 + --> $DIR/rename.rs:80:9 | LL | #![warn(clippy::mem_discriminant_non_enum)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums` error: lint `clippy::panic_params` has been renamed to `non_fmt_panics` - --> $DIR/rename.rs:79:9 + --> $DIR/rename.rs:81:9 | LL | #![warn(clippy::panic_params)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics` error: lint `clippy::positional_named_format_parameters` has been renamed to `named_arguments_used_positionally` - --> $DIR/rename.rs:80:9 + --> $DIR/rename.rs:82:9 | LL | #![warn(clippy::positional_named_format_parameters)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `named_arguments_used_positionally` error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr` - --> $DIR/rename.rs:81:9 + --> $DIR/rename.rs:83:9 | LL | #![warn(clippy::temporary_cstring_as_ptr)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr` error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints` - --> $DIR/rename.rs:82:9 + --> $DIR/rename.rs:84:9 | LL | #![warn(clippy::unknown_clippy_lints)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints` error: lint `clippy::unused_label` has been renamed to `unused_labels` - --> $DIR/rename.rs:83:9 + --> $DIR/rename.rs:85:9 | LL | #![warn(clippy::unused_label)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels` -error: aborting due to 42 previous errors +error: aborting due to 43 previous errors diff --git a/tests/ui/unnecessary_clone.rs b/tests/ui/unnecessary_clone.rs index 8b1629b19a769..7ceed3c75fd85 100644 --- a/tests/ui/unnecessary_clone.rs +++ b/tests/ui/unnecessary_clone.rs @@ -42,14 +42,6 @@ fn clone_on_copy_generic(t: T) { Some(t).clone(); } -fn clone_on_double_ref() { - let x = vec![1]; - let y = &&x; - let z: &Vec<_> = y.clone(); - - println!("{:p} {:p}", *y, z); -} - mod many_derefs { struct A; struct B; @@ -84,11 +76,6 @@ mod many_derefs { let _: E = a.clone(); let _: E = *****a; } - - fn check(mut encoded: &[u8]) { - let _ = &mut encoded.clone(); - let _ = &encoded.clone(); - } } mod issue2076 { diff --git a/tests/ui/unnecessary_clone.stderr b/tests/ui/unnecessary_clone.stderr index 6022d9fa4c5c3..5686ab6b4531e 100644 --- a/tests/ui/unnecessary_clone.stderr +++ b/tests/ui/unnecessary_clone.stderr @@ -44,63 +44,17 @@ error: using `clone` on type `Option` which implements the `Copy` trait LL | Some(t).clone(); | ^^^^^^^^^^^^^^^ help: try removing the `clone` call: `Some(t)` -error: using `clone` on a double-reference; this will copy the reference of type `&Vec` instead of cloning the inner type - --> $DIR/unnecessary_clone.rs:48:22 - | -LL | let z: &Vec<_> = y.clone(); - | ^^^^^^^^^ - | - = note: `#[deny(clippy::clone_double_ref)]` on by default -help: try dereferencing it - | -LL | let z: &Vec<_> = &(*y).clone(); - | ~~~~~~~~~~~~~ -help: or try being explicit if you are sure, that you want to clone a reference - | -LL | let z: &Vec<_> = <&Vec>::clone(y); - | ~~~~~~~~~~~~~~~~~~~~~ - error: using `clone` on type `E` which implements the `Copy` trait - --> $DIR/unnecessary_clone.rs:84:20 + --> $DIR/unnecessary_clone.rs:76:20 | LL | let _: E = a.clone(); | ^^^^^^^^^ help: try dereferencing it: `*****a` -error: using `clone` on a double-reference; this will copy the reference of type `&[u8]` instead of cloning the inner type - --> $DIR/unnecessary_clone.rs:89:22 - | -LL | let _ = &mut encoded.clone(); - | ^^^^^^^^^^^^^^^ - | -help: try dereferencing it - | -LL | let _ = &mut &(*encoded).clone(); - | ~~~~~~~~~~~~~~~~~~~ -help: or try being explicit if you are sure, that you want to clone a reference - | -LL | let _ = &mut <&[u8]>::clone(encoded); - | ~~~~~~~~~~~~~~~~~~~~~~~ - -error: using `clone` on a double-reference; this will copy the reference of type `&[u8]` instead of cloning the inner type - --> $DIR/unnecessary_clone.rs:90:18 - | -LL | let _ = &encoded.clone(); - | ^^^^^^^^^^^^^^^ - | -help: try dereferencing it - | -LL | let _ = &&(*encoded).clone(); - | ~~~~~~~~~~~~~~~~~~~ -help: or try being explicit if you are sure, that you want to clone a reference - | -LL | let _ = &<&[u8]>::clone(encoded); - | ~~~~~~~~~~~~~~~~~~~~~~~ - error: using `.clone()` on a ref-counted pointer - --> $DIR/unnecessary_clone.rs:108:14 + --> $DIR/unnecessary_clone.rs:95:14 | LL | Some(try_opt!(Some(rc)).clone()) | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `Rc::::clone(&try_opt!(Some(rc)))` -error: aborting due to 12 previous errors +error: aborting due to 9 previous errors From f37054b396cc67f2633d929c35cd88ecdb383ba8 Mon Sep 17 00:00:00 2001 From: blyxyas Date: Fri, 28 Apr 2023 20:19:36 +0200 Subject: [PATCH 61/86] Remove useless span magic --- clippy_lints/src/items_after_test_module.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/items_after_test_module.rs b/clippy_lints/src/items_after_test_module.rs index 96097575c9cb7..b992d689aa979 100644 --- a/clippy_lints/src/items_after_test_module.rs +++ b/clippy_lints/src/items_after_test_module.rs @@ -74,7 +74,7 @@ impl LateLintPass<'_> for ItemsAfterTestModule { if mitem.has_name(sym::test); then { was_test_mod_visited = true; - test_mod_span = Some(module.spans.inner_span.with_lo(item.span.lo())); + test_mod_span = Some(item.span); } } } From 2b5820d58b62845ac23bda57533b44178c93cb7c Mon Sep 17 00:00:00 2001 From: blyxyas Date: Fri, 28 Apr 2023 20:23:05 +0200 Subject: [PATCH 62/86] Change module import system --- .../items_after_test_module/{tests/mod.rs => auxiliary/tests.rs} | 0 tests/ui/items_after_test_module/imported_module.rs | 1 + 2 files changed, 1 insertion(+) rename tests/ui/items_after_test_module/{tests/mod.rs => auxiliary/tests.rs} (100%) diff --git a/tests/ui/items_after_test_module/tests/mod.rs b/tests/ui/items_after_test_module/auxiliary/tests.rs similarity index 100% rename from tests/ui/items_after_test_module/tests/mod.rs rename to tests/ui/items_after_test_module/auxiliary/tests.rs diff --git a/tests/ui/items_after_test_module/imported_module.rs b/tests/ui/items_after_test_module/imported_module.rs index 819b6c8a9e084..22b1d3e2a9b6f 100644 --- a/tests/ui/items_after_test_module/imported_module.rs +++ b/tests/ui/items_after_test_module/imported_module.rs @@ -6,6 +6,7 @@ fn main() {} fn should_not_lint() {} +#[path = "auxiliary/tests.rs"] #[cfg(test)] mod tests; // Should not lint From 395b1f5bf333e2ff168a3cf34592a816cab6016c Mon Sep 17 00:00:00 2001 From: blyxyas Date: Fri, 28 Apr 2023 20:40:47 +0200 Subject: [PATCH 63/86] Rename items + Delete `imported_module.stderr` --- tests/ui/items_after_test_module/imported_module.rs | 6 ++++-- tests/ui/items_after_test_module/imported_module.stderr | 0 2 files changed, 4 insertions(+), 2 deletions(-) delete mode 100644 tests/ui/items_after_test_module/imported_module.stderr diff --git a/tests/ui/items_after_test_module/imported_module.rs b/tests/ui/items_after_test_module/imported_module.rs index 22b1d3e2a9b6f..6a757aef48e79 100644 --- a/tests/ui/items_after_test_module/imported_module.rs +++ b/tests/ui/items_after_test_module/imported_module.rs @@ -2,6 +2,8 @@ #![allow(unused)] #![warn(clippy::items_after_test_module)] +// Nothing here should lint, as `tests` is an imported module (that has no body). + fn main() {} fn should_not_lint() {} @@ -10,9 +12,9 @@ fn should_not_lint() {} #[cfg(test)] mod tests; // Should not lint -fn should_lint() {} +fn should_not_lint2() {} -const SHOULD_ALSO_LINT: usize = 1; +const SHOULD_ALSO_NOT_LINT: usize = 1; macro_rules! should_not_lint { () => {}; } diff --git a/tests/ui/items_after_test_module/imported_module.stderr b/tests/ui/items_after_test_module/imported_module.stderr deleted file mode 100644 index e69de29bb2d1d..0000000000000 From 2ed254e29f237c90bafdc1c064f98c61cf42f685 Mon Sep 17 00:00:00 2001 From: Lukas Lueg Date: Sat, 29 Apr 2023 14:18:31 +0200 Subject: [PATCH 64/86] Clarify docs for RESULT_LARGE_ERR --- clippy_lints/src/functions/mod.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/clippy_lints/src/functions/mod.rs b/clippy_lints/src/functions/mod.rs index 1528a7be09c3c..ee10334c67f13 100644 --- a/clippy_lints/src/functions/mod.rs +++ b/clippy_lints/src/functions/mod.rs @@ -252,6 +252,11 @@ declare_clippy_lint! { /// A `Result` is at least as large as the `Err`-variant. While we /// expect that variant to be seldomly used, the compiler needs to reserve /// and move that much memory every single time. + /// Furthermore, errors are often simply passed up the call-stack, making + /// use of the `?`-operator and its type-conversion mechanics. If the + /// `Err`-variant further up the call-stack stores the `Err`-variant in + /// question (as library code often does), it itself needs to be at least + /// as large, propagating the problem. /// /// ### Known problems /// The size determined by Clippy is platform-dependent. From bb58083ce59b44c54866a4d8305f59c7e7742593 Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Tue, 4 Apr 2023 08:16:37 +0200 Subject: [PATCH 65/86] new lint: `while_pop_unwrap` --- CHANGELOG.md | 1 + clippy_lints/src/declared_lints.rs | 1 + clippy_lints/src/lib.rs | 1 + clippy_lints/src/loops/mod.rs | 3 + clippy_lints/src/while_pop_unwrap.rs | 126 +++++++++++++++++++++++++++ clippy_utils/src/paths.rs | 4 + tests/ui/while_pop_unwrap.rs | 47 ++++++++++ tests/ui/while_pop_unwrap.stderr | 43 +++++++++ 8 files changed, 226 insertions(+) create mode 100644 clippy_lints/src/while_pop_unwrap.rs create mode 100644 tests/ui/while_pop_unwrap.rs create mode 100644 tests/ui/while_pop_unwrap.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 23f4f97ee07c5..da03f5c012b98 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5160,6 +5160,7 @@ Released 2018-09-13 [`while_immutable_condition`]: https://rust-lang.github.io/rust-clippy/master/index.html#while_immutable_condition [`while_let_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#while_let_loop [`while_let_on_iterator`]: https://rust-lang.github.io/rust-clippy/master/index.html#while_let_on_iterator +[`while_pop_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#while_pop_unwrap [`wildcard_dependencies`]: https://rust-lang.github.io/rust-clippy/master/index.html#wildcard_dependencies [`wildcard_enum_match_arm`]: https://rust-lang.github.io/rust-clippy/master/index.html#wildcard_enum_match_arm [`wildcard_imports`]: https://rust-lang.github.io/rust-clippy/master/index.html#wildcard_imports diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 4aebd0b7d011f..ddc4b139670c3 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -645,6 +645,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::useless_conversion::USELESS_CONVERSION_INFO, crate::vec::USELESS_VEC_INFO, crate::vec_init_then_push::VEC_INIT_THEN_PUSH_INFO, + crate::while_pop_unwrap::WHILE_POP_UNWRAP_INFO, crate::wildcard_imports::ENUM_GLOB_USE_INFO, crate::wildcard_imports::WILDCARD_IMPORTS_INFO, crate::write::PRINTLN_EMPTY_STRING_INFO, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 48dbecc9f6aa2..0d594612b7965 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -324,6 +324,7 @@ mod use_self; mod useless_conversion; mod vec; mod vec_init_then_push; +mod while_pop_unwrap; mod wildcard_imports; mod write; mod zero_div_zero; diff --git a/clippy_lints/src/loops/mod.rs b/clippy_lints/src/loops/mod.rs index 610a0233eee15..90012694062e6 100644 --- a/clippy_lints/src/loops/mod.rs +++ b/clippy_lints/src/loops/mod.rs @@ -25,6 +25,8 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; use utils::{make_iterator_snippet, IncrementVisitor, InitializeVisitor}; +use crate::while_pop_unwrap; + declare_clippy_lint! { /// ### What it does /// Checks for for-loops that manually copy items between @@ -643,6 +645,7 @@ impl<'tcx> LateLintPass<'tcx> for Loops { if let Some(higher::While { condition, body }) = higher::While::hir(expr) { while_immutable_condition::check(cx, condition, body); missing_spin_loop::check(cx, condition, body); + while_pop_unwrap::check(cx, condition, body); } } } diff --git a/clippy_lints/src/while_pop_unwrap.rs b/clippy_lints/src/while_pop_unwrap.rs new file mode 100644 index 0000000000000..fc77febad6b68 --- /dev/null +++ b/clippy_lints/src/while_pop_unwrap.rs @@ -0,0 +1,126 @@ +use clippy_utils::{diagnostics::span_lint_and_then, match_def_path, paths, source::snippet}; +use rustc_errors::Applicability; +use rustc_hir::*; +use rustc_lint::LateContext; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::{symbol::Ident, Span}; + +declare_clippy_lint! { + /// ### What it does + /// Looks for loops that check for emptiness of a `Vec` in the condition and pop an element + /// in the body as a separate operation. + /// + /// ### Why is this bad? + /// Such loops can be written in a more idiomatic way by using a while..let loop and directly + /// pattern matching on the return value of `Vec::pop()`. + /// + /// ### Example + /// ```rust + /// let mut numbers = vec![1, 2, 3, 4, 5]; + /// while !numbers.is_empty() { + /// let number = numbers.pop().unwrap(); + /// // use `number` + /// } + /// ``` + /// Use instead: + /// ```rust + /// let mut numbers = vec![1, 2, 3, 4, 5]; + /// while let Some(number) = numbers.pop() { + /// // use `number` + /// } + /// ``` + #[clippy::version = "1.70.0"] + pub WHILE_POP_UNWRAP, + style, + "checking for emptiness of a `Vec` in the loop condition and popping an element in the body" +} +declare_lint_pass!(WhilePopUnwrap => [WHILE_POP_UNWRAP]); + +fn report_lint<'tcx>( + cx: &LateContext<'tcx>, + pop_span: Span, + ident: Option, + loop_span: Span, + receiver_span: Span, +) { + span_lint_and_then( + cx, + WHILE_POP_UNWRAP, + pop_span, + "you seem to be trying to pop elements from a `Vec` in a loop", + |diag| { + diag.span_suggestion( + loop_span, + "try", + format!( + "while let Some({}) = {}.pop()", + ident.as_ref().map(Ident::as_str).unwrap_or("element"), + snippet(cx, receiver_span, "..") + ), + Applicability::MaybeIncorrect, + ) + .note("this while loop can be written in a more idiomatic way"); + }, + ); +} + +fn match_method_call(cx: &LateContext<'_>, expr: &Expr<'_>, method: &[&str]) -> bool { + if let ExprKind::MethodCall(..) = expr.kind + && let Some(id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) + && match_def_path(cx, id, method) + { + true + } else { + false + } +} + +fn is_vec_pop<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> bool { + match_method_call(cx, expr, &paths::VEC_POP) +} + +fn is_vec_pop_unwrap<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> bool { + if let ExprKind::MethodCall(_, inner, ..) = expr.kind + && (match_method_call(cx, expr, &paths::OPTION_UNWRAP) || match_method_call(cx, expr, &paths::OPTION_EXPECT)) + && is_vec_pop(cx, inner) + { + true + } else { + false + } +} + +fn check_local<'tcx>(cx: &LateContext<'tcx>, stmt: &Stmt<'_>, loop_span: Span, recv_span: Span) { + if let StmtKind::Local(local) = stmt.kind + && let PatKind::Binding(.., ident, _) = local.pat.kind + && let Some(init) = local.init + && let ExprKind::MethodCall(_, inner, ..) = init.kind + && is_vec_pop_unwrap(cx, init) + { + report_lint(cx, init.span.to(inner.span), Some(ident), loop_span, recv_span); + } +} + +fn check_call_arguments<'tcx>(cx: &LateContext<'tcx>, stmt: &Stmt<'_>, loop_span: Span, recv_span: Span) { + if let StmtKind::Semi(expr) | StmtKind::Expr(expr) = stmt.kind { + if let ExprKind::MethodCall(_, _, args, _) | ExprKind::Call(_, args) = expr.kind { + let offending_arg = args.iter().find_map(|arg| is_vec_pop_unwrap(cx, arg).then(|| arg.span)); + + if let Some(offending_arg) = offending_arg { + report_lint(cx, offending_arg, None, loop_span, recv_span); + } + } + } +} + +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, cond: &'tcx Expr<'_>, body: &'tcx Expr<'_>) { + if let ExprKind::Unary(UnOp::Not, cond) = cond.kind + && let ExprKind::MethodCall(_, Expr { span: recv_span, .. }, _, _) = cond.kind + && match_method_call(cx, cond, &paths::VEC_IS_EMPTY) + && let ExprKind::Block(body, _) = body.kind + && let Some(stmt) = body.stmts.first() + { + check_local(cx, stmt, cond.span, *recv_span); + check_call_arguments(cx, stmt, cond.span, *recv_span); + } +} diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index 9be2d0eae80aa..0f0792fdaa963 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -159,3 +159,7 @@ pub const WEAK_RC: [&str; 3] = ["alloc", "rc", "Weak"]; pub const PTR_NON_NULL: [&str; 4] = ["core", "ptr", "non_null", "NonNull"]; pub const INSTANT_NOW: [&str; 4] = ["std", "time", "Instant", "now"]; pub const INSTANT: [&str; 3] = ["std", "time", "Instant"]; +pub const VEC_IS_EMPTY: [&str; 4] = ["alloc", "vec", "Vec", "is_empty"]; +pub const VEC_POP: [&str; 4] = ["alloc", "vec", "Vec", "pop"]; +pub const OPTION_UNWRAP: [&str; 4] = ["core", "option", "Option", "unwrap"]; +pub const OPTION_EXPECT: [&str; 4] = ["core", "option", "Option", "expect"]; diff --git a/tests/ui/while_pop_unwrap.rs b/tests/ui/while_pop_unwrap.rs new file mode 100644 index 0000000000000..1b6de8f1f89ea --- /dev/null +++ b/tests/ui/while_pop_unwrap.rs @@ -0,0 +1,47 @@ +#![allow(unused)] +#![warn(clippy::while_pop_unwrap)] + +struct VecInStruct { + numbers: Vec, + unrelated: String, +} + +fn accept_i32(_: i32) {} + +fn main() { + let mut numbers = vec![1, 2, 3, 4, 5]; + while !numbers.is_empty() { + let number = numbers.pop().unwrap(); + } + + let mut val = VecInStruct { + numbers: vec![1, 2, 3, 4, 5], + unrelated: String::new(), + }; + while !val.numbers.is_empty() { + let number = val.numbers.pop().unwrap(); + } + + while !numbers.is_empty() { + accept_i32(numbers.pop().unwrap()); + } + + while !numbers.is_empty() { + accept_i32(numbers.pop().expect("")); + } + + // This should not warn. It "conditionally" pops elements. + while !numbers.is_empty() { + if true { + accept_i32(numbers.pop().unwrap()); + } + } + + // This should also not warn. It conditionally pops elements. + while !numbers.is_empty() { + if false { + continue; + } + accept_i32(numbers.pop().unwrap()); + } +} diff --git a/tests/ui/while_pop_unwrap.stderr b/tests/ui/while_pop_unwrap.stderr new file mode 100644 index 0000000000000..8dc77db8b5a85 --- /dev/null +++ b/tests/ui/while_pop_unwrap.stderr @@ -0,0 +1,43 @@ +error: you seem to be trying to pop elements from a `Vec` in a loop + --> $DIR/while_pop_unwrap.rs:14:22 + | +LL | while !numbers.is_empty() { + | ------------------ help: try: `while let Some(number) = numbers.pop()` +LL | let number = numbers.pop().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this while loop can be written in a more idiomatic way + = note: `-D clippy::while-pop-unwrap` implied by `-D warnings` + +error: you seem to be trying to pop elements from a `Vec` in a loop + --> $DIR/while_pop_unwrap.rs:22:22 + | +LL | while !val.numbers.is_empty() { + | ---------------------- help: try: `while let Some(number) = val.numbers.pop()` +LL | let number = val.numbers.pop().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this while loop can be written in a more idiomatic way + +error: you seem to be trying to pop elements from a `Vec` in a loop + --> $DIR/while_pop_unwrap.rs:26:20 + | +LL | while !numbers.is_empty() { + | ------------------ help: try: `while let Some(element) = numbers.pop()` +LL | accept_i32(numbers.pop().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this while loop can be written in a more idiomatic way + +error: you seem to be trying to pop elements from a `Vec` in a loop + --> $DIR/while_pop_unwrap.rs:30:20 + | +LL | while !numbers.is_empty() { + | ------------------ help: try: `while let Some(element) = numbers.pop()` +LL | accept_i32(numbers.pop().expect("")); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this while loop can be written in a more idiomatic way + +error: aborting due to 4 previous errors + From bcdcc34ba95cd27cab6da68fcac820ca6968d3e2 Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Sat, 15 Apr 2023 23:01:53 +0200 Subject: [PATCH 66/86] elide lifetimes, get rid of glob import --- clippy_lints/src/while_pop_unwrap.rs | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/clippy_lints/src/while_pop_unwrap.rs b/clippy_lints/src/while_pop_unwrap.rs index fc77febad6b68..0a3f08888a3bf 100644 --- a/clippy_lints/src/while_pop_unwrap.rs +++ b/clippy_lints/src/while_pop_unwrap.rs @@ -1,6 +1,6 @@ use clippy_utils::{diagnostics::span_lint_and_then, match_def_path, paths, source::snippet}; use rustc_errors::Applicability; -use rustc_hir::*; +use rustc_hir::{Expr, ExprKind, PatKind, Stmt, StmtKind, UnOp}; use rustc_lint::LateContext; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::{symbol::Ident, Span}; @@ -36,13 +36,7 @@ declare_clippy_lint! { } declare_lint_pass!(WhilePopUnwrap => [WHILE_POP_UNWRAP]); -fn report_lint<'tcx>( - cx: &LateContext<'tcx>, - pop_span: Span, - ident: Option, - loop_span: Span, - receiver_span: Span, -) { +fn report_lint(cx: &LateContext<'_>, pop_span: Span, ident: Option, loop_span: Span, receiver_span: Span) { span_lint_and_then( cx, WHILE_POP_UNWRAP, @@ -54,7 +48,7 @@ fn report_lint<'tcx>( "try", format!( "while let Some({}) = {}.pop()", - ident.as_ref().map(Ident::as_str).unwrap_or("element"), + ident.as_ref().map_or("element", Ident::as_str), snippet(cx, receiver_span, "..") ), Applicability::MaybeIncorrect, @@ -75,11 +69,11 @@ fn match_method_call(cx: &LateContext<'_>, expr: &Expr<'_>, method: &[&str]) -> } } -fn is_vec_pop<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> bool { +fn is_vec_pop(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { match_method_call(cx, expr, &paths::VEC_POP) } -fn is_vec_pop_unwrap<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> bool { +fn is_vec_pop_unwrap(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { if let ExprKind::MethodCall(_, inner, ..) = expr.kind && (match_method_call(cx, expr, &paths::OPTION_UNWRAP) || match_method_call(cx, expr, &paths::OPTION_EXPECT)) && is_vec_pop(cx, inner) @@ -90,7 +84,7 @@ fn is_vec_pop_unwrap<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> bool { } } -fn check_local<'tcx>(cx: &LateContext<'tcx>, stmt: &Stmt<'_>, loop_span: Span, recv_span: Span) { +fn check_local(cx: &LateContext<'_>, stmt: &Stmt<'_>, loop_span: Span, recv_span: Span) { if let StmtKind::Local(local) = stmt.kind && let PatKind::Binding(.., ident, _) = local.pat.kind && let Some(init) = local.init @@ -101,10 +95,12 @@ fn check_local<'tcx>(cx: &LateContext<'tcx>, stmt: &Stmt<'_>, loop_span: Span, r } } -fn check_call_arguments<'tcx>(cx: &LateContext<'tcx>, stmt: &Stmt<'_>, loop_span: Span, recv_span: Span) { +fn check_call_arguments(cx: &LateContext<'_>, stmt: &Stmt<'_>, loop_span: Span, recv_span: Span) { if let StmtKind::Semi(expr) | StmtKind::Expr(expr) = stmt.kind { if let ExprKind::MethodCall(_, _, args, _) | ExprKind::Call(_, args) = expr.kind { - let offending_arg = args.iter().find_map(|arg| is_vec_pop_unwrap(cx, arg).then(|| arg.span)); + let offending_arg = args + .iter() + .find_map(|arg| is_vec_pop_unwrap(cx, arg).then_some(arg.span)); if let Some(offending_arg) = offending_arg { report_lint(cx, offending_arg, None, loop_span, recv_span); From 1d08325293f0dcccd29700d6b14755f8fbd5f076 Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Tue, 18 Apr 2023 00:14:56 +0200 Subject: [PATCH 67/86] move lint to loops, emit proper suggestion, more tests --- clippy_lints/src/declared_lints.rs | 2 +- clippy_lints/src/lib.rs | 1 - clippy_lints/src/loops/mod.rs | 38 ++++++- clippy_lints/src/loops/while_pop_unwrap.rs | 109 ++++++++++++++++++ clippy_lints/src/utils/author.rs | 2 +- clippy_lints/src/while_pop_unwrap.rs | 122 --------------------- clippy_utils/src/higher.rs | 6 +- tests/ui/while_pop_unwrap.fixed | 93 ++++++++++++++++ tests/ui/while_pop_unwrap.rs | 46 ++++++++ tests/ui/while_pop_unwrap.stderr | 82 ++++++++++---- 10 files changed, 351 insertions(+), 150 deletions(-) create mode 100644 clippy_lints/src/loops/while_pop_unwrap.rs delete mode 100644 clippy_lints/src/while_pop_unwrap.rs create mode 100644 tests/ui/while_pop_unwrap.fixed diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index ddc4b139670c3..ff418092e4bfd 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -258,6 +258,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::loops::WHILE_IMMUTABLE_CONDITION_INFO, crate::loops::WHILE_LET_LOOP_INFO, crate::loops::WHILE_LET_ON_ITERATOR_INFO, + crate::loops::WHILE_POP_UNWRAP_INFO, crate::macro_use::MACRO_USE_IMPORTS_INFO, crate::main_recursion::MAIN_RECURSION_INFO, crate::manual_assert::MANUAL_ASSERT_INFO, @@ -645,7 +646,6 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::useless_conversion::USELESS_CONVERSION_INFO, crate::vec::USELESS_VEC_INFO, crate::vec_init_then_push::VEC_INIT_THEN_PUSH_INFO, - crate::while_pop_unwrap::WHILE_POP_UNWRAP_INFO, crate::wildcard_imports::ENUM_GLOB_USE_INFO, crate::wildcard_imports::WILDCARD_IMPORTS_INFO, crate::write::PRINTLN_EMPTY_STRING_INFO, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 0d594612b7965..48dbecc9f6aa2 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -324,7 +324,6 @@ mod use_self; mod useless_conversion; mod vec; mod vec_init_then_push; -mod while_pop_unwrap; mod wildcard_imports; mod write; mod zero_div_zero; diff --git a/clippy_lints/src/loops/mod.rs b/clippy_lints/src/loops/mod.rs index 90012694062e6..02197e9c187e7 100644 --- a/clippy_lints/src/loops/mod.rs +++ b/clippy_lints/src/loops/mod.rs @@ -17,6 +17,7 @@ mod utils; mod while_immutable_condition; mod while_let_loop; mod while_let_on_iterator; +mod while_pop_unwrap; use clippy_utils::higher; use rustc_hir::{Expr, ExprKind, LoopSource, Pat}; @@ -25,8 +26,6 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; use utils::{make_iterator_snippet, IncrementVisitor, InitializeVisitor}; -use crate::while_pop_unwrap; - declare_clippy_lint! { /// ### What it does /// Checks for for-loops that manually copy items between @@ -577,6 +576,36 @@ declare_clippy_lint! { "manual implementation of `Iterator::find`" } +declare_clippy_lint! { + /// ### What it does + /// Looks for loops that check for emptiness of a `Vec` in the condition and pop an element + /// in the body as a separate operation. + /// + /// ### Why is this bad? + /// Such loops can be written in a more idiomatic way by using a while..let loop and directly + /// pattern matching on the return value of `Vec::pop()`. + /// + /// ### Example + /// ```rust + /// let mut numbers = vec![1, 2, 3, 4, 5]; + /// while !numbers.is_empty() { + /// let number = numbers.pop().unwrap(); + /// // use `number` + /// } + /// ``` + /// Use instead: + /// ```rust + /// let mut numbers = vec![1, 2, 3, 4, 5]; + /// while let Some(number) = numbers.pop() { + /// // use `number` + /// } + /// ``` + #[clippy::version = "1.70.0"] + pub WHILE_POP_UNWRAP, + style, + "checking for emptiness of a `Vec` in the loop condition and popping an element in the body" +} + declare_lint_pass!(Loops => [ MANUAL_MEMCPY, MANUAL_FLATTEN, @@ -596,6 +625,7 @@ declare_lint_pass!(Loops => [ SINGLE_ELEMENT_LOOP, MISSING_SPIN_LOOP, MANUAL_FIND, + WHILE_POP_UNWRAP ]); impl<'tcx> LateLintPass<'tcx> for Loops { @@ -642,10 +672,10 @@ impl<'tcx> LateLintPass<'tcx> for Loops { while_let_on_iterator::check(cx, expr); - if let Some(higher::While { condition, body }) = higher::While::hir(expr) { + if let Some(higher::While { condition, body, span }) = higher::While::hir(expr) { while_immutable_condition::check(cx, condition, body); missing_spin_loop::check(cx, condition, body); - while_pop_unwrap::check(cx, condition, body); + while_pop_unwrap::check(cx, condition, body, span); } } } diff --git a/clippy_lints/src/loops/while_pop_unwrap.rs b/clippy_lints/src/loops/while_pop_unwrap.rs new file mode 100644 index 0000000000000..1e31184b34d63 --- /dev/null +++ b/clippy_lints/src/loops/while_pop_unwrap.rs @@ -0,0 +1,109 @@ +use clippy_utils::{ + diagnostics::{multispan_sugg_with_applicability, span_lint_and_then}, + match_def_path, paths, + source::snippet, + SpanlessEq, +}; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind, Pat, Stmt, StmtKind, UnOp}; +use rustc_lint::LateContext; +use rustc_span::Span; +use std::borrow::Cow; + +use super::WHILE_POP_UNWRAP; + +/// The kind of statement that the `pop()` call appeared in. +/// +/// Depending on whether the value was assigned to a variable or not changes what pattern +/// we use for the suggestion. +enum PopStmt<'hir> { + /// `x.pop().unwrap()` was and assigned to a variable. + /// The pattern of this local variable will be used and the local statement + /// is deleted in the suggestion. + Local(&'hir Pat<'hir>), + /// `x.pop().unwrap()` appeared in an arbitrary expression and was not assigned to a variable. + /// The suggestion will use some placeholder identifier and the `x.pop().unwrap()` expression + /// is replaced with that identifier. + Anonymous, +} + +fn report_lint(cx: &LateContext<'_>, pop_span: Span, pop_stmt_kind: PopStmt<'_>, loop_span: Span, receiver_span: Span) { + span_lint_and_then( + cx, + WHILE_POP_UNWRAP, + pop_span, + "you seem to be trying to pop elements from a `Vec` in a loop", + |diag| { + let (pat, pop_replacement) = match &pop_stmt_kind { + PopStmt::Local(pat) => (snippet(cx, pat.span, ".."), String::new()), + PopStmt::Anonymous => (Cow::Borrowed("element"), "element".into()), + }; + + let loop_replacement = format!("while let Some({}) = {}.pop()", pat, snippet(cx, receiver_span, "..")); + multispan_sugg_with_applicability( + diag, + "consider using a `while..let` loop", + Applicability::MachineApplicable, + [(loop_span, loop_replacement), (pop_span, pop_replacement)], + ); + }, + ); +} + +fn match_method_call(cx: &LateContext<'_>, expr: &Expr<'_>, method: &[&str]) -> bool { + if let ExprKind::MethodCall(..) = expr.kind + && let Some(id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) + { + match_def_path(cx, id, method) + } else { + false + } +} + +fn is_vec_pop_unwrap(cx: &LateContext<'_>, expr: &Expr<'_>, is_empty_recv: &Expr<'_>) -> bool { + if (match_method_call(cx, expr, &paths::OPTION_UNWRAP) || match_method_call(cx, expr, &paths::OPTION_EXPECT)) + && let ExprKind::MethodCall(_, unwrap_recv, ..) = expr.kind + && match_method_call(cx, unwrap_recv, &paths::VEC_POP) + && let ExprKind::MethodCall(_, pop_recv, ..) = unwrap_recv.kind + { + // make sure they're the same `Vec` + SpanlessEq::new(cx).eq_expr(pop_recv, is_empty_recv) + } else { + false + } +} + +fn check_local(cx: &LateContext<'_>, stmt: &Stmt<'_>, is_empty_recv: &Expr<'_>, loop_span: Span) { + if let StmtKind::Local(local) = stmt.kind + && let Some(init) = local.init + && is_vec_pop_unwrap(cx, init, is_empty_recv) + { + report_lint(cx, stmt.span, PopStmt::Local(&local.pat), loop_span, is_empty_recv.span); + } +} + +fn check_call_arguments(cx: &LateContext<'_>, stmt: &Stmt<'_>, is_empty_recv: &Expr<'_>, loop_span: Span) { + if let StmtKind::Semi(expr) | StmtKind::Expr(expr) = stmt.kind { + if let ExprKind::MethodCall(.., args, _) | ExprKind::Call(_, args) = expr.kind { + let offending_arg = args + .iter() + .find_map(|arg| is_vec_pop_unwrap(cx, arg, is_empty_recv).then_some(arg.span)); + + if let Some(offending_arg) = offending_arg { + report_lint(cx, offending_arg, PopStmt::Anonymous, loop_span, is_empty_recv.span); + } + } + } +} + +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, full_cond: &'tcx Expr<'_>, body: &'tcx Expr<'_>, loop_span: Span) { + if let ExprKind::Unary(UnOp::Not, cond) = full_cond.kind + && let ExprKind::MethodCall(_, is_empty_recv, _, _) = cond.kind + && match_method_call(cx, cond, &paths::VEC_IS_EMPTY) + && let ExprKind::Block(body, _) = body.kind + && let Some(stmt) = body.stmts.first() + { + check_local(cx, stmt, is_empty_recv, loop_span); + check_call_arguments(cx, stmt, is_empty_recv, loop_span); + } +} diff --git a/clippy_lints/src/utils/author.rs b/clippy_lints/src/utils/author.rs index 1f632916c5701..108077b9d1588 100644 --- a/clippy_lints/src/utils/author.rs +++ b/clippy_lints/src/utils/author.rs @@ -333,7 +333,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { #[allow(clippy::too_many_lines)] fn expr(&self, expr: &Binding<&hir::Expr<'_>>) { - if let Some(higher::While { condition, body }) = higher::While::hir(expr.value) { + if let Some(higher::While { condition, body, .. }) = higher::While::hir(expr.value) { bind!(self, condition, body); chain!( self, diff --git a/clippy_lints/src/while_pop_unwrap.rs b/clippy_lints/src/while_pop_unwrap.rs deleted file mode 100644 index 0a3f08888a3bf..0000000000000 --- a/clippy_lints/src/while_pop_unwrap.rs +++ /dev/null @@ -1,122 +0,0 @@ -use clippy_utils::{diagnostics::span_lint_and_then, match_def_path, paths, source::snippet}; -use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind, PatKind, Stmt, StmtKind, UnOp}; -use rustc_lint::LateContext; -use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::{symbol::Ident, Span}; - -declare_clippy_lint! { - /// ### What it does - /// Looks for loops that check for emptiness of a `Vec` in the condition and pop an element - /// in the body as a separate operation. - /// - /// ### Why is this bad? - /// Such loops can be written in a more idiomatic way by using a while..let loop and directly - /// pattern matching on the return value of `Vec::pop()`. - /// - /// ### Example - /// ```rust - /// let mut numbers = vec![1, 2, 3, 4, 5]; - /// while !numbers.is_empty() { - /// let number = numbers.pop().unwrap(); - /// // use `number` - /// } - /// ``` - /// Use instead: - /// ```rust - /// let mut numbers = vec![1, 2, 3, 4, 5]; - /// while let Some(number) = numbers.pop() { - /// // use `number` - /// } - /// ``` - #[clippy::version = "1.70.0"] - pub WHILE_POP_UNWRAP, - style, - "checking for emptiness of a `Vec` in the loop condition and popping an element in the body" -} -declare_lint_pass!(WhilePopUnwrap => [WHILE_POP_UNWRAP]); - -fn report_lint(cx: &LateContext<'_>, pop_span: Span, ident: Option, loop_span: Span, receiver_span: Span) { - span_lint_and_then( - cx, - WHILE_POP_UNWRAP, - pop_span, - "you seem to be trying to pop elements from a `Vec` in a loop", - |diag| { - diag.span_suggestion( - loop_span, - "try", - format!( - "while let Some({}) = {}.pop()", - ident.as_ref().map_or("element", Ident::as_str), - snippet(cx, receiver_span, "..") - ), - Applicability::MaybeIncorrect, - ) - .note("this while loop can be written in a more idiomatic way"); - }, - ); -} - -fn match_method_call(cx: &LateContext<'_>, expr: &Expr<'_>, method: &[&str]) -> bool { - if let ExprKind::MethodCall(..) = expr.kind - && let Some(id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) - && match_def_path(cx, id, method) - { - true - } else { - false - } -} - -fn is_vec_pop(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { - match_method_call(cx, expr, &paths::VEC_POP) -} - -fn is_vec_pop_unwrap(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { - if let ExprKind::MethodCall(_, inner, ..) = expr.kind - && (match_method_call(cx, expr, &paths::OPTION_UNWRAP) || match_method_call(cx, expr, &paths::OPTION_EXPECT)) - && is_vec_pop(cx, inner) - { - true - } else { - false - } -} - -fn check_local(cx: &LateContext<'_>, stmt: &Stmt<'_>, loop_span: Span, recv_span: Span) { - if let StmtKind::Local(local) = stmt.kind - && let PatKind::Binding(.., ident, _) = local.pat.kind - && let Some(init) = local.init - && let ExprKind::MethodCall(_, inner, ..) = init.kind - && is_vec_pop_unwrap(cx, init) - { - report_lint(cx, init.span.to(inner.span), Some(ident), loop_span, recv_span); - } -} - -fn check_call_arguments(cx: &LateContext<'_>, stmt: &Stmt<'_>, loop_span: Span, recv_span: Span) { - if let StmtKind::Semi(expr) | StmtKind::Expr(expr) = stmt.kind { - if let ExprKind::MethodCall(_, _, args, _) | ExprKind::Call(_, args) = expr.kind { - let offending_arg = args - .iter() - .find_map(|arg| is_vec_pop_unwrap(cx, arg).then_some(arg.span)); - - if let Some(offending_arg) = offending_arg { - report_lint(cx, offending_arg, None, loop_span, recv_span); - } - } - } -} - -pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, cond: &'tcx Expr<'_>, body: &'tcx Expr<'_>) { - if let ExprKind::Unary(UnOp::Not, cond) = cond.kind - && let ExprKind::MethodCall(_, Expr { span: recv_span, .. }, _, _) = cond.kind - && match_method_call(cx, cond, &paths::VEC_IS_EMPTY) - && let ExprKind::Block(body, _) = body.kind - && let Some(stmt) = body.stmts.first() - { - check_local(cx, stmt, cond.span, *recv_span); - check_call_arguments(cx, stmt, cond.span, *recv_span); - } -} diff --git a/clippy_utils/src/higher.rs b/clippy_utils/src/higher.rs index 50bef3709309d..a61e4c380886d 100644 --- a/clippy_utils/src/higher.rs +++ b/clippy_utils/src/higher.rs @@ -311,6 +311,8 @@ pub struct While<'hir> { pub condition: &'hir Expr<'hir>, /// `while` loop body pub body: &'hir Expr<'hir>, + /// Span of the loop header + pub span: Span, } impl<'hir> While<'hir> { @@ -336,10 +338,10 @@ impl<'hir> While<'hir> { }, _, LoopSource::While, - _, + span, ) = expr.kind { - return Some(Self { condition, body }); + return Some(Self { condition, body, span }); } None } diff --git a/tests/ui/while_pop_unwrap.fixed b/tests/ui/while_pop_unwrap.fixed new file mode 100644 index 0000000000000..a635e054e6eca --- /dev/null +++ b/tests/ui/while_pop_unwrap.fixed @@ -0,0 +1,93 @@ +// run-rustfix + +#![allow(unused)] +#![warn(clippy::while_pop_unwrap)] + +struct VecInStruct { + numbers: Vec, + unrelated: String, +} + +struct Foo { + a: i32, + b: i32, +} + +fn accept_i32(_: i32) {} +fn accept_optional_i32(_: Option) {} +fn accept_i32_tuple(_: (i32, i32)) {} + +fn main() { + let mut numbers = vec![1, 2, 3, 4, 5]; + while let Some(number) = numbers.pop() { + + } + + let mut val = VecInStruct { + numbers: vec![1, 2, 3, 4, 5], + unrelated: String::new(), + }; + while let Some(number) = val.numbers.pop() { + + } + + while let Some(element) = numbers.pop() { + accept_i32(element); + } + + while let Some(element) = numbers.pop() { + accept_i32(element); + } + + // This should not warn. It "conditionally" pops elements. + while !numbers.is_empty() { + if true { + accept_i32(numbers.pop().unwrap()); + } + } + + // This should also not warn. It conditionally pops elements. + while !numbers.is_empty() { + if false { + continue; + } + accept_i32(numbers.pop().unwrap()); + } + + // This should not warn. It pops elements, but does not unwrap it. + // Might handle the Option in some other arbitrary way. + while !numbers.is_empty() { + accept_optional_i32(numbers.pop()); + } + + let unrelated_vec: Vec = Vec::new(); + // This should not warn. It pops elements from a different vector. + while !unrelated_vec.is_empty() { + accept_i32(numbers.pop().unwrap()); + } + + macro_rules! generate_loop { + () => { + while !numbers.is_empty() { + accept_i32(numbers.pop().unwrap()); + } + }; + } + // Do not warn if the loop is in a macro. + generate_loop!(); + + // Try other kinds of patterns + let mut numbers = vec![(0, 0), (1, 1), (2, 2)]; + while let Some((a, b)) = numbers.pop() { + + } + + while let Some(element) = numbers.pop() { + accept_i32_tuple(element); + } + + let mut results = vec![Foo { a: 1, b: 2 }, Foo { a: 3, b: 4 }]; + while let Some(Foo { a, b }) = results.pop() { + + } +} diff --git a/tests/ui/while_pop_unwrap.rs b/tests/ui/while_pop_unwrap.rs index 1b6de8f1f89ea..820ff211086c1 100644 --- a/tests/ui/while_pop_unwrap.rs +++ b/tests/ui/while_pop_unwrap.rs @@ -1,3 +1,5 @@ +// run-rustfix + #![allow(unused)] #![warn(clippy::while_pop_unwrap)] @@ -6,7 +8,14 @@ struct VecInStruct { unrelated: String, } +struct Foo { + a: i32, + b: i32, +} + fn accept_i32(_: i32) {} +fn accept_optional_i32(_: Option) {} +fn accept_i32_tuple(_: (i32, i32)) {} fn main() { let mut numbers = vec![1, 2, 3, 4, 5]; @@ -44,4 +53,41 @@ fn main() { } accept_i32(numbers.pop().unwrap()); } + + // This should not warn. It pops elements, but does not unwrap it. + // Might handle the Option in some other arbitrary way. + while !numbers.is_empty() { + accept_optional_i32(numbers.pop()); + } + + let unrelated_vec: Vec = Vec::new(); + // This should not warn. It pops elements from a different vector. + while !unrelated_vec.is_empty() { + accept_i32(numbers.pop().unwrap()); + } + + macro_rules! generate_loop { + () => { + while !numbers.is_empty() { + accept_i32(numbers.pop().unwrap()); + } + }; + } + // Do not warn if the loop is in a macro. + generate_loop!(); + + // Try other kinds of patterns + let mut numbers = vec![(0, 0), (1, 1), (2, 2)]; + while !numbers.is_empty() { + let (a, b) = numbers.pop().unwrap(); + } + + while !numbers.is_empty() { + accept_i32_tuple(numbers.pop().unwrap()); + } + + let mut results = vec![Foo { a: 1, b: 2 }, Foo { a: 3, b: 4 }]; + while !results.is_empty() { + let Foo { a, b } = results.pop().unwrap(); + } } diff --git a/tests/ui/while_pop_unwrap.stderr b/tests/ui/while_pop_unwrap.stderr index 8dc77db8b5a85..f8a6cfcda0ea1 100644 --- a/tests/ui/while_pop_unwrap.stderr +++ b/tests/ui/while_pop_unwrap.stderr @@ -1,43 +1,87 @@ error: you seem to be trying to pop elements from a `Vec` in a loop - --> $DIR/while_pop_unwrap.rs:14:22 + --> $DIR/while_pop_unwrap.rs:23:9 | -LL | while !numbers.is_empty() { - | ------------------ help: try: `while let Some(number) = numbers.pop()` LL | let number = numbers.pop().unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: this while loop can be written in a more idiomatic way = note: `-D clippy::while-pop-unwrap` implied by `-D warnings` +help: consider using a `while..let` loop + | +LL ~ while let Some(number) = numbers.pop() { +LL ~ + | error: you seem to be trying to pop elements from a `Vec` in a loop - --> $DIR/while_pop_unwrap.rs:22:22 + --> $DIR/while_pop_unwrap.rs:31:9 | -LL | while !val.numbers.is_empty() { - | ---------------------- help: try: `while let Some(number) = val.numbers.pop()` LL | let number = val.numbers.pop().unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using a `while..let` loop + | +LL ~ while let Some(number) = val.numbers.pop() { +LL ~ | - = note: this while loop can be written in a more idiomatic way error: you seem to be trying to pop elements from a `Vec` in a loop - --> $DIR/while_pop_unwrap.rs:26:20 + --> $DIR/while_pop_unwrap.rs:35:20 | -LL | while !numbers.is_empty() { - | ------------------ help: try: `while let Some(element) = numbers.pop()` LL | accept_i32(numbers.pop().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^ | - = note: this while loop can be written in a more idiomatic way +help: consider using a `while..let` loop + | +LL ~ while let Some(element) = numbers.pop() { +LL ~ accept_i32(element); + | error: you seem to be trying to pop elements from a `Vec` in a loop - --> $DIR/while_pop_unwrap.rs:30:20 + --> $DIR/while_pop_unwrap.rs:39:20 | -LL | while !numbers.is_empty() { - | ------------------ help: try: `while let Some(element) = numbers.pop()` LL | accept_i32(numbers.pop().expect("")); | ^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: this while loop can be written in a more idiomatic way +help: consider using a `while..let` loop + | +LL ~ while let Some(element) = numbers.pop() { +LL ~ accept_i32(element); + | + +error: you seem to be trying to pop elements from a `Vec` in a loop + --> $DIR/while_pop_unwrap.rs:82:9 + | +LL | let (a, b) = numbers.pop().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using a `while..let` loop + | +LL ~ while let Some((a, b)) = numbers.pop() { +LL ~ + | + +error: you seem to be trying to pop elements from a `Vec` in a loop + --> $DIR/while_pop_unwrap.rs:86:26 + | +LL | accept_i32_tuple(numbers.pop().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using a `while..let` loop + | +LL ~ while let Some(element) = numbers.pop() { +LL ~ accept_i32_tuple(element); + | + +error: you seem to be trying to pop elements from a `Vec` in a loop + --> $DIR/while_pop_unwrap.rs:91:9 + | +LL | let Foo { a, b } = results.pop().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using a `while..let` loop + | +LL ~ while let Some(Foo { a, b }) = results.pop() { +LL ~ + | -error: aborting due to 4 previous errors +error: aborting due to 7 previous errors From ab9b7a5ad23bd2cb2097719ad9439277b8f5d987 Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Tue, 18 Apr 2023 00:25:39 +0200 Subject: [PATCH 68/86] remove unnecessary reference --- clippy_lints/src/loops/while_pop_unwrap.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/loops/while_pop_unwrap.rs b/clippy_lints/src/loops/while_pop_unwrap.rs index 1e31184b34d63..fc6797d72c0df 100644 --- a/clippy_lints/src/loops/while_pop_unwrap.rs +++ b/clippy_lints/src/loops/while_pop_unwrap.rs @@ -34,7 +34,7 @@ fn report_lint(cx: &LateContext<'_>, pop_span: Span, pop_stmt_kind: PopStmt<'_>, pop_span, "you seem to be trying to pop elements from a `Vec` in a loop", |diag| { - let (pat, pop_replacement) = match &pop_stmt_kind { + let (pat, pop_replacement) = match pop_stmt_kind { PopStmt::Local(pat) => (snippet(cx, pat.span, ".."), String::new()), PopStmt::Anonymous => (Cow::Borrowed("element"), "element".into()), }; @@ -78,7 +78,7 @@ fn check_local(cx: &LateContext<'_>, stmt: &Stmt<'_>, is_empty_recv: &Expr<'_>, && let Some(init) = local.init && is_vec_pop_unwrap(cx, init, is_empty_recv) { - report_lint(cx, stmt.span, PopStmt::Local(&local.pat), loop_span, is_empty_recv.span); + report_lint(cx, stmt.span, PopStmt::Local(local.pat), loop_span, is_empty_recv.span); } } From f10e39fd2be243b7f0d4f82f56420ba1cbd4a7bb Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Tue, 18 Apr 2023 00:40:03 +0200 Subject: [PATCH 69/86] make PopStmt copy+clone --- clippy_lints/src/loops/while_pop_unwrap.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/clippy_lints/src/loops/while_pop_unwrap.rs b/clippy_lints/src/loops/while_pop_unwrap.rs index fc6797d72c0df..3a583396230c9 100644 --- a/clippy_lints/src/loops/while_pop_unwrap.rs +++ b/clippy_lints/src/loops/while_pop_unwrap.rs @@ -16,6 +16,7 @@ use super::WHILE_POP_UNWRAP; /// /// Depending on whether the value was assigned to a variable or not changes what pattern /// we use for the suggestion. +#[derive(Copy, Clone)] enum PopStmt<'hir> { /// `x.pop().unwrap()` was and assigned to a variable. /// The pattern of this local variable will be used and the local statement From 8d8178f93184d09cf1e3f813257d6aeb19d08c57 Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Wed, 19 Apr 2023 22:26:50 +0200 Subject: [PATCH 70/86] rename lint to `manual_while_let_some` --- CHANGELOG.md | 2 +- clippy_lints/src/declared_lints.rs | 2 +- ...le_pop_unwrap.rs => manual_while_let_some.rs} | 4 ++-- clippy_lints/src/loops/mod.rs | 10 +++++----- ..._unwrap.fixed => manual_while_let_some.fixed} | 4 ++-- ...le_pop_unwrap.rs => manual_while_let_some.rs} | 4 ++-- ...nwrap.stderr => manual_while_let_some.stderr} | 16 ++++++++-------- 7 files changed, 21 insertions(+), 21 deletions(-) rename clippy_lints/src/loops/{while_pop_unwrap.rs => manual_while_let_some.rs} (98%) rename tests/ui/{while_pop_unwrap.fixed => manual_while_let_some.fixed} (95%) rename tests/ui/{while_pop_unwrap.rs => manual_while_let_some.rs} (95%) rename tests/ui/{while_pop_unwrap.stderr => manual_while_let_some.stderr} (85%) diff --git a/CHANGELOG.md b/CHANGELOG.md index da03f5c012b98..d1e98a93940d6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4797,6 +4797,7 @@ Released 2018-09-13 [`manual_strip`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_strip [`manual_swap`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_swap [`manual_unwrap_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_unwrap_or +[`manual_while_let_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_while_let_some [`many_single_char_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#many_single_char_names [`map_clone`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_clone [`map_collect_result_unit`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_collect_result_unit @@ -5160,7 +5161,6 @@ Released 2018-09-13 [`while_immutable_condition`]: https://rust-lang.github.io/rust-clippy/master/index.html#while_immutable_condition [`while_let_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#while_let_loop [`while_let_on_iterator`]: https://rust-lang.github.io/rust-clippy/master/index.html#while_let_on_iterator -[`while_pop_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#while_pop_unwrap [`wildcard_dependencies`]: https://rust-lang.github.io/rust-clippy/master/index.html#wildcard_dependencies [`wildcard_enum_match_arm`]: https://rust-lang.github.io/rust-clippy/master/index.html#wildcard_enum_match_arm [`wildcard_imports`]: https://rust-lang.github.io/rust-clippy/master/index.html#wildcard_imports diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index ff418092e4bfd..44e725be710e0 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -249,6 +249,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::loops::MANUAL_FIND_INFO, crate::loops::MANUAL_FLATTEN_INFO, crate::loops::MANUAL_MEMCPY_INFO, + crate::loops::MANUAL_WHILE_LET_SOME_INFO, crate::loops::MISSING_SPIN_LOOP_INFO, crate::loops::MUT_RANGE_BOUND_INFO, crate::loops::NEEDLESS_RANGE_LOOP_INFO, @@ -258,7 +259,6 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::loops::WHILE_IMMUTABLE_CONDITION_INFO, crate::loops::WHILE_LET_LOOP_INFO, crate::loops::WHILE_LET_ON_ITERATOR_INFO, - crate::loops::WHILE_POP_UNWRAP_INFO, crate::macro_use::MACRO_USE_IMPORTS_INFO, crate::main_recursion::MAIN_RECURSION_INFO, crate::manual_assert::MANUAL_ASSERT_INFO, diff --git a/clippy_lints/src/loops/while_pop_unwrap.rs b/clippy_lints/src/loops/manual_while_let_some.rs similarity index 98% rename from clippy_lints/src/loops/while_pop_unwrap.rs rename to clippy_lints/src/loops/manual_while_let_some.rs index 3a583396230c9..cb9c84be4c7a6 100644 --- a/clippy_lints/src/loops/while_pop_unwrap.rs +++ b/clippy_lints/src/loops/manual_while_let_some.rs @@ -10,7 +10,7 @@ use rustc_lint::LateContext; use rustc_span::Span; use std::borrow::Cow; -use super::WHILE_POP_UNWRAP; +use super::MANUAL_WHILE_LET_SOME; /// The kind of statement that the `pop()` call appeared in. /// @@ -31,7 +31,7 @@ enum PopStmt<'hir> { fn report_lint(cx: &LateContext<'_>, pop_span: Span, pop_stmt_kind: PopStmt<'_>, loop_span: Span, receiver_span: Span) { span_lint_and_then( cx, - WHILE_POP_UNWRAP, + MANUAL_WHILE_LET_SOME, pop_span, "you seem to be trying to pop elements from a `Vec` in a loop", |diag| { diff --git a/clippy_lints/src/loops/mod.rs b/clippy_lints/src/loops/mod.rs index 02197e9c187e7..f83ad388a742f 100644 --- a/clippy_lints/src/loops/mod.rs +++ b/clippy_lints/src/loops/mod.rs @@ -7,6 +7,7 @@ mod iter_next_loop; mod manual_find; mod manual_flatten; mod manual_memcpy; +mod manual_while_let_some; mod missing_spin_loop; mod mut_range_bound; mod needless_range_loop; @@ -17,7 +18,6 @@ mod utils; mod while_immutable_condition; mod while_let_loop; mod while_let_on_iterator; -mod while_pop_unwrap; use clippy_utils::higher; use rustc_hir::{Expr, ExprKind, LoopSource, Pat}; @@ -582,7 +582,7 @@ declare_clippy_lint! { /// in the body as a separate operation. /// /// ### Why is this bad? - /// Such loops can be written in a more idiomatic way by using a while..let loop and directly + /// Such loops can be written in a more idiomatic way by using a while-let loop and directly /// pattern matching on the return value of `Vec::pop()`. /// /// ### Example @@ -601,7 +601,7 @@ declare_clippy_lint! { /// } /// ``` #[clippy::version = "1.70.0"] - pub WHILE_POP_UNWRAP, + pub MANUAL_WHILE_LET_SOME, style, "checking for emptiness of a `Vec` in the loop condition and popping an element in the body" } @@ -625,7 +625,7 @@ declare_lint_pass!(Loops => [ SINGLE_ELEMENT_LOOP, MISSING_SPIN_LOOP, MANUAL_FIND, - WHILE_POP_UNWRAP + MANUAL_WHILE_LET_SOME ]); impl<'tcx> LateLintPass<'tcx> for Loops { @@ -675,7 +675,7 @@ impl<'tcx> LateLintPass<'tcx> for Loops { if let Some(higher::While { condition, body, span }) = higher::While::hir(expr) { while_immutable_condition::check(cx, condition, body); missing_spin_loop::check(cx, condition, body); - while_pop_unwrap::check(cx, condition, body, span); + manual_while_let_some::check(cx, condition, body, span); } } } diff --git a/tests/ui/while_pop_unwrap.fixed b/tests/ui/manual_while_let_some.fixed similarity index 95% rename from tests/ui/while_pop_unwrap.fixed rename to tests/ui/manual_while_let_some.fixed index a635e054e6eca..75738209bad13 100644 --- a/tests/ui/while_pop_unwrap.fixed +++ b/tests/ui/manual_while_let_some.fixed @@ -1,7 +1,7 @@ // run-rustfix #![allow(unused)] -#![warn(clippy::while_pop_unwrap)] +#![warn(clippy::manual_while_let_some)] struct VecInStruct { numbers: Vec, @@ -73,7 +73,7 @@ fn main() { } }; } - // Do not warn if the loop is in a macro. + // Do not warn if the loop comes from a macro. generate_loop!(); // Try other kinds of patterns diff --git a/tests/ui/while_pop_unwrap.rs b/tests/ui/manual_while_let_some.rs similarity index 95% rename from tests/ui/while_pop_unwrap.rs rename to tests/ui/manual_while_let_some.rs index 820ff211086c1..142c14715983d 100644 --- a/tests/ui/while_pop_unwrap.rs +++ b/tests/ui/manual_while_let_some.rs @@ -1,7 +1,7 @@ // run-rustfix #![allow(unused)] -#![warn(clippy::while_pop_unwrap)] +#![warn(clippy::manual_while_let_some)] struct VecInStruct { numbers: Vec, @@ -73,7 +73,7 @@ fn main() { } }; } - // Do not warn if the loop is in a macro. + // Do not warn if the loop comes from a macro. generate_loop!(); // Try other kinds of patterns diff --git a/tests/ui/while_pop_unwrap.stderr b/tests/ui/manual_while_let_some.stderr similarity index 85% rename from tests/ui/while_pop_unwrap.stderr rename to tests/ui/manual_while_let_some.stderr index f8a6cfcda0ea1..633fe05c49b84 100644 --- a/tests/ui/while_pop_unwrap.stderr +++ b/tests/ui/manual_while_let_some.stderr @@ -1,10 +1,10 @@ error: you seem to be trying to pop elements from a `Vec` in a loop - --> $DIR/while_pop_unwrap.rs:23:9 + --> $DIR/manual_while_let_some.rs:23:9 | LL | let number = numbers.pop().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `-D clippy::while-pop-unwrap` implied by `-D warnings` + = note: `-D clippy::manual-while-let-some` implied by `-D warnings` help: consider using a `while..let` loop | LL ~ while let Some(number) = numbers.pop() { @@ -12,7 +12,7 @@ LL ~ | error: you seem to be trying to pop elements from a `Vec` in a loop - --> $DIR/while_pop_unwrap.rs:31:9 + --> $DIR/manual_while_let_some.rs:31:9 | LL | let number = val.numbers.pop().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -24,7 +24,7 @@ LL ~ | error: you seem to be trying to pop elements from a `Vec` in a loop - --> $DIR/while_pop_unwrap.rs:35:20 + --> $DIR/manual_while_let_some.rs:35:20 | LL | accept_i32(numbers.pop().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^ @@ -36,7 +36,7 @@ LL ~ accept_i32(element); | error: you seem to be trying to pop elements from a `Vec` in a loop - --> $DIR/while_pop_unwrap.rs:39:20 + --> $DIR/manual_while_let_some.rs:39:20 | LL | accept_i32(numbers.pop().expect("")); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -48,7 +48,7 @@ LL ~ accept_i32(element); | error: you seem to be trying to pop elements from a `Vec` in a loop - --> $DIR/while_pop_unwrap.rs:82:9 + --> $DIR/manual_while_let_some.rs:82:9 | LL | let (a, b) = numbers.pop().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -60,7 +60,7 @@ LL ~ | error: you seem to be trying to pop elements from a `Vec` in a loop - --> $DIR/while_pop_unwrap.rs:86:26 + --> $DIR/manual_while_let_some.rs:86:26 | LL | accept_i32_tuple(numbers.pop().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^ @@ -72,7 +72,7 @@ LL ~ accept_i32_tuple(element); | error: you seem to be trying to pop elements from a `Vec` in a loop - --> $DIR/while_pop_unwrap.rs:91:9 + --> $DIR/manual_while_let_some.rs:91:9 | LL | let Foo { a, b } = results.pop().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ From 9613ea85c65c8c4f75b443e061739c82f75e317d Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Sat, 29 Apr 2023 19:10:52 +0200 Subject: [PATCH 71/86] fix run-rustfix directive --- tests/ui/manual_while_let_some.fixed | 2 +- tests/ui/manual_while_let_some.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/ui/manual_while_let_some.fixed b/tests/ui/manual_while_let_some.fixed index 75738209bad13..8b610919536c0 100644 --- a/tests/ui/manual_while_let_some.fixed +++ b/tests/ui/manual_while_let_some.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] #![warn(clippy::manual_while_let_some)] diff --git a/tests/ui/manual_while_let_some.rs b/tests/ui/manual_while_let_some.rs index 142c14715983d..85a0a084a424f 100644 --- a/tests/ui/manual_while_let_some.rs +++ b/tests/ui/manual_while_let_some.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] #![warn(clippy::manual_while_let_some)] From 032bc11fd482cc99fd3f85f053855b3e3e6ad18a Mon Sep 17 00:00:00 2001 From: Icxolu <10486322+Icxolu@users.noreply.github.com> Date: Sat, 29 Apr 2023 21:11:34 +0200 Subject: [PATCH 72/86] fix diagnostic message style Co-authored-by: Ruby Lazuli --- clippy_lints/src/default_constructed_unit_struct.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/default_constructed_unit_struct.rs b/clippy_lints/src/default_constructed_unit_struct.rs index a04f7b9d9a9fd..d518c8e7c568b 100644 --- a/clippy_lints/src/default_constructed_unit_struct.rs +++ b/clippy_lints/src/default_constructed_unit_struct.rs @@ -55,7 +55,7 @@ impl LateLintPass<'_> for DefaultConstructedUnitStruct { cx, DEFAULT_CONSTRUCTED_UNIT_STRUCT, qpath.last_segment_span(), - "Use of `default` to create a unit struct.", + "use of `default` to create a unit struct", "remove this call to `default`", String::new(), Applicability::MachineApplicable, From d4baabe9027b17714038cf392e2bfdd9d4effdb3 Mon Sep 17 00:00:00 2001 From: yukang Date: Wed, 15 Mar 2023 00:23:34 +0800 Subject: [PATCH 73/86] clean up Colon from clippy --- clippy_utils/src/sugg.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/clippy_utils/src/sugg.rs b/clippy_utils/src/sugg.rs index e81eadceec0aa..03cd8e48b9a55 100644 --- a/clippy_utils/src/sugg.rs +++ b/clippy_utils/src/sugg.rs @@ -163,7 +163,8 @@ impl<'a> Sugg<'a> { get_snippet(rhs.span), ), hir::ExprKind::Cast(lhs, ty) => Sugg::BinOp(AssocOp::As, get_snippet(lhs.span), get_snippet(ty.span)), - hir::ExprKind::Type(lhs, ty) => Sugg::BinOp(AssocOp::Colon, get_snippet(lhs.span), get_snippet(ty.span)), + //FIXME(chenyukang), remove this after type ascription is removed from AST + hir::ExprKind::Type(lhs, ty) => Sugg::BinOp(AssocOp::As, get_snippet(lhs.span), get_snippet(ty.span)), } } @@ -258,8 +259,9 @@ impl<'a> Sugg<'a> { snippet_with_context(cx, lhs.span, ctxt, default, app).0, snippet_with_context(cx, ty.span, ctxt, default, app).0, ), + //FIXME(chenyukang), remove this after type ascription is removed from AST ast::ExprKind::Type(ref lhs, ref ty) => Sugg::BinOp( - AssocOp::Colon, + AssocOp::As, snippet_with_context(cx, lhs.span, ctxt, default, app).0, snippet_with_context(cx, ty.span, ctxt, default, app).0, ), @@ -392,7 +394,6 @@ fn binop_to_string(op: AssocOp, lhs: &str, rhs: &str) -> String { AssocOp::As => format!("{lhs} as {rhs}"), AssocOp::DotDot => format!("{lhs}..{rhs}"), AssocOp::DotDotEq => format!("{lhs}..={rhs}"), - AssocOp::Colon => format!("{lhs}: {rhs}"), } } @@ -602,13 +603,13 @@ enum Associativity { #[must_use] fn associativity(op: AssocOp) -> Associativity { use rustc_ast::util::parser::AssocOp::{ - Add, As, Assign, AssignOp, BitAnd, BitOr, BitXor, Colon, Divide, DotDot, DotDotEq, Equal, Greater, + Add, As, Assign, AssignOp, BitAnd, BitOr, BitXor, Divide, DotDot, DotDotEq, Equal, Greater, GreaterEqual, LAnd, LOr, Less, LessEqual, Modulus, Multiply, NotEqual, ShiftLeft, ShiftRight, Subtract, }; match op { Assign | AssignOp(_) => Associativity::Right, - Add | BitAnd | BitOr | BitXor | LAnd | LOr | Multiply | As | Colon => Associativity::Both, + Add | BitAnd | BitOr | BitXor | LAnd | LOr | Multiply | As => Associativity::Both, Divide | Equal | Greater | GreaterEqual | Less | LessEqual | Modulus | NotEqual | ShiftLeft | ShiftRight | Subtract => Associativity::Left, DotDot | DotDotEq => Associativity::None, From 57490542419e50a22eca2b4aa79e2a64ad39c4cd Mon Sep 17 00:00:00 2001 From: blyxyas Date: Mon, 1 May 2023 12:39:20 +0200 Subject: [PATCH 74/86] globally ignore `#[no_std]` crates --- clippy_lints/src/floating_point_arithmetic.rs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/clippy_lints/src/floating_point_arithmetic.rs b/clippy_lints/src/floating_point_arithmetic.rs index da3d0da994c29..e221905580cb1 100644 --- a/clippy_lints/src/floating_point_arithmetic.rs +++ b/clippy_lints/src/floating_point_arithmetic.rs @@ -453,9 +453,6 @@ fn is_float_mul_expr<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<(&' // TODO: Fix rust-lang/rust-clippy#4735 fn check_mul_add(cx: &LateContext<'_>, expr: &Expr<'_>) { - if is_no_std_crate(cx) { - return; // The suggested methods are not available in core - } if let ExprKind::Binary( Spanned { node: op @ (BinOpKind::Add | BinOpKind::Sub), @@ -570,9 +567,6 @@ fn are_negated<'a>(cx: &LateContext<'_>, expr1: &'a Expr<'a>, expr2: &'a Expr<'a } fn check_custom_abs(cx: &LateContext<'_>, expr: &Expr<'_>) { - if is_no_std_crate(cx) { - return; // The suggested methods are not available in core - } if_chain! { if let Some(higher::If { cond, then, r#else: Some(r#else) }) = higher::If::hir(expr); let if_body_expr = peel_blocks(then); @@ -737,8 +731,8 @@ fn check_radians(cx: &LateContext<'_>, expr: &Expr<'_>) { impl<'tcx> LateLintPass<'tcx> for FloatingPointArithmetic { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - // All of these operations are currently not const. - if in_constant(cx, expr.hir_id) { + // All of these operations are currently not const and are in std. + if in_constant(cx, expr.hir_id) || is_no_std_crate(cx) { return; } From 220a9db64215df07f730cd01322a0c8b658629cd Mon Sep 17 00:00:00 2001 From: Icxolu <10486322+Icxolu@users.noreply.github.com> Date: Mon, 1 May 2023 20:12:34 +0200 Subject: [PATCH 75/86] fixed span and corrected test output --- .../src/default_constructed_unit_struct.rs | 2 +- .../ui/default_constructed_unit_struct.stderr | 24 +++++++++---------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/clippy_lints/src/default_constructed_unit_struct.rs b/clippy_lints/src/default_constructed_unit_struct.rs index d518c8e7c568b..d261cdd44a56e 100644 --- a/clippy_lints/src/default_constructed_unit_struct.rs +++ b/clippy_lints/src/default_constructed_unit_struct.rs @@ -54,7 +54,7 @@ impl LateLintPass<'_> for DefaultConstructedUnitStruct { span_lint_and_sugg( cx, DEFAULT_CONSTRUCTED_UNIT_STRUCT, - qpath.last_segment_span(), + expr.span.with_lo(qpath.qself_span().hi()), "use of `default` to create a unit struct", "remove this call to `default`", String::new(), diff --git a/tests/ui/default_constructed_unit_struct.stderr b/tests/ui/default_constructed_unit_struct.stderr index 13439414f4a7b..952d401964491 100644 --- a/tests/ui/default_constructed_unit_struct.stderr +++ b/tests/ui/default_constructed_unit_struct.stderr @@ -1,28 +1,28 @@ -error: Use of `default` to create a unit struct. - --> $DIR/default_constructed_unit_struct.rs:39:33 +error: use of `default` to create a unit struct + --> $DIR/default_constructed_unit_struct.rs:39:31 | LL | inner: PhantomData::default(), - | ^^^^^^^ help: remove this call to `default` + | ^^^^^^^^^^^ help: remove this call to `default` | = note: `-D clippy::default-constructed-unit-struct` implied by `-D warnings` -error: Use of `default` to create a unit struct. - --> $DIR/default_constructed_unit_struct.rs:62:35 +error: use of `default` to create a unit struct + --> $DIR/default_constructed_unit_struct.rs:62:33 | LL | let _ = PhantomData::::default(); - | ^^^^^^^ help: remove this call to `default` + | ^^^^^^^^^^^ help: remove this call to `default` -error: Use of `default` to create a unit struct. - --> $DIR/default_constructed_unit_struct.rs:63:44 +error: use of `default` to create a unit struct + --> $DIR/default_constructed_unit_struct.rs:63:42 | LL | let _: PhantomData = PhantomData::default(); - | ^^^^^^^ help: remove this call to `default` + | ^^^^^^^^^^^ help: remove this call to `default` -error: Use of `default` to create a unit struct. - --> $DIR/default_constructed_unit_struct.rs:64:25 +error: use of `default` to create a unit struct + --> $DIR/default_constructed_unit_struct.rs:64:23 | LL | let _ = UnitStruct::default(); - | ^^^^^^^ help: remove this call to `default` + | ^^^^^^^^^^^ help: remove this call to `default` error: aborting due to 4 previous errors From 0dd2501e0d06684de5836a00d5e039f25793fd74 Mon Sep 17 00:00:00 2001 From: blyxyas Date: Tue, 2 May 2023 20:47:18 +0200 Subject: [PATCH 76/86] Don't ignore `check_radians` --- clippy_lints/src/floating_point_arithmetic.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/clippy_lints/src/floating_point_arithmetic.rs b/clippy_lints/src/floating_point_arithmetic.rs index e221905580cb1..a1a2c398a8a02 100644 --- a/clippy_lints/src/floating_point_arithmetic.rs +++ b/clippy_lints/src/floating_point_arithmetic.rs @@ -732,14 +732,14 @@ fn check_radians(cx: &LateContext<'_>, expr: &Expr<'_>) { impl<'tcx> LateLintPass<'tcx> for FloatingPointArithmetic { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { // All of these operations are currently not const and are in std. - if in_constant(cx, expr.hir_id) || is_no_std_crate(cx) { + if in_constant(cx, expr.hir_id) { return; } if let ExprKind::MethodCall(path, receiver, args, _) = &expr.kind { let recv_ty = cx.typeck_results().expr_ty(receiver); - if recv_ty.is_floating_point() { + if recv_ty.is_floating_point() && !is_no_std_crate(cx) { match path.ident.name.as_str() { "ln" => check_ln1p(cx, expr, receiver), "log" => check_log_base(cx, expr, receiver, args), @@ -750,10 +750,12 @@ impl<'tcx> LateLintPass<'tcx> for FloatingPointArithmetic { } } } else { - check_expm1(cx, expr); - check_mul_add(cx, expr); - check_custom_abs(cx, expr); - check_log_division(cx, expr); + if !is_no_std_crate(cx) { + check_expm1(cx, expr); + check_mul_add(cx, expr); + check_custom_abs(cx, expr); + check_log_division(cx, expr); + } check_radians(cx, expr); } } From 431cce15401f9dc99ac9ac08551d803130896b83 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 20 Apr 2023 13:26:58 +1000 Subject: [PATCH 77/86] Restrict `From` for `{D,Subd}iagnosticMessage`. Currently a `{D,Subd}iagnosticMessage` can be created from any type that impls `Into`. That includes `&str`, `String`, and `Cow<'static, str>`, which are reasonable. It also includes `&String`, which is pretty weird, and results in many places making unnecessary allocations for patterns like this: ``` self.fatal(&format!(...)) ``` This creates a string with `format!`, takes a reference, passes the reference to `fatal`, which does an `into()`, which clones the reference, doing a second allocation. Two allocations for a single string, bleh. This commit changes the `From` impls so that you can only create a `{D,Subd}iagnosticMessage` from `&str`, `String`, or `Cow<'static, str>`. This requires changing all the places that currently create one from a `&String`. Most of these are of the `&format!(...)` form described above; each one removes an unnecessary static `&`, plus an allocation when executed. There are also a few places where the existing use of `&String` was more reasonable; these now just use `clone()` at the call site. As well as making the code nicer and more efficient, this is a step towards possibly using `Cow<'static, str>` in `{D,Subd}iagnosticMessage::{Str,Eager}`. That would require changing the `From<&'a str>` impls to `From<&'static str>`, which is doable, but I'm not yet sure if it's worthwhile. --- clippy_lints/src/future_not_send.rs | 2 +- clippy_lints/src/lib.rs | 2 +- clippy_lints/src/methods/str_splitn.rs | 4 ++-- clippy_lints/src/non_send_fields_in_send_ty.rs | 6 +++--- clippy_utils/src/attrs.rs | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/clippy_lints/src/future_not_send.rs b/clippy_lints/src/future_not_send.rs index ff838c2d56e43..d1314795f5803 100644 --- a/clippy_lints/src/future_not_send.rs +++ b/clippy_lints/src/future_not_send.rs @@ -96,7 +96,7 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend { if let PredicateKind::Clause(Clause::Trait(trait_pred)) = obligation.predicate.kind().skip_binder() { - db.note(&format!( + db.note(format!( "`{}` doesn't implement `{}`", trait_pred.self_ty(), trait_pred.trait_ref.print_only_trait_path(), diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 573ffe349ec23..9e65f9ecd1664 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -353,7 +353,7 @@ pub fn register_pre_expansion_lints(store: &mut rustc_lint::LintStore, sess: &Se pub fn read_conf(sess: &Session, path: &io::Result<(Option, Vec)>) -> Conf { if let Ok((_, warnings)) = path { for warning in warnings { - sess.warn(warning); + sess.warn(warning.clone()); } } let file_name = match path { diff --git a/clippy_lints/src/methods/str_splitn.rs b/clippy_lints/src/methods/str_splitn.rs index d00708e828eae..91f7ce1dbe58e 100644 --- a/clippy_lints/src/methods/str_splitn.rs +++ b/clippy_lints/src/methods/str_splitn.rs @@ -175,13 +175,13 @@ fn check_manual_split_once_indirect( let remove_msg = format!("remove the `{iter_ident}` usages"); diag.span_suggestion( first.span, - &remove_msg, + remove_msg.clone(), "", app, ); diag.span_suggestion( second.span, - &remove_msg, + remove_msg, "", app, ); diff --git a/clippy_lints/src/non_send_fields_in_send_ty.rs b/clippy_lints/src/non_send_fields_in_send_ty.rs index 839c3a3815c29..7eaa7db78a470 100644 --- a/clippy_lints/src/non_send_fields_in_send_ty.rs +++ b/clippy_lints/src/non_send_fields_in_send_ty.rs @@ -131,13 +131,13 @@ impl<'tcx> LateLintPass<'tcx> for NonSendFieldInSendTy { for field in non_send_fields { diag.span_note( field.def.span, - &format!("it is not safe to send field `{}` to another thread", field.def.ident.name), + format!("it is not safe to send field `{}` to another thread", field.def.ident.name), ); match field.generic_params.len() { 0 => diag.help("use a thread-safe type that implements `Send`"), - 1 if is_ty_param(field.ty) => diag.help(&format!("add `{}: Send` bound in `Send` impl", field.ty)), - _ => diag.help(&format!( + 1 if is_ty_param(field.ty) => diag.help(format!("add `{}: Send` bound in `Send` impl", field.ty)), + _ => diag.help(format!( "add bounds on type parameter{} `{}` that satisfy `{}: Send`", if field.generic_params.len() > 1 { "s" } else { "" }, field.generic_params_string(), diff --git a/clippy_utils/src/attrs.rs b/clippy_utils/src/attrs.rs index b4ad42a50279f..49cb9718ef66e 100644 --- a/clippy_utils/src/attrs.rs +++ b/clippy_utils/src/attrs.rs @@ -133,7 +133,7 @@ pub fn get_unique_attr<'a>( let mut unique_attr: Option<&ast::Attribute> = None; for attr in get_attr(sess, attrs, name) { if let Some(duplicate) = unique_attr { - sess.struct_span_err(attr.span, &format!("`{name}` is defined multiple times")) + sess.struct_span_err(attr.span, format!("`{name}` is defined multiple times")) .span_note(duplicate.span, "first definition found here") .emit(); } else { From 7e24ff33e4a940df392e5329e18e6bc05f882088 Mon Sep 17 00:00:00 2001 From: Samuel Moelius <35515885+smoelius@users.noreply.github.com> Date: Tue, 2 May 2023 19:02:06 -0400 Subject: [PATCH 78/86] Update macros.rs --- clippy_utils/src/macros.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_utils/src/macros.rs b/clippy_utils/src/macros.rs index 62d388a5ece8d..e4a4936ff42fc 100644 --- a/clippy_utils/src/macros.rs +++ b/clippy_utils/src/macros.rs @@ -362,7 +362,7 @@ thread_local! { /// able to access the many features of a [`LateContext`]. /// /// A thread local is used because [`FormatArgs`] is `!Send` and `!Sync`, we are making an - /// assumption that the early pass the populates the map and the later late passes will all be + /// assumption that the early pass that populates the map and the later late passes will all be /// running on the same thread. static AST_FORMAT_ARGS: RefCell> = { static CALLED: AtomicBool = AtomicBool::new(false); From 4e049036313759df55c4c68ad87e1cd7ad5cf214 Mon Sep 17 00:00:00 2001 From: Icxolu <10486322+Icxolu@users.noreply.github.com> Date: Wed, 3 May 2023 19:25:25 +0200 Subject: [PATCH 79/86] rename to plural form --- CHANGELOG.md | 2 +- clippy_lints/src/declared_lints.rs | 2 +- ...t_struct.rs => default_constructed_unit_structs.rs} | 8 ++++---- clippy_lints/src/lib.rs | 4 ++-- ...t_struct.rs => default_constructed_unit_structs.rs} | 2 +- ....stderr => default_constructed_unit_structs.stderr} | 10 +++++----- 6 files changed, 14 insertions(+), 14 deletions(-) rename clippy_lints/src/{default_constructed_unit_struct.rs => default_constructed_unit_structs.rs} (90%) rename tests/ui/{default_constructed_unit_struct.rs => default_constructed_unit_structs.rs} (96%) rename tests/ui/{default_constructed_unit_struct.stderr => default_constructed_unit_structs.stderr} (73%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 735ac59758a64..31ad00536c5b5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4582,7 +4582,7 @@ Released 2018-09-13 [`debug_assert_with_mut_call`]: https://rust-lang.github.io/rust-clippy/master/index.html#debug_assert_with_mut_call [`decimal_literal_representation`]: https://rust-lang.github.io/rust-clippy/master/index.html#decimal_literal_representation [`declare_interior_mutable_const`]: https://rust-lang.github.io/rust-clippy/master/index.html#declare_interior_mutable_const -[`default_constructed_unit_struct`]: https://rust-lang.github.io/rust-clippy/master/index.html#default_constructed_unit_struct +[`default_constructed_unit_structs`]: https://rust-lang.github.io/rust-clippy/master/index.html#default_constructed_unit_structs [`default_instead_of_iter_empty`]: https://rust-lang.github.io/rust-clippy/master/index.html#default_instead_of_iter_empty [`default_numeric_fallback`]: https://rust-lang.github.io/rust-clippy/master/index.html#default_numeric_fallback [`default_trait_access`]: https://rust-lang.github.io/rust-clippy/master/index.html#default_trait_access diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index bf30f5b52f7d2..d3f5cb6e5f484 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -105,7 +105,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::dbg_macro::DBG_MACRO_INFO, crate::default::DEFAULT_TRAIT_ACCESS_INFO, crate::default::FIELD_REASSIGN_WITH_DEFAULT_INFO, - crate::default_constructed_unit_struct::DEFAULT_CONSTRUCTED_UNIT_STRUCT_INFO, + crate::default_constructed_unit_structs::DEFAULT_CONSTRUCTED_UNIT_STRUCTS_INFO, crate::default_instead_of_iter_empty::DEFAULT_INSTEAD_OF_ITER_EMPTY_INFO, crate::default_numeric_fallback::DEFAULT_NUMERIC_FALLBACK_INFO, crate::default_union_representation::DEFAULT_UNION_REPRESENTATION_INFO, diff --git a/clippy_lints/src/default_constructed_unit_struct.rs b/clippy_lints/src/default_constructed_unit_structs.rs similarity index 90% rename from clippy_lints/src/default_constructed_unit_struct.rs rename to clippy_lints/src/default_constructed_unit_structs.rs index d261cdd44a56e..a79923e9715e4 100644 --- a/clippy_lints/src/default_constructed_unit_struct.rs +++ b/clippy_lints/src/default_constructed_unit_structs.rs @@ -31,13 +31,13 @@ declare_clippy_lint! { /// } /// ``` #[clippy::version = "1.71.0"] - pub DEFAULT_CONSTRUCTED_UNIT_STRUCT, + pub DEFAULT_CONSTRUCTED_UNIT_STRUCTS, complexity, "unit structs can be contructed without calling `default`" } -declare_lint_pass!(DefaultConstructedUnitStruct => [DEFAULT_CONSTRUCTED_UNIT_STRUCT]); +declare_lint_pass!(DefaultConstructedUnitStructs => [DEFAULT_CONSTRUCTED_UNIT_STRUCTS]); -impl LateLintPass<'_> for DefaultConstructedUnitStruct { +impl LateLintPass<'_> for DefaultConstructedUnitStructs { fn check_expr<'tcx>(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) { if_chain!( // make sure we have a call to `Default::default` @@ -53,7 +53,7 @@ impl LateLintPass<'_> for DefaultConstructedUnitStruct { then { span_lint_and_sugg( cx, - DEFAULT_CONSTRUCTED_UNIT_STRUCT, + DEFAULT_CONSTRUCTED_UNIT_STRUCTS, expr.span.with_lo(qpath.qself_span().hi()), "use of `default` to create a unit struct", "remove this call to `default`", diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 9af0b17e27bce..657a3d1f43107 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -94,7 +94,7 @@ mod crate_in_macro_def; mod create_dir; mod dbg_macro; mod default; -mod default_constructed_unit_struct; +mod default_constructed_unit_structs; mod default_instead_of_iter_empty; mod default_numeric_fallback; mod default_union_representation; @@ -971,7 +971,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|_| Box::new(manual_slice_size_calculation::ManualSliceSizeCalculation)); store.register_early_pass(|| Box::new(suspicious_doc_comments::SuspiciousDocComments)); store.register_late_pass(|_| Box::new(items_after_test_module::ItemsAfterTestModule)); - store.register_late_pass(|_| Box::new(default_constructed_unit_struct::DefaultConstructedUnitStruct)); + store.register_late_pass(|_| Box::new(default_constructed_unit_structs::DefaultConstructedUnitStructs)); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/tests/ui/default_constructed_unit_struct.rs b/tests/ui/default_constructed_unit_structs.rs similarity index 96% rename from tests/ui/default_constructed_unit_struct.rs rename to tests/ui/default_constructed_unit_structs.rs index b64da9b863ac4..505be09a50e47 100644 --- a/tests/ui/default_constructed_unit_struct.rs +++ b/tests/ui/default_constructed_unit_structs.rs @@ -1,5 +1,5 @@ #![allow(unused)] -#![warn(clippy::default_constructed_unit_struct)] +#![warn(clippy::default_constructed_unit_structs)] use std::marker::PhantomData; #[derive(Default)] diff --git a/tests/ui/default_constructed_unit_struct.stderr b/tests/ui/default_constructed_unit_structs.stderr similarity index 73% rename from tests/ui/default_constructed_unit_struct.stderr rename to tests/ui/default_constructed_unit_structs.stderr index 952d401964491..23ffa2782886a 100644 --- a/tests/ui/default_constructed_unit_struct.stderr +++ b/tests/ui/default_constructed_unit_structs.stderr @@ -1,25 +1,25 @@ error: use of `default` to create a unit struct - --> $DIR/default_constructed_unit_struct.rs:39:31 + --> $DIR/default_constructed_unit_structs.rs:39:31 | LL | inner: PhantomData::default(), | ^^^^^^^^^^^ help: remove this call to `default` | - = note: `-D clippy::default-constructed-unit-struct` implied by `-D warnings` + = note: `-D clippy::default-constructed-unit-structs` implied by `-D warnings` error: use of `default` to create a unit struct - --> $DIR/default_constructed_unit_struct.rs:62:33 + --> $DIR/default_constructed_unit_structs.rs:62:33 | LL | let _ = PhantomData::::default(); | ^^^^^^^^^^^ help: remove this call to `default` error: use of `default` to create a unit struct - --> $DIR/default_constructed_unit_struct.rs:63:42 + --> $DIR/default_constructed_unit_structs.rs:63:42 | LL | let _: PhantomData = PhantomData::default(); | ^^^^^^^^^^^ help: remove this call to `default` error: use of `default` to create a unit struct - --> $DIR/default_constructed_unit_struct.rs:64:23 + --> $DIR/default_constructed_unit_structs.rs:64:23 | LL | let _ = UnitStruct::default(); | ^^^^^^^^^^^ help: remove this call to `default` From 8701009860273828cb6853e1dba79a82e1271619 Mon Sep 17 00:00:00 2001 From: Icxolu <10486322+Icxolu@users.noreply.github.com> Date: Wed, 3 May 2023 20:06:29 +0200 Subject: [PATCH 80/86] add more test cases --- .../src/default_constructed_unit_structs.rs | 8 ++-- tests/ui/default_constructed_unit_structs.rs | 45 +++++++++++++++++++ .../default_constructed_unit_structs.stderr | 20 ++++++--- 3 files changed, 62 insertions(+), 11 deletions(-) diff --git a/clippy_lints/src/default_constructed_unit_structs.rs b/clippy_lints/src/default_constructed_unit_structs.rs index a79923e9715e4..dab76a2c41ffb 100644 --- a/clippy_lints/src/default_constructed_unit_structs.rs +++ b/clippy_lints/src/default_constructed_unit_structs.rs @@ -42,14 +42,14 @@ impl LateLintPass<'_> for DefaultConstructedUnitStructs { if_chain!( // make sure we have a call to `Default::default` if let hir::ExprKind::Call(fn_expr, &[]) = expr.kind; - if let ExprKind::Path(ref qpath) = fn_expr.kind; + if let ExprKind::Path(ref qpath@ hir::QPath::TypeRelative(_,_)) = fn_expr.kind; if let Res::Def(_, def_id) = cx.qpath_res(qpath, fn_expr.hir_id); if match_def_path(cx, def_id, &paths::DEFAULT_TRAIT_METHOD); // make sure we have a struct with no fields (unit struct) if let ty::Adt(def, ..) = cx.typeck_results().expr_ty(expr).kind(); - if def.is_struct() && def.is_payloadfree() - && !def.non_enum_variant().is_field_list_non_exhaustive() - && !is_from_proc_macro(cx, expr); + if def.is_struct(); + if let var @ ty::VariantDef { ctor: Some((hir::def::CtorKind::Const, _)), .. } = def.non_enum_variant(); + if !var.is_field_list_non_exhaustive() && !is_from_proc_macro(cx, expr); then { span_lint_and_sugg( cx, diff --git a/tests/ui/default_constructed_unit_structs.rs b/tests/ui/default_constructed_unit_structs.rs index 505be09a50e47..276fc40aa189b 100644 --- a/tests/ui/default_constructed_unit_structs.rs +++ b/tests/ui/default_constructed_unit_structs.rs @@ -5,9 +5,23 @@ use std::marker::PhantomData; #[derive(Default)] struct UnitStruct; +impl UnitStruct { + fn new() -> Self { + //should lint + Self::default() + } +} + #[derive(Default)] struct TupleStruct(usize); +impl TupleStruct { + fn new() -> Self { + // should not lint + Self(Default::default()) + } +} + // no lint for derived impl #[derive(Default)] struct NormalStruct { @@ -39,6 +53,13 @@ impl NormalStruct { inner: PhantomData::default(), } } + + fn new2() -> Self { + // should not lint + Self { + inner: Default::default(), + } + } } #[derive(Default)] @@ -51,8 +72,29 @@ impl GenericStruct { // should not lint Self { t: T::default() } } + + fn new2() -> Self { + // should not lint + Self { t: Default::default() } + } +} + +struct FakeDefault; +impl FakeDefault { + fn default() -> Self { + Self + } } +impl Default for FakeDefault { + fn default() -> Self { + Self + } +} + +#[derive(Default)] +struct EmptyStruct {} + #[derive(Default)] #[non_exhaustive] struct NonExhaustiveStruct; @@ -69,4 +111,7 @@ fn main() { let _ = NonExhaustiveStruct::default(); let _ = SomeEnum::default(); let _ = NonDefaultStruct::default(); + let _ = EmptyStruct::default(); + let _ = FakeDefault::default(); + let _ = ::default(); } diff --git a/tests/ui/default_constructed_unit_structs.stderr b/tests/ui/default_constructed_unit_structs.stderr index 23ffa2782886a..fa39ef4cda160 100644 --- a/tests/ui/default_constructed_unit_structs.stderr +++ b/tests/ui/default_constructed_unit_structs.stderr @@ -1,28 +1,34 @@ error: use of `default` to create a unit struct - --> $DIR/default_constructed_unit_structs.rs:39:31 + --> $DIR/default_constructed_unit_structs.rs:11:13 | -LL | inner: PhantomData::default(), - | ^^^^^^^^^^^ help: remove this call to `default` +LL | Self::default() + | ^^^^^^^^^^^ help: remove this call to `default` | = note: `-D clippy::default-constructed-unit-structs` implied by `-D warnings` error: use of `default` to create a unit struct - --> $DIR/default_constructed_unit_structs.rs:62:33 + --> $DIR/default_constructed_unit_structs.rs:53:31 + | +LL | inner: PhantomData::default(), + | ^^^^^^^^^^^ help: remove this call to `default` + +error: use of `default` to create a unit struct + --> $DIR/default_constructed_unit_structs.rs:104:33 | LL | let _ = PhantomData::::default(); | ^^^^^^^^^^^ help: remove this call to `default` error: use of `default` to create a unit struct - --> $DIR/default_constructed_unit_structs.rs:63:42 + --> $DIR/default_constructed_unit_structs.rs:105:42 | LL | let _: PhantomData = PhantomData::default(); | ^^^^^^^^^^^ help: remove this call to `default` error: use of `default` to create a unit struct - --> $DIR/default_constructed_unit_structs.rs:64:23 + --> $DIR/default_constructed_unit_structs.rs:106:23 | LL | let _ = UnitStruct::default(); | ^^^^^^^^^^^ help: remove this call to `default` -error: aborting due to 4 previous errors +error: aborting due to 5 previous errors From 4ed7fd1ecc94eb82d99fe18192c156f367029731 Mon Sep 17 00:00:00 2001 From: Icxolu <10486322+Icxolu@users.noreply.github.com> Date: Wed, 3 May 2023 20:07:02 +0200 Subject: [PATCH 81/86] fix failing tests --- tests/ui/box_default.fixed | 1 + tests/ui/box_default.rs | 1 + tests/ui/box_default.stderr | 32 ++++++++++++++++---------------- tests/ui/from_over_into.fixed | 2 +- tests/ui/from_over_into.rs | 2 +- tests/ui/from_over_into.stderr | 2 +- tests/ui/use_self_trait.fixed | 4 ++-- tests/ui/use_self_trait.rs | 4 ++-- tests/ui/use_self_trait.stderr | 2 +- 9 files changed, 26 insertions(+), 24 deletions(-) diff --git a/tests/ui/box_default.fixed b/tests/ui/box_default.fixed index 6afce2087697f..e6331290420b4 100644 --- a/tests/ui/box_default.fixed +++ b/tests/ui/box_default.fixed @@ -1,5 +1,6 @@ //@run-rustfix #![warn(clippy::box_default)] +#![allow(clippy::default_constructed_unit_structs)] #[derive(Default)] struct ImplementsDefault; diff --git a/tests/ui/box_default.rs b/tests/ui/box_default.rs index 09365618e6336..34a05a29c5aa3 100644 --- a/tests/ui/box_default.rs +++ b/tests/ui/box_default.rs @@ -1,5 +1,6 @@ //@run-rustfix #![warn(clippy::box_default)] +#![allow(clippy::default_constructed_unit_structs)] #[derive(Default)] struct ImplementsDefault; diff --git a/tests/ui/box_default.stderr b/tests/ui/box_default.stderr index 78e17b9f0359c..c983486360144 100644 --- a/tests/ui/box_default.stderr +++ b/tests/ui/box_default.stderr @@ -1,5 +1,5 @@ error: `Box::new(_)` of default value - --> $DIR/box_default.rs:22:32 + --> $DIR/box_default.rs:23:32 | LL | let _string: Box = Box::new(Default::default()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::default()` @@ -7,91 +7,91 @@ LL | let _string: Box = Box::new(Default::default()); = note: `-D clippy::box-default` implied by `-D warnings` error: `Box::new(_)` of default value - --> $DIR/box_default.rs:23:17 + --> $DIR/box_default.rs:24:17 | LL | let _byte = Box::new(u8::default()); | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::::default()` error: `Box::new(_)` of default value - --> $DIR/box_default.rs:24:16 + --> $DIR/box_default.rs:25:16 | LL | let _vec = Box::new(Vec::::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::>::default()` error: `Box::new(_)` of default value - --> $DIR/box_default.rs:25:17 + --> $DIR/box_default.rs:26:17 | LL | let _impl = Box::new(ImplementsDefault::default()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::::default()` error: `Box::new(_)` of default value - --> $DIR/box_default.rs:26:18 + --> $DIR/box_default.rs:27:18 | LL | let _impl2 = Box::new(::default()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::::default()` error: `Box::new(_)` of default value - --> $DIR/box_default.rs:27:42 + --> $DIR/box_default.rs:28:42 | LL | let _impl3: Box = Box::new(Default::default()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::default()` error: `Box::new(_)` of default value - --> $DIR/box_default.rs:29:28 + --> $DIR/box_default.rs:30:28 | LL | let _in_macro = outer!(Box::new(String::new())); | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::::default()` error: `Box::new(_)` of default value - --> $DIR/box_default.rs:30:34 + --> $DIR/box_default.rs:31:34 | LL | let _string_default = outer!(Box::new(String::from(""))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::::default()` error: `Box::new(_)` of default value - --> $DIR/box_default.rs:31:46 + --> $DIR/box_default.rs:32:46 | LL | let _vec2: Box> = Box::new(vec![]); | ^^^^^^^^^^^^^^^^ help: try: `Box::default()` error: `Box::new(_)` of default value - --> $DIR/box_default.rs:32:33 + --> $DIR/box_default.rs:33:33 | LL | let _vec3: Box> = Box::new(Vec::from([])); | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::default()` error: `Box::new(_)` of default value - --> $DIR/box_default.rs:33:25 + --> $DIR/box_default.rs:34:25 | LL | let _vec4: Box<_> = Box::new(Vec::from([false; 0])); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::>::default()` error: `Box::new(_)` of default value - --> $DIR/box_default.rs:35:16 + --> $DIR/box_default.rs:36:16 | LL | call_ty_fn(Box::new(u8::default())); | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::default()` error: `Box::new(_)` of default value - --> $DIR/box_default.rs:40:5 + --> $DIR/box_default.rs:41:5 | LL | Box::new(bool::default()) | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::::default()` error: `Box::new(_)` of default value - --> $DIR/box_default.rs:57:28 + --> $DIR/box_default.rs:58:28 | LL | let _: Box = Box::new(ImplementsDefault::default()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::::default()` error: `Box::new(_)` of default value - --> $DIR/box_default.rs:66:17 + --> $DIR/box_default.rs:67:17 | LL | let _ = Box::new(WeirdPathed::default()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::::default()` error: `Box::new(_)` of default value - --> $DIR/box_default.rs:78:18 + --> $DIR/box_default.rs:79:18 | LL | Some(Box::new(Foo::default())) | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::::default()` diff --git a/tests/ui/from_over_into.fixed b/tests/ui/from_over_into.fixed index fc6d937060dc0..d18f93875658c 100644 --- a/tests/ui/from_over_into.fixed +++ b/tests/ui/from_over_into.fixed @@ -32,7 +32,7 @@ struct SelfKeywords; impl From for SelfKeywords { fn from(val: X) -> Self { - let _ = X::default(); + let _ = X; let _ = X::FOO; let _: X = val; diff --git a/tests/ui/from_over_into.rs b/tests/ui/from_over_into.rs index fe1ebee35f166..de8ff0b06bdca 100644 --- a/tests/ui/from_over_into.rs +++ b/tests/ui/from_over_into.rs @@ -32,7 +32,7 @@ struct SelfKeywords; impl Into for X { fn into(self) -> SelfKeywords { - let _ = Self::default(); + let _ = Self; let _ = Self::FOO; let _: Self = self; diff --git a/tests/ui/from_over_into.stderr b/tests/ui/from_over_into.stderr index 990b905c1b158..6039f86fe6703 100644 --- a/tests/ui/from_over_into.stderr +++ b/tests/ui/from_over_into.stderr @@ -35,7 +35,7 @@ help: replace the `Into` implementation with `From` | LL ~ impl From for SelfKeywords { LL ~ fn from(val: X) -> Self { -LL ~ let _ = X::default(); +LL ~ let _ = X; LL ~ let _ = X::FOO; LL ~ let _: X = val; | diff --git a/tests/ui/use_self_trait.fixed b/tests/ui/use_self_trait.fixed index 4623aeeb0eb23..20138a29fd1f1 100644 --- a/tests/ui/use_self_trait.fixed +++ b/tests/ui/use_self_trait.fixed @@ -33,7 +33,7 @@ impl SelfTrait for Bad { fn nested(_p1: Box, _p2: (&u8, &Self)) {} fn vals(_: Self) -> Self { - Self::default() + Self } } @@ -70,7 +70,7 @@ impl SelfTrait for Good { fn nested(_p1: Box, _p2: (&u8, &Self)) {} fn vals(_: Self) -> Self { - Self::default() + Self } } diff --git a/tests/ui/use_self_trait.rs b/tests/ui/use_self_trait.rs index d7d76dd96233c..bf697b01a42f7 100644 --- a/tests/ui/use_self_trait.rs +++ b/tests/ui/use_self_trait.rs @@ -33,7 +33,7 @@ impl SelfTrait for Bad { fn nested(_p1: Box, _p2: (&u8, &Bad)) {} fn vals(_: Bad) -> Bad { - Bad::default() + Bad } } @@ -70,7 +70,7 @@ impl SelfTrait for Good { fn nested(_p1: Box, _p2: (&u8, &Self)) {} fn vals(_: Self) -> Self { - Self::default() + Self } } diff --git a/tests/ui/use_self_trait.stderr b/tests/ui/use_self_trait.stderr index 090729b9c3d54..6257f802dd80a 100644 --- a/tests/ui/use_self_trait.stderr +++ b/tests/ui/use_self_trait.stderr @@ -63,7 +63,7 @@ LL | fn vals(_: Bad) -> Bad { error: unnecessary structure name repetition --> $DIR/use_self_trait.rs:36:9 | -LL | Bad::default() +LL | Bad | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition From 160371550fbb7783200f6184109c02babf06efb3 Mon Sep 17 00:00:00 2001 From: Icxolu <10486322+Icxolu@users.noreply.github.com> Date: Wed, 3 May 2023 21:05:50 +0200 Subject: [PATCH 82/86] add `rustfix` annotation --- .../ui/default_constructed_unit_structs.fixed | 119 ++++++++++++++++++ tests/ui/default_constructed_unit_structs.rs | 2 + .../default_constructed_unit_structs.stderr | 10 +- 3 files changed, 126 insertions(+), 5 deletions(-) create mode 100644 tests/ui/default_constructed_unit_structs.fixed diff --git a/tests/ui/default_constructed_unit_structs.fixed b/tests/ui/default_constructed_unit_structs.fixed new file mode 100644 index 0000000000000..4c2d1ea48e119 --- /dev/null +++ b/tests/ui/default_constructed_unit_structs.fixed @@ -0,0 +1,119 @@ +//@run-rustfix + +#![allow(unused)] +#![warn(clippy::default_constructed_unit_structs)] +use std::marker::PhantomData; + +#[derive(Default)] +struct UnitStruct; + +impl UnitStruct { + fn new() -> Self { + //should lint + Self + } +} + +#[derive(Default)] +struct TupleStruct(usize); + +impl TupleStruct { + fn new() -> Self { + // should not lint + Self(Default::default()) + } +} + +// no lint for derived impl +#[derive(Default)] +struct NormalStruct { + inner: PhantomData, +} + +struct NonDefaultStruct; + +impl NonDefaultStruct { + fn default() -> Self { + Self + } +} + +#[derive(Default)] +enum SomeEnum { + #[default] + Unit, + Tuple(UnitStruct), + Struct { + inner: usize, + }, +} + +impl NormalStruct { + fn new() -> Self { + // should lint + Self { + inner: PhantomData, + } + } + + fn new2() -> Self { + // should not lint + Self { + inner: Default::default(), + } + } +} + +#[derive(Default)] +struct GenericStruct { + t: T, +} + +impl GenericStruct { + fn new() -> Self { + // should not lint + Self { t: T::default() } + } + + fn new2() -> Self { + // should not lint + Self { t: Default::default() } + } +} + +struct FakeDefault; +impl FakeDefault { + fn default() -> Self { + Self + } +} + +impl Default for FakeDefault { + fn default() -> Self { + Self + } +} + +#[derive(Default)] +struct EmptyStruct {} + +#[derive(Default)] +#[non_exhaustive] +struct NonExhaustiveStruct; + +fn main() { + // should lint + let _ = PhantomData::; + let _: PhantomData = PhantomData; + let _ = UnitStruct; + + // should not lint + let _ = TupleStruct::default(); + let _ = NormalStruct::default(); + let _ = NonExhaustiveStruct::default(); + let _ = SomeEnum::default(); + let _ = NonDefaultStruct::default(); + let _ = EmptyStruct::default(); + let _ = FakeDefault::default(); + let _ = ::default(); +} diff --git a/tests/ui/default_constructed_unit_structs.rs b/tests/ui/default_constructed_unit_structs.rs index 276fc40aa189b..850793dd5de81 100644 --- a/tests/ui/default_constructed_unit_structs.rs +++ b/tests/ui/default_constructed_unit_structs.rs @@ -1,3 +1,5 @@ +//@run-rustfix + #![allow(unused)] #![warn(clippy::default_constructed_unit_structs)] use std::marker::PhantomData; diff --git a/tests/ui/default_constructed_unit_structs.stderr b/tests/ui/default_constructed_unit_structs.stderr index fa39ef4cda160..4058943d08727 100644 --- a/tests/ui/default_constructed_unit_structs.stderr +++ b/tests/ui/default_constructed_unit_structs.stderr @@ -1,5 +1,5 @@ error: use of `default` to create a unit struct - --> $DIR/default_constructed_unit_structs.rs:11:13 + --> $DIR/default_constructed_unit_structs.rs:13:13 | LL | Self::default() | ^^^^^^^^^^^ help: remove this call to `default` @@ -7,25 +7,25 @@ LL | Self::default() = note: `-D clippy::default-constructed-unit-structs` implied by `-D warnings` error: use of `default` to create a unit struct - --> $DIR/default_constructed_unit_structs.rs:53:31 + --> $DIR/default_constructed_unit_structs.rs:55:31 | LL | inner: PhantomData::default(), | ^^^^^^^^^^^ help: remove this call to `default` error: use of `default` to create a unit struct - --> $DIR/default_constructed_unit_structs.rs:104:33 + --> $DIR/default_constructed_unit_structs.rs:106:33 | LL | let _ = PhantomData::::default(); | ^^^^^^^^^^^ help: remove this call to `default` error: use of `default` to create a unit struct - --> $DIR/default_constructed_unit_structs.rs:105:42 + --> $DIR/default_constructed_unit_structs.rs:107:42 | LL | let _: PhantomData = PhantomData::default(); | ^^^^^^^^^^^ help: remove this call to `default` error: use of `default` to create a unit struct - --> $DIR/default_constructed_unit_structs.rs:106:23 + --> $DIR/default_constructed_unit_structs.rs:108:23 | LL | let _ = UnitStruct::default(); | ^^^^^^^^^^^ help: remove this call to `default` From 48ae5a071bc32e5fb69669248ab103ecba7509ab Mon Sep 17 00:00:00 2001 From: Icxolu <10486322+Icxolu@users.noreply.github.com> Date: Wed, 3 May 2023 21:43:10 +0200 Subject: [PATCH 83/86] fix lint docs --- clippy_lints/src/default_constructed_unit_structs.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/default_constructed_unit_structs.rs b/clippy_lints/src/default_constructed_unit_structs.rs index dab76a2c41ffb..e529d81a7e9f3 100644 --- a/clippy_lints/src/default_constructed_unit_structs.rs +++ b/clippy_lints/src/default_constructed_unit_structs.rs @@ -15,6 +15,7 @@ declare_clippy_lint! { /// /// ### Example /// ```rust + /// # use std::marker::PhantomData; /// #[derive(Default)] /// struct S { /// _marker: PhantomData @@ -26,9 +27,14 @@ declare_clippy_lint! { /// ``` /// Use instead: /// ```rust - /// let _: S = Something { - /// _marker: PhantomData + /// # use std::marker::PhantomData; + /// struct S { + /// _marker: PhantomData /// } + /// + /// let _: S = S { + /// _marker: PhantomData + /// }; /// ``` #[clippy::version = "1.71.0"] pub DEFAULT_CONSTRUCTED_UNIT_STRUCTS, From 0f7b61d729e20fd486bb26663993f63cce5a68eb Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Fri, 5 May 2023 11:45:24 +0000 Subject: [PATCH 84/86] Inherit stdout/stderr for `cargo dev dogfood` --- clippy_dev/src/dogfood.rs | 8 +++----- clippy_dev/src/lib.rs | 13 +++++++++++++ clippy_dev/src/lint.rs | 17 +++-------------- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/clippy_dev/src/dogfood.rs b/clippy_dev/src/dogfood.rs index b69e9f649ec78..a0d57f5ab483f 100644 --- a/clippy_dev/src/dogfood.rs +++ b/clippy_dev/src/dogfood.rs @@ -1,4 +1,4 @@ -use crate::clippy_project_root; +use crate::{clippy_project_root, exit_if_err}; use std::process::Command; /// # Panics @@ -10,7 +10,7 @@ pub fn dogfood(fix: bool, allow_dirty: bool, allow_staged: bool) { cmd.current_dir(clippy_project_root()) .args(["test", "--test", "dogfood"]) .args(["--features", "internal"]) - .args(["--", "dogfood_clippy"]); + .args(["--", "dogfood_clippy", "--nocapture"]); let mut dogfood_args = Vec::new(); if fix { @@ -27,7 +27,5 @@ pub fn dogfood(fix: bool, allow_dirty: bool, allow_staged: bool) { cmd.env("__CLIPPY_DOGFOOD_ARGS", dogfood_args.join(" ")); - let output = cmd.output().expect("failed to run command"); - - println!("{}", String::from_utf8_lossy(&output.stdout)); + exit_if_err(cmd.status()); } diff --git a/clippy_dev/src/lib.rs b/clippy_dev/src/lib.rs index 3a8b070d73516..56a269288c053 100644 --- a/clippy_dev/src/lib.rs +++ b/clippy_dev/src/lib.rs @@ -10,7 +10,9 @@ extern crate rustc_driver; extern crate rustc_lexer; +use std::io; use std::path::PathBuf; +use std::process::{self, ExitStatus}; pub mod bless; pub mod dogfood; @@ -58,3 +60,14 @@ pub fn clippy_project_root() -> PathBuf { } panic!("error: Can't determine root of project. Please run inside a Clippy working dir."); } + +pub fn exit_if_err(status: io::Result) { + match status.expect("failed to run command").code() { + Some(0) => {}, + Some(n) => process::exit(n), + None => { + eprintln!("Killed by signal"); + process::exit(1); + }, + } +} diff --git a/clippy_dev/src/lint.rs b/clippy_dev/src/lint.rs index aafd0f71a59bc..a19be1bca6c3d 100644 --- a/clippy_dev/src/lint.rs +++ b/clippy_dev/src/lint.rs @@ -1,17 +1,6 @@ -use crate::cargo_clippy_path; -use std::process::{self, Command, ExitStatus}; -use std::{fs, io}; - -fn exit_if_err(status: io::Result) { - match status.expect("failed to run command").code() { - Some(0) => {}, - Some(n) => process::exit(n), - None => { - eprintln!("Killed by signal"); - process::exit(1); - }, - } -} +use crate::{cargo_clippy_path, exit_if_err}; +use std::fs; +use std::process::{self, Command}; pub fn run<'a>(path: &str, args: impl Iterator) { let is_file = match fs::metadata(path) { From 79656cc95e0a1156360b678db71b1b851c3d2a61 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Fri, 5 May 2023 17:29:40 +0200 Subject: [PATCH 85/86] Bump nightly version -> 2023-05-05 --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index 91e8ccea1f434..60b8a5ac07193 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2023-04-06" +channel = "nightly-2023-05-05" components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] From b53c1bb2707cc2ffe36b3fdef1cc50a10ba6dcf6 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Fri, 5 May 2023 17:46:00 +0200 Subject: [PATCH 86/86] Update Cargo.lock --- Cargo.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8e71d8ceac8d0..d24a4271aa166 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -577,7 +577,7 @@ checksum = "8a2dd5a6fe8c6e3502f568a6353e5273bbb15193ad9a89e457b9970798efbea1" [[package]] name = "clippy" -version = "0.1.70" +version = "0.1.71" dependencies = [ "clap 4.2.1", "clippy_lints", @@ -619,7 +619,7 @@ dependencies = [ [[package]] name = "clippy_lints" -version = "0.1.70" +version = "0.1.71" dependencies = [ "arrayvec", "cargo_metadata 0.15.3", @@ -643,7 +643,7 @@ dependencies = [ [[package]] name = "clippy_utils" -version = "0.1.70" +version = "0.1.71" dependencies = [ "arrayvec", "if_chain", @@ -969,7 +969,7 @@ checksum = "a0afaad2b26fa326569eb264b1363e8ae3357618c43982b3f285f0774ce76b69" [[package]] name = "declare_clippy_lint" -version = "0.1.70" +version = "0.1.71" dependencies = [ "itertools", "quote",