From 7e83df40685907ea917813ec5b13fea360bdc070 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Thu, 7 Mar 2024 17:19:29 +0100 Subject: [PATCH] Merge commit '93f0a9a91f58c9b2153868f458402155fb6265bb' into clippy-subtree-update --- .github/driver.sh | 4 +- .github/workflows/clippy.yml | 11 +- .github/workflows/clippy_bors.yml | 32 +- CHANGELOG.md | 124 +- book/src/development/trait_checking.md | 50 + book/src/development/type_checking.md | 16 + book/src/lint_configuration.md | 1300 ++++++++--------- clippy_config/src/conf.rs | 6 +- clippy_config/src/lib.rs | 2 +- clippy_config/src/metadata.rs | 4 +- clippy_config/src/msrvs.rs | 1 + clippy_lints/src/assigning_clones.rs | 322 ++++ clippy_lints/src/attrs.rs | 1210 --------------- .../attrs/allow_attributes_without_reason.rs | 37 + .../attrs/blanket_clippy_restriction_lints.rs | 44 + clippy_lints/src/attrs/deprecated_cfg_attr.rs | 87 ++ clippy_lints/src/attrs/deprecated_semver.rs | 20 + clippy_lints/src/attrs/empty_line_after.rs | 52 + clippy_lints/src/attrs/inline_always.rs | 29 + clippy_lints/src/attrs/maybe_misused_cfg.rs | 51 + .../src/attrs/mismatched_target_os.rs | 90 ++ .../src/attrs/mixed_attributes_style.rs | 30 + clippy_lints/src/attrs/mod.rs | 588 ++++++++ clippy_lints/src/attrs/non_minimal_cfg.rs | 49 + .../src/attrs/should_panic_without_expect.rs | 54 + .../src/attrs/unnecessary_clippy_cfg.rs | 70 + clippy_lints/src/attrs/useless_attribute.rs | 73 + clippy_lints/src/attrs/utils.rs | 87 ++ clippy_lints/src/booleans.rs | 26 +- clippy_lints/src/casts/unnecessary_cast.rs | 13 +- clippy_lints/src/declared_lints.rs | 2 + clippy_lints/src/derive.rs | 6 +- clippy_lints/src/doc/markdown.rs | 17 +- clippy_lints/src/doc/mod.rs | 18 +- clippy_lints/src/entry.rs | 55 +- clippy_lints/src/let_underscore.rs | 5 +- clippy_lints/src/lib.rs | 2 + clippy_lints/src/loops/manual_memcpy.rs | 6 +- .../matches/significant_drop_in_scrutinee.rs | 7 +- clippy_lints/src/methods/mod.rs | 2 + clippy_lints/src/operators/identity_op.rs | 43 +- .../src/operators/misrefactored_assign_op.rs | 5 +- clippy_lints/src/question_mark.rs | 207 +-- clippy_lints/src/redundant_closure_call.rs | 9 + clippy_lints/src/redundant_field_names.rs | 34 +- clippy_lints/src/std_instead_of_core.rs | 6 +- ...ead_local_initializer_can_be_made_const.rs | 67 +- clippy_lints/src/transmute/mod.rs | 2 +- .../transmutes_expressible_as_ptr_casts.rs | 2 + clippy_lints/src/types/vec_box.rs | 7 +- clippy_utils/src/paths.rs | 1 - clippy_utils/src/sugg.rs | 2 +- rust-toolchain | 2 +- src/main.rs | 9 +- tests/compile-test.rs | 1 + tests/missing-test-files.rs | 2 +- tests/ui-internal/custom_ice_message.rs | 1 + tests/ui-internal/custom_ice_message.stderr | 7 +- tests/ui-internal/disallow_span_lint.rs | 15 +- tests/ui-internal/disallow_span_lint.stderr | 2 +- .../undocumented_unsafe_blocks.default.stderr | 74 +- ...undocumented_unsafe_blocks.disabled.stderr | 94 +- .../undocumented_unsafe_blocks.rs | 7 +- tests/ui/assigning_clones.fixed | 222 +++ tests/ui/assigning_clones.rs | 222 +++ tests/ui/assigning_clones.stderr | 107 ++ .../ui/crashes/unreachable-array-or-slice.rs | 2 +- tests/ui/derive_partial_eq_without_eq.fixed | 26 + tests/ui/derive_partial_eq_without_eq.rs | 26 + tests/ui/derive_partial_eq_without_eq.stderr | 14 +- tests/ui/doc/doc-fixable.fixed | 5 + tests/ui/doc/doc-fixable.rs | 5 + tests/ui/doc/doc-fixable.stderr | 13 +- tests/ui/doc/issue_9473.fixed | 9 + tests/ui/doc/issue_9473.rs | 9 + tests/ui/doc/issue_9473.stderr | 15 + tests/ui/else_if_without_else.rs | 2 + tests/ui/else_if_without_else.stderr | 4 +- tests/ui/empty_docs.rs | 2 + tests/ui/empty_docs.stderr | 18 +- tests/ui/entry.fixed | 11 + tests/ui/entry.rs | 11 + tests/ui/explicit_iter_loop.fixed | 2 +- tests/ui/explicit_iter_loop.rs | 2 +- tests/ui/field_reassign_with_default.rs | 1 + tests/ui/field_reassign_with_default.stderr | 44 +- tests/ui/identity_op.fixed | 2 +- tests/ui/identity_op.rs | 2 +- tests/ui/indexing_slicing_index.rs | 2 + tests/ui/indexing_slicing_index.stderr | 32 +- tests/ui/let_underscore_untyped.rs | 2 + tests/ui/manual_let_else.rs | 10 + tests/ui/manual_let_else.stderr | 68 +- .../ui/manual_memcpy/without_loop_counters.rs | 58 +- .../without_loop_counters.stderr | 52 +- tests/ui/manual_retain.fixed | 2 + tests/ui/manual_retain.rs | 2 + tests/ui/manual_retain.stderr | 76 +- tests/ui/many_single_char_names.rs | 2 + tests/ui/many_single_char_names.stderr | 10 +- tests/ui/min_rust_version_invalid_attr.rs | 2 + tests/ui/min_rust_version_invalid_attr.stderr | 12 +- tests/ui/mixed_attributes_style.rs | 39 + tests/ui/mixed_attributes_style.stderr | 30 + tests/ui/mut_mut.rs | 2 + tests/ui/mut_mut.stderr | 18 +- tests/ui/no_effect_replace.rs | 2 + tests/ui/no_effect_replace.stderr | 16 +- tests/ui/non_canonical_clone_impl.fixed | 1 + tests/ui/non_canonical_clone_impl.rs | 1 + tests/ui/non_canonical_clone_impl.stderr | 8 +- tests/ui/nonminimal_bool.rs | 6 + tests/ui/nonminimal_bool.stderr | 58 +- tests/ui/nonminimal_bool_methods.fixed | 2 + tests/ui/nonminimal_bool_methods.rs | 2 + tests/ui/nonminimal_bool_methods.stderr | 26 +- tests/ui/option_option.rs | 2 + tests/ui/option_option.stderr | 26 +- tests/ui/ptr_as_ptr.fixed | 1 + tests/ui/ptr_as_ptr.rs | 1 + tests/ui/ptr_as_ptr.stderr | 66 +- tests/ui/question_mark.fixed | 10 + tests/ui/question_mark.rs | 10 + tests/ui/redundant_closure_call_fixable.fixed | 17 + tests/ui/redundant_closure_call_fixable.rs | 17 + tests/ui/redundant_field_names.fixed | 15 +- tests/ui/redundant_field_names.rs | 15 +- tests/ui/redundant_field_names.stderr | 15 +- tests/ui/renamed_builtin_attr.fixed | 2 + tests/ui/renamed_builtin_attr.rs | 2 + tests/ui/renamed_builtin_attr.stderr | 2 +- tests/ui/single_match.fixed | 2 + tests/ui/single_match.rs | 2 + tests/ui/single_match.stderr | 36 +- tests/ui/single_match_else.fixed | 2 + tests/ui/single_match_else.rs | 2 + tests/ui/single_match_else.stderr | 18 +- tests/ui/std_instead_of_core.fixed | 11 +- tests/ui/std_instead_of_core.rs | 9 + tests/ui/std_instead_of_core.stderr | 36 +- tests/ui/suspicious_operation_groupings.fixed | 2 + tests/ui/suspicious_operation_groupings.rs | 2 + .../ui/suspicious_operation_groupings.stderr | 52 +- ..._local_initializer_can_be_made_const.fixed | 14 + ...ead_local_initializer_can_be_made_const.rs | 14 + ...local_initializer_can_be_made_const.stderr | 14 +- .../transmutes_expressible_as_ptr_casts.fixed | 7 + .../ui/transmutes_expressible_as_ptr_casts.rs | 7 + tests/ui/type_complexity.rs | 2 + tests/ui/type_complexity.stderr | 30 +- tests/ui/unknown_attribute.rs | 2 + tests/ui/unknown_attribute.stderr | 2 +- tests/ui/unnecessary_cast.fixed | 6 + tests/ui/unnecessary_cast.rs | 6 + tests/ui/unnecessary_cast.stderr | 8 +- 155 files changed, 4359 insertions(+), 2646 deletions(-) create mode 100644 clippy_lints/src/assigning_clones.rs delete mode 100644 clippy_lints/src/attrs.rs create mode 100644 clippy_lints/src/attrs/allow_attributes_without_reason.rs create mode 100644 clippy_lints/src/attrs/blanket_clippy_restriction_lints.rs create mode 100644 clippy_lints/src/attrs/deprecated_cfg_attr.rs create mode 100644 clippy_lints/src/attrs/deprecated_semver.rs create mode 100644 clippy_lints/src/attrs/empty_line_after.rs create mode 100644 clippy_lints/src/attrs/inline_always.rs create mode 100644 clippy_lints/src/attrs/maybe_misused_cfg.rs create mode 100644 clippy_lints/src/attrs/mismatched_target_os.rs create mode 100644 clippy_lints/src/attrs/mixed_attributes_style.rs create mode 100644 clippy_lints/src/attrs/mod.rs create mode 100644 clippy_lints/src/attrs/non_minimal_cfg.rs create mode 100644 clippy_lints/src/attrs/should_panic_without_expect.rs create mode 100644 clippy_lints/src/attrs/unnecessary_clippy_cfg.rs create mode 100644 clippy_lints/src/attrs/useless_attribute.rs create mode 100644 clippy_lints/src/attrs/utils.rs create mode 100644 tests/ui/assigning_clones.fixed create mode 100644 tests/ui/assigning_clones.rs create mode 100644 tests/ui/assigning_clones.stderr create mode 100644 tests/ui/doc/issue_9473.fixed create mode 100644 tests/ui/doc/issue_9473.rs create mode 100644 tests/ui/doc/issue_9473.stderr create mode 100644 tests/ui/mixed_attributes_style.rs create mode 100644 tests/ui/mixed_attributes_style.stderr diff --git a/.github/driver.sh b/.github/driver.sh index 11fd6b5c79e..2eafdd0fbc8 100755 --- a/.github/driver.sh +++ b/.github/driver.sh @@ -50,11 +50,11 @@ diff -u normalized.stderr tests/ui/double_neg.stderr # make sure "clippy-driver --rustc --arg" and "rustc --arg" behave the same SYSROOT=$(rustc --print sysroot) -diff -u <(LD_LIBRARY_PATH=${SYSROOT}/lib ./target/debug/clippy-driver --rustc --version --verbose) <(rustc --version --verbose) +diff -u <(./target/debug/clippy-driver --rustc --version --verbose) <(rustc --version --verbose) echo "fn main() {}" >target/driver_test.rs # we can't run 2 rustcs on the same file at the same time -CLIPPY=$(LD_LIBRARY_PATH=${SYSROOT}/lib ./target/debug/clippy-driver ./target/driver_test.rs --rustc) +CLIPPY=$(./target/debug/clippy-driver ./target/driver_test.rs --rustc) RUSTC=$(rustc ./target/driver_test.rs) diff -u <($CLIPPY) <($RUSTC) diff --git a/.github/workflows/clippy.yml b/.github/workflows/clippy.yml index 5ba960db66d..603f91a910b 100644 --- a/.github/workflows/clippy.yml +++ b/.github/workflows/clippy.yml @@ -44,11 +44,6 @@ jobs: run: rustup show active-toolchain # Run - - name: Set LD_LIBRARY_PATH (Linux) - run: | - SYSROOT=$(rustc --print sysroot) - echo "LD_LIBRARY_PATH=${SYSROOT}/lib${LD_LIBRARY_PATH+:${LD_LIBRARY_PATH}}" >> $GITHUB_ENV - - name: Build run: cargo build --tests --features deny-warnings,internal @@ -72,6 +67,6 @@ jobs: working-directory: clippy_dev - name: Test clippy-driver - run: bash .github/driver.sh - env: - OS: ${{ runner.os }} + run: | + TOOLCHAIN=$(rustup show active-toolchain | cut -f1 -d' ') + rustup run $TOOLCHAIN bash .github/driver.sh diff --git a/.github/workflows/clippy_bors.yml b/.github/workflows/clippy_bors.yml index 012797e5ca7..0bc28c1f9d9 100644 --- a/.github/workflows/clippy_bors.yml +++ b/.github/workflows/clippy_bors.yml @@ -59,7 +59,7 @@ jobs: host: i686-unknown-linux-gnu - os: windows-latest host: x86_64-pc-windows-msvc - - os: macos-latest + - os: macos-13 host: x86_64-apple-darwin runs-on: ${{ matrix.os }} @@ -87,23 +87,6 @@ jobs: rustup show active-toolchain # Run - - name: Set LD_LIBRARY_PATH (Linux) - if: runner.os == 'Linux' - run: | - SYSROOT=$(rustc --print sysroot) - echo "LD_LIBRARY_PATH=${SYSROOT}/lib${LD_LIBRARY_PATH+:${LD_LIBRARY_PATH}}" >> $GITHUB_ENV - - name: Link rustc dylib (MacOS) - if: runner.os == 'macOS' - run: | - SYSROOT=$(rustc --print sysroot) - sudo mkdir -p /usr/local/lib - sudo find "${SYSROOT}/lib" -maxdepth 1 -name '*dylib' -exec ln -s {} /usr/local/lib \; - - name: Set PATH (Windows) - if: runner.os == 'Windows' - run: | - SYSROOT=$(rustc --print sysroot) - echo "$SYSROOT/bin" >> $GITHUB_PATH - - name: Build run: cargo build --tests --features deny-warnings,internal @@ -136,7 +119,9 @@ jobs: working-directory: clippy_dev - name: Test clippy-driver - run: bash .github/driver.sh + run: | + TOOLCHAIN=$(rustup show active-toolchain | cut -f1 -d' ') + rustup run $TOOLCHAIN bash .github/driver.sh env: OS: ${{ runner.os }} @@ -236,11 +221,6 @@ jobs: - name: Install toolchain run: rustup show active-toolchain - - name: Set LD_LIBRARY_PATH - run: | - SYSROOT=$(rustc --print sysroot) - echo "LD_LIBRARY_PATH=${SYSROOT}/lib${LD_LIBRARY_PATH+:${LD_LIBRARY_PATH}}" >> $GITHUB_ENV - # Download - name: Download target dir uses: actions/download-artifact@v3 @@ -254,8 +234,8 @@ jobs: # Run - name: Test ${{ matrix.integration }} run: | - RUSTUP_TOOLCHAIN="$(rustup show active-toolchain | grep -o -E "nightly-[0-9]{4}-[0-9]{2}-[0-9]{2}")" \ - $CARGO_TARGET_DIR/debug/integration --show-output + TOOLCHAIN=$(rustup show active-toolchain | cut -f1 -d' ') + rustup run $TOOLCHAIN $CARGO_TARGET_DIR/debug/integration --show-output env: INTEGRATION: ${{ matrix.integration }} diff --git a/CHANGELOG.md b/CHANGELOG.md index f0b01742deb..d3b2c0a7bf6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5046,6 +5046,7 @@ Released 2018-09-13 [`assertions_on_result_states`]: https://rust-lang.github.io/rust-clippy/master/index.html#assertions_on_result_states [`assign_op_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#assign_op_pattern [`assign_ops`]: https://rust-lang.github.io/rust-clippy/master/index.html#assign_ops +[`assigning_clones`]: https://rust-lang.github.io/rust-clippy/master/index.html#assigning_clones [`async_yields_async`]: https://rust-lang.github.io/rust-clippy/master/index.html#async_yields_async [`await_holding_invalid_type`]: https://rust-lang.github.io/rust-clippy/master/index.html#await_holding_invalid_type [`await_holding_lock`]: https://rust-lang.github.io/rust-clippy/master/index.html#await_holding_lock @@ -5423,6 +5424,7 @@ Released 2018-09-13 [`missing_spin_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_spin_loop [`missing_trait_methods`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_trait_methods [`mistyped_literal_suffixes`]: https://rust-lang.github.io/rust-clippy/master/index.html#mistyped_literal_suffixes +[`mixed_attributes_style`]: https://rust-lang.github.io/rust-clippy/master/index.html#mixed_attributes_style [`mixed_case_hex_literals`]: https://rust-lang.github.io/rust-clippy/master/index.html#mixed_case_hex_literals [`mixed_read_write_in_expression`]: https://rust-lang.github.io/rust-clippy/master/index.html#mixed_read_write_in_expression [`mod_module_files`]: https://rust-lang.github.io/rust-clippy/master/index.html#mod_module_files @@ -5816,74 +5818,74 @@ Released 2018-09-13 [`zst_offset`]: https://rust-lang.github.io/rust-clippy/master/index.html#zst_offset +[`absolute-paths-allowed-crates`]: https://doc.rust-lang.org/clippy/lint_configuration.html#absolute-paths-allowed-crates +[`absolute-paths-max-segments`]: https://doc.rust-lang.org/clippy/lint_configuration.html#absolute-paths-max-segments +[`accept-comment-above-attributes`]: https://doc.rust-lang.org/clippy/lint_configuration.html#accept-comment-above-attributes +[`accept-comment-above-statement`]: https://doc.rust-lang.org/clippy/lint_configuration.html#accept-comment-above-statement +[`allow-comparison-to-zero`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-comparison-to-zero +[`allow-dbg-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-dbg-in-tests +[`allow-expect-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-expect-in-tests +[`allow-mixed-uninlined-format-args`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-mixed-uninlined-format-args +[`allow-one-hash-in-raw-strings`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-one-hash-in-raw-strings +[`allow-print-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-print-in-tests +[`allow-private-module-inception`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-private-module-inception +[`allow-unwrap-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-unwrap-in-tests +[`allowed-dotfiles`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-dotfiles +[`allowed-duplicate-crates`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-duplicate-crates +[`allowed-idents-below-min-chars`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-idents-below-min-chars +[`allowed-scripts`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-scripts +[`allowed-wildcard-imports`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-wildcard-imports [`arithmetic-side-effects-allowed`]: https://doc.rust-lang.org/clippy/lint_configuration.html#arithmetic-side-effects-allowed [`arithmetic-side-effects-allowed-binary`]: https://doc.rust-lang.org/clippy/lint_configuration.html#arithmetic-side-effects-allowed-binary [`arithmetic-side-effects-allowed-unary`]: https://doc.rust-lang.org/clippy/lint_configuration.html#arithmetic-side-effects-allowed-unary -[`avoid-breaking-exported-api`]: https://doc.rust-lang.org/clippy/lint_configuration.html#avoid-breaking-exported-api -[`msrv`]: https://doc.rust-lang.org/clippy/lint_configuration.html#msrv -[`cognitive-complexity-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#cognitive-complexity-threshold -[`excessive-nesting-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#excessive-nesting-threshold -[`disallowed-names`]: https://doc.rust-lang.org/clippy/lint_configuration.html#disallowed-names -[`semicolon-inside-block-ignore-singleline`]: https://doc.rust-lang.org/clippy/lint_configuration.html#semicolon-inside-block-ignore-singleline -[`semicolon-outside-block-ignore-multiline`]: https://doc.rust-lang.org/clippy/lint_configuration.html#semicolon-outside-block-ignore-multiline -[`doc-valid-idents`]: https://doc.rust-lang.org/clippy/lint_configuration.html#doc-valid-idents -[`too-many-arguments-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#too-many-arguments-threshold -[`type-complexity-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#type-complexity-threshold -[`single-char-binding-names-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#single-char-binding-names-threshold -[`too-large-for-stack`]: https://doc.rust-lang.org/clippy/lint_configuration.html#too-large-for-stack -[`enum-variant-name-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#enum-variant-name-threshold -[`struct-field-name-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#struct-field-name-threshold -[`enum-variant-size-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#enum-variant-size-threshold -[`verbose-bit-mask-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#verbose-bit-mask-threshold -[`literal-representation-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#literal-representation-threshold -[`trivial-copy-size-limit`]: https://doc.rust-lang.org/clippy/lint_configuration.html#trivial-copy-size-limit -[`pass-by-value-size-limit`]: https://doc.rust-lang.org/clippy/lint_configuration.html#pass-by-value-size-limit -[`too-many-lines-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#too-many-lines-threshold [`array-size-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#array-size-threshold -[`stack-size-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#stack-size-threshold -[`vec-box-size-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#vec-box-size-threshold -[`max-trait-bounds`]: https://doc.rust-lang.org/clippy/lint_configuration.html#max-trait-bounds -[`max-struct-bools`]: https://doc.rust-lang.org/clippy/lint_configuration.html#max-struct-bools -[`max-fn-params-bools`]: https://doc.rust-lang.org/clippy/lint_configuration.html#max-fn-params-bools -[`warn-on-all-wildcard-imports`]: https://doc.rust-lang.org/clippy/lint_configuration.html#warn-on-all-wildcard-imports +[`avoid-breaking-exported-api`]: https://doc.rust-lang.org/clippy/lint_configuration.html#avoid-breaking-exported-api +[`await-holding-invalid-types`]: https://doc.rust-lang.org/clippy/lint_configuration.html#await-holding-invalid-types +[`cargo-ignore-publish`]: https://doc.rust-lang.org/clippy/lint_configuration.html#cargo-ignore-publish +[`check-private-items`]: https://doc.rust-lang.org/clippy/lint_configuration.html#check-private-items +[`cognitive-complexity-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#cognitive-complexity-threshold [`disallowed-macros`]: https://doc.rust-lang.org/clippy/lint_configuration.html#disallowed-macros [`disallowed-methods`]: https://doc.rust-lang.org/clippy/lint_configuration.html#disallowed-methods +[`disallowed-names`]: https://doc.rust-lang.org/clippy/lint_configuration.html#disallowed-names [`disallowed-types`]: https://doc.rust-lang.org/clippy/lint_configuration.html#disallowed-types +[`doc-valid-idents`]: https://doc.rust-lang.org/clippy/lint_configuration.html#doc-valid-idents +[`enable-raw-pointer-heuristic-for-send`]: https://doc.rust-lang.org/clippy/lint_configuration.html#enable-raw-pointer-heuristic-for-send +[`enforce-iter-loop-reborrow`]: https://doc.rust-lang.org/clippy/lint_configuration.html#enforce-iter-loop-reborrow +[`enforced-import-renames`]: https://doc.rust-lang.org/clippy/lint_configuration.html#enforced-import-renames +[`enum-variant-name-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#enum-variant-name-threshold +[`enum-variant-size-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#enum-variant-size-threshold +[`excessive-nesting-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#excessive-nesting-threshold +[`future-size-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#future-size-threshold +[`ignore-interior-mutability`]: https://doc.rust-lang.org/clippy/lint_configuration.html#ignore-interior-mutability +[`large-error-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#large-error-threshold +[`literal-representation-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#literal-representation-threshold +[`matches-for-let-else`]: https://doc.rust-lang.org/clippy/lint_configuration.html#matches-for-let-else +[`max-fn-params-bools`]: https://doc.rust-lang.org/clippy/lint_configuration.html#max-fn-params-bools +[`max-include-file-size`]: https://doc.rust-lang.org/clippy/lint_configuration.html#max-include-file-size +[`max-struct-bools`]: https://doc.rust-lang.org/clippy/lint_configuration.html#max-struct-bools +[`max-suggested-slice-pattern-length`]: https://doc.rust-lang.org/clippy/lint_configuration.html#max-suggested-slice-pattern-length +[`max-trait-bounds`]: https://doc.rust-lang.org/clippy/lint_configuration.html#max-trait-bounds +[`min-ident-chars-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#min-ident-chars-threshold +[`missing-docs-in-crate-items`]: https://doc.rust-lang.org/clippy/lint_configuration.html#missing-docs-in-crate-items +[`msrv`]: https://doc.rust-lang.org/clippy/lint_configuration.html#msrv +[`pass-by-value-size-limit`]: https://doc.rust-lang.org/clippy/lint_configuration.html#pass-by-value-size-limit +[`pub-underscore-fields-behavior`]: https://doc.rust-lang.org/clippy/lint_configuration.html#pub-underscore-fields-behavior +[`semicolon-inside-block-ignore-singleline`]: https://doc.rust-lang.org/clippy/lint_configuration.html#semicolon-inside-block-ignore-singleline +[`semicolon-outside-block-ignore-multiline`]: https://doc.rust-lang.org/clippy/lint_configuration.html#semicolon-outside-block-ignore-multiline +[`single-char-binding-names-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#single-char-binding-names-threshold +[`stack-size-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#stack-size-threshold +[`standard-macro-braces`]: https://doc.rust-lang.org/clippy/lint_configuration.html#standard-macro-braces +[`struct-field-name-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#struct-field-name-threshold +[`suppress-restriction-lint-in-const`]: https://doc.rust-lang.org/clippy/lint_configuration.html#suppress-restriction-lint-in-const +[`too-large-for-stack`]: https://doc.rust-lang.org/clippy/lint_configuration.html#too-large-for-stack +[`too-many-arguments-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#too-many-arguments-threshold +[`too-many-lines-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#too-many-lines-threshold +[`trivial-copy-size-limit`]: https://doc.rust-lang.org/clippy/lint_configuration.html#trivial-copy-size-limit +[`type-complexity-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#type-complexity-threshold +[`unnecessary-box-size`]: https://doc.rust-lang.org/clippy/lint_configuration.html#unnecessary-box-size [`unreadable-literal-lint-fractions`]: https://doc.rust-lang.org/clippy/lint_configuration.html#unreadable-literal-lint-fractions [`upper-case-acronyms-aggressive`]: https://doc.rust-lang.org/clippy/lint_configuration.html#upper-case-acronyms-aggressive -[`matches-for-let-else`]: https://doc.rust-lang.org/clippy/lint_configuration.html#matches-for-let-else -[`cargo-ignore-publish`]: https://doc.rust-lang.org/clippy/lint_configuration.html#cargo-ignore-publish -[`standard-macro-braces`]: https://doc.rust-lang.org/clippy/lint_configuration.html#standard-macro-braces -[`enforced-import-renames`]: https://doc.rust-lang.org/clippy/lint_configuration.html#enforced-import-renames -[`allowed-scripts`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-scripts -[`enable-raw-pointer-heuristic-for-send`]: https://doc.rust-lang.org/clippy/lint_configuration.html#enable-raw-pointer-heuristic-for-send -[`max-suggested-slice-pattern-length`]: https://doc.rust-lang.org/clippy/lint_configuration.html#max-suggested-slice-pattern-length -[`await-holding-invalid-types`]: https://doc.rust-lang.org/clippy/lint_configuration.html#await-holding-invalid-types -[`max-include-file-size`]: https://doc.rust-lang.org/clippy/lint_configuration.html#max-include-file-size -[`allow-expect-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-expect-in-tests -[`allow-unwrap-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-unwrap-in-tests -[`allow-dbg-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-dbg-in-tests -[`allow-print-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-print-in-tests -[`large-error-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#large-error-threshold -[`ignore-interior-mutability`]: https://doc.rust-lang.org/clippy/lint_configuration.html#ignore-interior-mutability -[`allow-mixed-uninlined-format-args`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-mixed-uninlined-format-args -[`suppress-restriction-lint-in-const`]: https://doc.rust-lang.org/clippy/lint_configuration.html#suppress-restriction-lint-in-const -[`missing-docs-in-crate-items`]: https://doc.rust-lang.org/clippy/lint_configuration.html#missing-docs-in-crate-items -[`future-size-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#future-size-threshold -[`unnecessary-box-size`]: https://doc.rust-lang.org/clippy/lint_configuration.html#unnecessary-box-size -[`allow-private-module-inception`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-private-module-inception -[`allowed-idents-below-min-chars`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-idents-below-min-chars -[`min-ident-chars-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#min-ident-chars-threshold -[`accept-comment-above-statement`]: https://doc.rust-lang.org/clippy/lint_configuration.html#accept-comment-above-statement -[`accept-comment-above-attributes`]: https://doc.rust-lang.org/clippy/lint_configuration.html#accept-comment-above-attributes -[`allow-one-hash-in-raw-strings`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-one-hash-in-raw-strings -[`absolute-paths-max-segments`]: https://doc.rust-lang.org/clippy/lint_configuration.html#absolute-paths-max-segments -[`absolute-paths-allowed-crates`]: https://doc.rust-lang.org/clippy/lint_configuration.html#absolute-paths-allowed-crates -[`allowed-dotfiles`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-dotfiles -[`allowed-duplicate-crates`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-duplicate-crates -[`enforce-iter-loop-reborrow`]: https://doc.rust-lang.org/clippy/lint_configuration.html#enforce-iter-loop-reborrow -[`check-private-items`]: https://doc.rust-lang.org/clippy/lint_configuration.html#check-private-items -[`pub-underscore-fields-behavior`]: https://doc.rust-lang.org/clippy/lint_configuration.html#pub-underscore-fields-behavior -[`allow-comparison-to-zero`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-comparison-to-zero -[`allowed-wildcard-imports`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-wildcard-imports +[`vec-box-size-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#vec-box-size-threshold +[`verbose-bit-mask-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#verbose-bit-mask-threshold +[`warn-on-all-wildcard-imports`]: https://doc.rust-lang.org/clippy/lint_configuration.html#warn-on-all-wildcard-imports diff --git a/book/src/development/trait_checking.md b/book/src/development/trait_checking.md index fb263922cf8..b7d229ccc19 100644 --- a/book/src/development/trait_checking.md +++ b/book/src/development/trait_checking.md @@ -94,6 +94,53 @@ impl LateLintPass<'_> for CheckTokioAsyncReadExtTrait { } ``` +## Creating Types Programmatically + +Traits are often generic over a type parameter, e.g. `Borrow` is generic +over `T`. Rust allows us to implement a trait for a specific type. For example, +we can implement `Borrow<[u8]>` for a hypothetical type `Foo`. Let's suppose +that we would like to find whether our type actually implements `Borrow<[u8]>`. + +To do so, we can use the same `implements_trait` function as above, and supply +a type parameter that represents `[u8]`. Since `[u8]` is a specialization of +`[T]`, we can use the [`Ty::new_slice`][new_slice] method to create a type +that represents `[T]` and supply `u8` as a type parameter. +To create a `ty::Ty` programmatically, we rely on `Ty::new_*` methods. These +methods create a `TyKind` and then wrap it in a `Ty` struct. This means we +have access to all the primitive types, such as `Ty::new_char`, +`Ty::new_bool`, `Ty::new_int`, etc. We can also create more complex types, +such as slices, tuples, and references out of these basic building blocks. + +For trait checking, it is not enough to create the types, we need to convert +them into [GenericArg]. In rustc, a generic is an entity that the compiler +understands and has three kinds, type, const and lifetime. By calling +`.into()` on a constructed [Ty], we wrap the type into a generic which can +then be used by the query system to decide whether the specialized trait +is implemented. + +The following code demonstrates how to do this: + +```rust + +use rustc_middle::ty::Ty; +use clippy_utils::ty::implements_trait; +use rustc_span::symbol::sym; + +let ty = todo!("Get the `Foo` type to check for a trait implementation"); +let borrow_id = cx.tcx.get_diagnostic_item(sym::Borrow).unwrap(); // avoid unwrap in real code +let slice_of_bytes_t = Ty::new_slice(cx.tcx, cx.tcx.types.u8); +let generic_param = slice_of_bytes_t.into(); +if implements_trait(cx, ty, borrow_id, &[generic_param]) { + todo!("Rest of lint implementation") +} +``` + +In essence, the [Ty] struct allows us to create types programmatically in a +representation that can be used by the compiler and the query engine. We then +use the `rustc_middle::Ty` of the type we are interested in, and query the +compiler to see if it indeed implements the trait we are interested in. + + [DefId]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/def_id/struct.DefId.html [diagnostic_items]: https://rustc-dev-guide.rust-lang.org/diagnostics/diagnostic-items.html [lang_items]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/lang_items/struct.LanguageItems.html @@ -102,4 +149,7 @@ impl LateLintPass<'_> for CheckTokioAsyncReadExtTrait { [symbol]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_span/symbol/struct.Symbol.html [symbol_index]: https://doc.rust-lang.org/beta/nightly-rustc/rustc_span/symbol/sym/index.html [TyCtxt]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/context/struct.TyCtxt.html +[Ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.Ty.html [rust]: https://github.com/rust-lang/rust +[new_slice]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.Ty.html#method.new_slice +[GenericArg]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.GenericArg.html diff --git a/book/src/development/type_checking.md b/book/src/development/type_checking.md index dc29ab5d08d..136b3fd0270 100644 --- a/book/src/development/type_checking.md +++ b/book/src/development/type_checking.md @@ -123,6 +123,22 @@ the [`TypeckResults::node_type()`][node_type] method inside of bodies. > **Warning**: Don't use `hir_ty_to_ty` inside of bodies, because this can cause ICEs. +## Creating Types programmatically + +A common usecase for creating types programmatically is when we want to check if a type implements a trait (see +[Trait Checking](trait_checking.md)). + +Here's an example of how to create a `Ty` for a slice of `u8`, i.e. `[u8]` + +```rust +use rustc_middle::ty::Ty; +// assume we have access to a LateContext +let ty = Ty::new_slice(cx.tcx, Ty::new_u8()); +``` + +In general, we rely on `Ty::new_*` methods. These methods define the basic building-blocks that the +type-system and trait-system use to define and understand the written code. + ## Useful Links Below are some useful links to further explore the concepts covered diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md index 214a60d3bfd..a985346b3c0 100644 --- a/book/src/lint_configuration.md +++ b/book/src/lint_configuration.md @@ -10,6 +10,192 @@ and lints affected. --- +## `absolute-paths-allowed-crates` +Which crates to allow absolute paths from + +**Default Value:** `[]` + +--- +**Affected lints:** +* [`absolute_paths`](https://rust-lang.github.io/rust-clippy/master/index.html#absolute_paths) + + +## `absolute-paths-max-segments` +The maximum number of segments a path can have before being linted, anything above this will +be linted. + +**Default Value:** `2` + +--- +**Affected lints:** +* [`absolute_paths`](https://rust-lang.github.io/rust-clippy/master/index.html#absolute_paths) + + +## `accept-comment-above-attributes` +Whether to accept a safety comment to be placed above the attributes for the `unsafe` block + +**Default Value:** `true` + +--- +**Affected lints:** +* [`undocumented_unsafe_blocks`](https://rust-lang.github.io/rust-clippy/master/index.html#undocumented_unsafe_blocks) + + +## `accept-comment-above-statement` +Whether to accept a safety comment to be placed above the statement containing the `unsafe` block + +**Default Value:** `true` + +--- +**Affected lints:** +* [`undocumented_unsafe_blocks`](https://rust-lang.github.io/rust-clippy/master/index.html#undocumented_unsafe_blocks) + + +## `allow-comparison-to-zero` +Don't lint when comparing the result of a modulo operation to zero. + +**Default Value:** `true` + +--- +**Affected lints:** +* [`modulo_arithmetic`](https://rust-lang.github.io/rust-clippy/master/index.html#modulo_arithmetic) + + +## `allow-dbg-in-tests` +Whether `dbg!` should be allowed in test functions or `#[cfg(test)]` + +**Default Value:** `false` + +--- +**Affected lints:** +* [`dbg_macro`](https://rust-lang.github.io/rust-clippy/master/index.html#dbg_macro) + + +## `allow-expect-in-tests` +Whether `expect` should be allowed in test functions or `#[cfg(test)]` + +**Default Value:** `false` + +--- +**Affected lints:** +* [`expect_used`](https://rust-lang.github.io/rust-clippy/master/index.html#expect_used) + + +## `allow-mixed-uninlined-format-args` +Whether to allow mixed uninlined format args, e.g. `format!("{} {}", a, foo.bar)` + +**Default Value:** `true` + +--- +**Affected lints:** +* [`uninlined_format_args`](https://rust-lang.github.io/rust-clippy/master/index.html#uninlined_format_args) + + +## `allow-one-hash-in-raw-strings` +Whether to allow `r#""#` when `r""` can be used + +**Default Value:** `false` + +--- +**Affected lints:** +* [`unnecessary_raw_string_hashes`](https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_raw_string_hashes) + + +## `allow-print-in-tests` +Whether print macros (ex. `println!`) should be allowed in test functions or `#[cfg(test)]` + +**Default Value:** `false` + +--- +**Affected lints:** +* [`print_stderr`](https://rust-lang.github.io/rust-clippy/master/index.html#print_stderr) +* [`print_stdout`](https://rust-lang.github.io/rust-clippy/master/index.html#print_stdout) + + +## `allow-private-module-inception` +Whether to allow module inception if it's not public. + +**Default Value:** `false` + +--- +**Affected lints:** +* [`module_inception`](https://rust-lang.github.io/rust-clippy/master/index.html#module_inception) + + +## `allow-unwrap-in-tests` +Whether `unwrap` should be allowed in test functions or `#[cfg(test)]` + +**Default Value:** `false` + +--- +**Affected lints:** +* [`unwrap_used`](https://rust-lang.github.io/rust-clippy/master/index.html#unwrap_used) + + +## `allowed-dotfiles` +Additional dotfiles (files or directories starting with a dot) to allow + +**Default Value:** `[]` + +--- +**Affected lints:** +* [`path_ends_with_ext`](https://rust-lang.github.io/rust-clippy/master/index.html#path_ends_with_ext) + + +## `allowed-duplicate-crates` +A list of crate names to allow duplicates of + +**Default Value:** `[]` + +--- +**Affected lints:** +* [`multiple_crate_versions`](https://rust-lang.github.io/rust-clippy/master/index.html#multiple_crate_versions) + + +## `allowed-idents-below-min-chars` +Allowed names below the minimum allowed characters. 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 Value:** `["j", "z", "i", "y", "n", "x", "w"]` + +--- +**Affected lints:** +* [`min_ident_chars`](https://rust-lang.github.io/rust-clippy/master/index.html#min_ident_chars) + + +## `allowed-scripts` +The list of unicode scripts allowed to be used in the scope. + +**Default Value:** `["Latin"]` + +--- +**Affected lints:** +* [`disallowed_script_idents`](https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_script_idents) + + +## `allowed-wildcard-imports` +List of path segments allowed to have wildcard imports. + +#### Example + +```toml +allowed-wildcard-imports = [ "utils", "common" ] +``` + +#### Noteworthy + +1. This configuration has no effects if used with `warn_on_all_wildcard_imports = true`. +2. Paths with any segment that containing the word 'prelude' +are already allowed by default. + +**Default Value:** `[]` + +--- +**Affected lints:** +* [`wildcard_imports`](https://rust-lang.github.io/rust-clippy/master/index.html#wildcard_imports) + + ## `arithmetic-side-effects-allowed` Suppress checking of the passed type names in all types of operations. @@ -72,6 +258,17 @@ arithmetic-side-effects-allowed-unary = ["SomeType", "AnotherType"] * [`arithmetic_side_effects`](https://rust-lang.github.io/rust-clippy/master/index.html#arithmetic_side_effects) +## `array-size-threshold` +The maximum allowed size for arrays on the stack + +**Default Value:** `512000` + +--- +**Affected lints:** +* [`large_const_arrays`](https://rust-lang.github.io/rust-clippy/master/index.html#large_const_arrays) +* [`large_stack_arrays`](https://rust-lang.github.io/rust-clippy/master/index.html#large_stack_arrays) + + ## `avoid-breaking-exported-api` Suppress lints whenever the suggested change would cause breakage for other crates. @@ -79,79 +276,55 @@ Suppress lints whenever the suggested change would cause breakage for other crat --- **Affected lints:** +* [`box_collection`](https://rust-lang.github.io/rust-clippy/master/index.html#box_collection) * [`enum_variant_names`](https://rust-lang.github.io/rust-clippy/master/index.html#enum_variant_names) * [`large_types_passed_by_value`](https://rust-lang.github.io/rust-clippy/master/index.html#large_types_passed_by_value) +* [`linkedlist`](https://rust-lang.github.io/rust-clippy/master/index.html#linkedlist) +* [`option_option`](https://rust-lang.github.io/rust-clippy/master/index.html#option_option) +* [`rc_buffer`](https://rust-lang.github.io/rust-clippy/master/index.html#rc_buffer) +* [`rc_mutex`](https://rust-lang.github.io/rust-clippy/master/index.html#rc_mutex) +* [`redundant_allocation`](https://rust-lang.github.io/rust-clippy/master/index.html#redundant_allocation) +* [`single_call_fn`](https://rust-lang.github.io/rust-clippy/master/index.html#single_call_fn) * [`trivially_copy_pass_by_ref`](https://rust-lang.github.io/rust-clippy/master/index.html#trivially_copy_pass_by_ref) +* [`unnecessary_box_returns`](https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_box_returns) * [`unnecessary_wraps`](https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_wraps) * [`unused_self`](https://rust-lang.github.io/rust-clippy/master/index.html#unused_self) * [`upper_case_acronyms`](https://rust-lang.github.io/rust-clippy/master/index.html#upper_case_acronyms) -* [`wrong_self_convention`](https://rust-lang.github.io/rust-clippy/master/index.html#wrong_self_convention) -* [`box_collection`](https://rust-lang.github.io/rust-clippy/master/index.html#box_collection) -* [`redundant_allocation`](https://rust-lang.github.io/rust-clippy/master/index.html#redundant_allocation) -* [`rc_buffer`](https://rust-lang.github.io/rust-clippy/master/index.html#rc_buffer) * [`vec_box`](https://rust-lang.github.io/rust-clippy/master/index.html#vec_box) -* [`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) -* [`single_call_fn`](https://rust-lang.github.io/rust-clippy/master/index.html#single_call_fn) +* [`wrong_self_convention`](https://rust-lang.github.io/rust-clippy/master/index.html#wrong_self_convention) -## `msrv` -The minimum rust version that the project supports. Defaults to the `rust-version` field in `Cargo.toml` +## `await-holding-invalid-types` + + +**Default Value:** `[]` --- **Affected lints:** -* [`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) -* [`cloned_instead_of_copied`](https://rust-lang.github.io/rust-clippy/master/index.html#cloned_instead_of_copied) -* [`redundant_field_names`](https://rust-lang.github.io/rust-clippy/master/index.html#redundant_field_names) -* [`option_map_unwrap_or`](https://rust-lang.github.io/rust-clippy/master/index.html#option_map_unwrap_or) -* [`redundant_static_lifetimes`](https://rust-lang.github.io/rust-clippy/master/index.html#redundant_static_lifetimes) -* [`filter_map_next`](https://rust-lang.github.io/rust-clippy/master/index.html#filter_map_next) -* [`checked_conversions`](https://rust-lang.github.io/rust-clippy/master/index.html#checked_conversions) -* [`manual_range_contains`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_range_contains) -* [`use_self`](https://rust-lang.github.io/rust-clippy/master/index.html#use_self) -* [`mem_replace_with_default`](https://rust-lang.github.io/rust-clippy/master/index.html#mem_replace_with_default) -* [`manual_non_exhaustive`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_non_exhaustive) -* [`option_as_ref_deref`](https://rust-lang.github.io/rust-clippy/master/index.html#option_as_ref_deref) -* [`map_unwrap_or`](https://rust-lang.github.io/rust-clippy/master/index.html#map_unwrap_or) -* [`match_like_matches_macro`](https://rust-lang.github.io/rust-clippy/master/index.html#match_like_matches_macro) -* [`manual_strip`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_strip) -* [`missing_const_for_fn`](https://rust-lang.github.io/rust-clippy/master/index.html#missing_const_for_fn) -* [`unnested_or_patterns`](https://rust-lang.github.io/rust-clippy/master/index.html#unnested_or_patterns) -* [`from_over_into`](https://rust-lang.github.io/rust-clippy/master/index.html#from_over_into) -* [`ptr_as_ptr`](https://rust-lang.github.io/rust-clippy/master/index.html#ptr_as_ptr) -* [`if_then_some_else_none`](https://rust-lang.github.io/rust-clippy/master/index.html#if_then_some_else_none) -* [`approx_constant`](https://rust-lang.github.io/rust-clippy/master/index.html#approx_constant) -* [`deprecated_cfg_attr`](https://rust-lang.github.io/rust-clippy/master/index.html#deprecated_cfg_attr) -* [`index_refutable_slice`](https://rust-lang.github.io/rust-clippy/master/index.html#index_refutable_slice) -* [`map_clone`](https://rust-lang.github.io/rust-clippy/master/index.html#map_clone) -* [`borrow_as_ptr`](https://rust-lang.github.io/rust-clippy/master/index.html#borrow_as_ptr) -* [`manual_bits`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_bits) -* [`err_expect`](https://rust-lang.github.io/rust-clippy/master/index.html#err_expect) -* [`cast_abs_to_unsigned`](https://rust-lang.github.io/rust-clippy/master/index.html#cast_abs_to_unsigned) -* [`uninlined_format_args`](https://rust-lang.github.io/rust-clippy/master/index.html#uninlined_format_args) -* [`manual_clamp`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_clamp) -* [`manual_let_else`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_let_else) -* [`unchecked_duration_subtraction`](https://rust-lang.github.io/rust-clippy/master/index.html#unchecked_duration_subtraction) -* [`collapsible_str_replace`](https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_str_replace) -* [`seek_from_current`](https://rust-lang.github.io/rust-clippy/master/index.html#seek_from_current) -* [`seek_rewind`](https://rust-lang.github.io/rust-clippy/master/index.html#seek_rewind) -* [`unnecessary_lazy_evaluations`](https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_lazy_evaluations) -* [`transmute_ptr_to_ref`](https://rust-lang.github.io/rust-clippy/master/index.html#transmute_ptr_to_ref) -* [`almost_complete_range`](https://rust-lang.github.io/rust-clippy/master/index.html#almost_complete_range) -* [`needless_borrow`](https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow) -* [`derivable_impls`](https://rust-lang.github.io/rust-clippy/master/index.html#derivable_impls) -* [`manual_is_ascii_check`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_ascii_check) -* [`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) -* [`type_repetition_in_bounds`](https://rust-lang.github.io/rust-clippy/master/index.html#type_repetition_in_bounds) -* [`tuple_array_conversions`](https://rust-lang.github.io/rust-clippy/master/index.html#tuple_array_conversions) -* [`manual_try_fold`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_try_fold) -* [`manual_hash_one`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_hash_one) -* [`iter_kv_map`](https://rust-lang.github.io/rust-clippy/master/index.html#iter_kv_map) -* [`manual_c_str_literals`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_c_str_literals) +* [`await_holding_invalid_type`](https://rust-lang.github.io/rust-clippy/master/index.html#await_holding_invalid_type) + + +## `cargo-ignore-publish` +For internal testing only, ignores the current `publish` settings in the Cargo manifest. + +**Default Value:** `false` + +--- +**Affected lints:** +* [`cargo_common_metadata`](https://rust-lang.github.io/rust-clippy/master/index.html#cargo_common_metadata) + + +## `check-private-items` +Whether to also run the listed lints on private items. + +**Default Value:** `false` + +--- +**Affected lints:** +* [`missing_errors_doc`](https://rust-lang.github.io/rust-clippy/master/index.html#missing_errors_doc) +* [`missing_panics_doc`](https://rust-lang.github.io/rust-clippy/master/index.html#missing_panics_doc) +* [`missing_safety_doc`](https://rust-lang.github.io/rust-clippy/master/index.html#missing_safety_doc) +* [`unnecessary_safety_doc`](https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_safety_doc) ## `cognitive-complexity-threshold` @@ -164,253 +337,6 @@ The maximum cognitive complexity a function can have * [`cognitive_complexity`](https://rust-lang.github.io/rust-clippy/master/index.html#cognitive_complexity) -## `excessive-nesting-threshold` -The maximum amount of nesting a block can reside in - -**Default Value:** `0` - ---- -**Affected lints:** -* [`excessive_nesting`](https://rust-lang.github.io/rust-clippy/master/index.html#excessive_nesting) - - -## `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 Value:** `["foo", "baz", "quux"]` - ---- -**Affected lints:** -* [`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` - ---- -**Affected lints:** -* [`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` - ---- -**Affected lints:** -* [`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 -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. - -**Default Value:** `["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "DirectX", "ECMAScript", "GPLv2", "GPLv3", "GitHub", "GitLab", "IPv4", "IPv6", "ClojureScript", "CoffeeScript", "JavaScript", "PureScript", "TypeScript", "WebAssembly", "NaN", "NaNs", "OAuth", "GraphQL", "OCaml", "OpenDNS", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenTelemetry", "WebGL", "WebGL2", "WebGPU", "TensorFlow", "TrueType", "iOS", "macOS", "FreeBSD", "TeX", "LaTeX", "BibTeX", "BibLaTeX", "MinGW", "CamelCase"]` - ---- -**Affected lints:** -* [`doc_markdown`](https://rust-lang.github.io/rust-clippy/master/index.html#doc_markdown) - - -## `too-many-arguments-threshold` -The maximum number of argument a function or method can have - -**Default Value:** `7` - ---- -**Affected lints:** -* [`too_many_arguments`](https://rust-lang.github.io/rust-clippy/master/index.html#too_many_arguments) - - -## `type-complexity-threshold` -The maximum complexity a type can have - -**Default Value:** `250` - ---- -**Affected lints:** -* [`type_complexity`](https://rust-lang.github.io/rust-clippy/master/index.html#type_complexity) - - -## `single-char-binding-names-threshold` -The maximum number of single char bindings a scope may have - -**Default Value:** `4` - ---- -**Affected lints:** -* [`many_single_char_names`](https://rust-lang.github.io/rust-clippy/master/index.html#many_single_char_names) - - -## `too-large-for-stack` -The maximum size of objects (in bytes) that will be linted. Larger objects are ok on the heap - -**Default Value:** `200` - ---- -**Affected lints:** -* [`boxed_local`](https://rust-lang.github.io/rust-clippy/master/index.html#boxed_local) -* [`useless_vec`](https://rust-lang.github.io/rust-clippy/master/index.html#useless_vec) - - -## `enum-variant-name-threshold` -The minimum number of enum variants for the lints about variant names to trigger - -**Default Value:** `3` - ---- -**Affected lints:** -* [`enum_variant_names`](https://rust-lang.github.io/rust-clippy/master/index.html#enum_variant_names) - - -## `struct-field-name-threshold` -The minimum number of struct fields for the lints about field names to trigger - -**Default Value:** `3` - ---- -**Affected lints:** -* [`struct_field_names`](https://rust-lang.github.io/rust-clippy/master/index.html#struct_field_names) - - -## `enum-variant-size-threshold` -The maximum size of an enum's variant to avoid box suggestion - -**Default Value:** `200` - ---- -**Affected lints:** -* [`large_enum_variant`](https://rust-lang.github.io/rust-clippy/master/index.html#large_enum_variant) - - -## `verbose-bit-mask-threshold` -The maximum allowed size of a bit mask before suggesting to use 'trailing_zeros' - -**Default Value:** `1` - ---- -**Affected lints:** -* [`verbose_bit_mask`](https://rust-lang.github.io/rust-clippy/master/index.html#verbose_bit_mask) - - -## `literal-representation-threshold` -The lower bound for linting decimal literals - -**Default Value:** `16384` - ---- -**Affected lints:** -* [`decimal_literal_representation`](https://rust-lang.github.io/rust-clippy/master/index.html#decimal_literal_representation) - - -## `trivial-copy-size-limit` -The maximum size (in bytes) to consider a `Copy` type for passing by value instead of by -reference. By default there is no limit - ---- -**Affected lints:** -* [`trivially_copy_pass_by_ref`](https://rust-lang.github.io/rust-clippy/master/index.html#trivially_copy_pass_by_ref) - - -## `pass-by-value-size-limit` -The minimum size (in bytes) to consider a type for passing by reference instead of by value. - -**Default Value:** `256` - ---- -**Affected lints:** -* [`large_types_passed_by_value`](https://rust-lang.github.io/rust-clippy/master/index.html#large_types_passed_by_value) - - -## `too-many-lines-threshold` -The maximum number of lines a function or method can have - -**Default Value:** `100` - ---- -**Affected lints:** -* [`too_many_lines`](https://rust-lang.github.io/rust-clippy/master/index.html#too_many_lines) - - -## `array-size-threshold` -The maximum allowed size for arrays on the stack - -**Default Value:** `512000` - ---- -**Affected lints:** -* [`large_stack_arrays`](https://rust-lang.github.io/rust-clippy/master/index.html#large_stack_arrays) -* [`large_const_arrays`](https://rust-lang.github.io/rust-clippy/master/index.html#large_const_arrays) - - -## `stack-size-threshold` -The maximum allowed stack size for functions in bytes - -**Default Value:** `512000` - ---- -**Affected lints:** -* [`large_stack_frames`](https://rust-lang.github.io/rust-clippy/master/index.html#large_stack_frames) - - -## `vec-box-size-threshold` -The size of the boxed type in bytes, where boxing in a `Vec` is allowed - -**Default Value:** `4096` - ---- -**Affected lints:** -* [`vec_box`](https://rust-lang.github.io/rust-clippy/master/index.html#vec_box) - - -## `max-trait-bounds` -The maximum number of bounds a trait can have to be linted - -**Default Value:** `3` - ---- -**Affected lints:** -* [`type_repetition_in_bounds`](https://rust-lang.github.io/rust-clippy/master/index.html#type_repetition_in_bounds) - - -## `max-struct-bools` -The maximum number of bool fields a struct can have - -**Default Value:** `3` - ---- -**Affected lints:** -* [`struct_excessive_bools`](https://rust-lang.github.io/rust-clippy/master/index.html#struct_excessive_bools) - - -## `max-fn-params-bools` -The maximum number of bool parameters a function can have - -**Default Value:** `3` - ---- -**Affected lints:** -* [`fn_params_excessive_bools`](https://rust-lang.github.io/rust-clippy/master/index.html#fn_params_excessive_bools) - - -## `warn-on-all-wildcard-imports` -Whether to allow certain wildcard imports (prelude, super in tests). - -**Default Value:** `false` - ---- -**Affected lints:** -* [`wildcard_imports`](https://rust-lang.github.io/rust-clippy/master/index.html#wildcard_imports) - - ## `disallowed-macros` The list of disallowed macros, written as fully qualified paths. @@ -431,6 +357,18 @@ The list of disallowed methods, written as fully qualified paths. * [`disallowed_methods`](https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_methods) +## `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 Value:** `["foo", "baz", "quux"]` + +--- +**Affected lints:** +* [`disallowed_names`](https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_names) + + ## `disallowed-types` The list of disallowed types, written as fully qualified paths. @@ -441,79 +379,18 @@ The list of disallowed types, written as fully qualified paths. * [`disallowed_types`](https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_types) -## `unreadable-literal-lint-fractions` -Should the fraction of a decimal be linted to include separators. +## `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 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. -**Default Value:** `true` +**Default Value:** `["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "DirectX", "ECMAScript", "GPLv2", "GPLv3", "GitHub", "GitLab", "IPv4", "IPv6", "ClojureScript", "CoffeeScript", "JavaScript", "PureScript", "TypeScript", "WebAssembly", "NaN", "NaNs", "OAuth", "GraphQL", "OCaml", "OpenDNS", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenTelemetry", "WebGL", "WebGL2", "WebGPU", "TensorFlow", "TrueType", "iOS", "macOS", "FreeBSD", "TeX", "LaTeX", "BibTeX", "BibLaTeX", "MinGW", "CamelCase"]` --- **Affected lints:** -* [`unreadable_literal`](https://rust-lang.github.io/rust-clippy/master/index.html#unreadable_literal) - - -## `upper-case-acronyms-aggressive` -Enables verbose mode. Triggers if there is more than one uppercase char next to each other - -**Default Value:** `false` - ---- -**Affected lints:** -* [`upper_case_acronyms`](https://rust-lang.github.io/rust-clippy/master/index.html#upper_case_acronyms) - - -## `matches-for-let-else` -Whether the matches should be considered by the lint, and whether there should -be filtering for common types. - -**Default Value:** `"WellKnownTypes"` - ---- -**Affected lints:** -* [`manual_let_else`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_let_else) - - -## `cargo-ignore-publish` -For internal testing only, ignores the current `publish` settings in the Cargo manifest. - -**Default Value:** `false` - ---- -**Affected lints:** -* [`cargo_common_metadata`](https://rust-lang.github.io/rust-clippy/master/index.html#cargo_common_metadata) - - -## `standard-macro-braces` -Enforce the named macros always use the braces specified. - -A `MacroMatcher` can be added like so `{ name = "macro_name", brace = "(" }`. If the macro -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:** `[]` - ---- -**Affected lints:** -* [`nonstandard_macro_braces`](https://rust-lang.github.io/rust-clippy/master/index.html#nonstandard_macro_braces) - - -## `enforced-import-renames` -The list of imports to always rename, a fully qualified path followed by the rename. - -**Default Value:** `[]` - ---- -**Affected lints:** -* [`missing_enforced_import_renames`](https://rust-lang.github.io/rust-clippy/master/index.html#missing_enforced_import_renames) - - -## `allowed-scripts` -The list of unicode scripts allowed to be used in the scope. - -**Default Value:** `["Latin"]` - ---- -**Affected lints:** -* [`disallowed_script_idents`](https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_script_idents) +* [`doc_markdown`](https://rust-lang.github.io/rust-clippy/master/index.html#doc_markdown) ## `enable-raw-pointer-heuristic-for-send` @@ -526,259 +403,6 @@ Whether to apply the raw pointer heuristic to determine if a type is `Send`. * [`non_send_fields_in_send_ty`](https://rust-lang.github.io/rust-clippy/master/index.html#non_send_fields_in_send_ty) -## `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 are necessary, the lint is suppressed. -For example, `[_, _, _, e, ..]` is a slice pattern with 4 elements. - -**Default Value:** `3` - ---- -**Affected lints:** -* [`index_refutable_slice`](https://rust-lang.github.io/rust-clippy/master/index.html#index_refutable_slice) - - -## `await-holding-invalid-types` - - -**Default Value:** `[]` - ---- -**Affected lints:** -* [`await_holding_invalid_type`](https://rust-lang.github.io/rust-clippy/master/index.html#await_holding_invalid_type) - - -## `max-include-file-size` -The maximum size of a file included via `include_bytes!()` or `include_str!()`, in bytes - -**Default Value:** `1000000` - ---- -**Affected lints:** -* [`large_include_file`](https://rust-lang.github.io/rust-clippy/master/index.html#large_include_file) - - -## `allow-expect-in-tests` -Whether `expect` should be allowed in test functions or `#[cfg(test)]` - -**Default Value:** `false` - ---- -**Affected lints:** -* [`expect_used`](https://rust-lang.github.io/rust-clippy/master/index.html#expect_used) - - -## `allow-unwrap-in-tests` -Whether `unwrap` should be allowed in test functions or `#[cfg(test)]` - -**Default Value:** `false` - ---- -**Affected lints:** -* [`unwrap_used`](https://rust-lang.github.io/rust-clippy/master/index.html#unwrap_used) - - -## `allow-dbg-in-tests` -Whether `dbg!` should be allowed in test functions or `#[cfg(test)]` - -**Default Value:** `false` - ---- -**Affected lints:** -* [`dbg_macro`](https://rust-lang.github.io/rust-clippy/master/index.html#dbg_macro) - - -## `allow-print-in-tests` -Whether print macros (ex. `println!`) should be allowed in test functions or `#[cfg(test)]` - -**Default Value:** `false` - ---- -**Affected lints:** -* [`print_stdout`](https://rust-lang.github.io/rust-clippy/master/index.html#print_stdout) -* [`print_stderr`](https://rust-lang.github.io/rust-clippy/master/index.html#print_stderr) - - -## `large-error-threshold` -The maximum size of the `Err`-variant in a `Result` returned from a function - -**Default Value:** `128` - ---- -**Affected lints:** -* [`result_large_err`](https://rust-lang.github.io/rust-clippy/master/index.html#result_large_err) - - -## `ignore-interior-mutability` -A list of paths to types that should be treated like `Arc`, i.e. ignored but -for the generic parameters for determining interior mutability - -**Default Value:** `["bytes::Bytes"]` - ---- -**Affected lints:** -* [`mutable_key_type`](https://rust-lang.github.io/rust-clippy/master/index.html#mutable_key_type) -* [`ifs_same_cond`](https://rust-lang.github.io/rust-clippy/master/index.html#ifs_same_cond) - - -## `allow-mixed-uninlined-format-args` -Whether to allow mixed uninlined format args, e.g. `format!("{} {}", a, foo.bar)` - -**Default Value:** `true` - ---- -**Affected lints:** -* [`uninlined_format_args`](https://rust-lang.github.io/rust-clippy/master/index.html#uninlined_format_args) - - -## `suppress-restriction-lint-in-const` -Whether to suppress a restriction lint in constant code. In same -cases the restructured operation might not be unavoidable, as the -suggested counterparts are unavailable in constant code. This -configuration will cause restriction lints to trigger even -if no suggestion can be made. - -**Default Value:** `false` - ---- -**Affected lints:** -* [`indexing_slicing`](https://rust-lang.github.io/rust-clippy/master/index.html#indexing_slicing) - - -## `missing-docs-in-crate-items` -Whether to **only** check for missing documentation in items visible within the current -crate. For example, `pub(crate)` items. - -**Default Value:** `false` - ---- -**Affected lints:** -* [`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` - ---- -**Affected lints:** -* [`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` - ---- -**Affected lints:** -* [`unnecessary_box_returns`](https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_box_returns) - - -## `allow-private-module-inception` -Whether to allow module inception if it's not public. - -**Default Value:** `false` - ---- -**Affected lints:** -* [`module_inception`](https://rust-lang.github.io/rust-clippy/master/index.html#module_inception) - - -## `allowed-idents-below-min-chars` -Allowed names below the minimum allowed characters. 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 Value:** `["j", "z", "i", "y", "n", "x", "w"]` - ---- -**Affected lints:** -* [`min_ident_chars`](https://rust-lang.github.io/rust-clippy/master/index.html#min_ident_chars) - - -## `min-ident-chars-threshold` -Minimum chars an ident can have, anything below or equal to this will be linted. - -**Default Value:** `1` - ---- -**Affected lints:** -* [`min_ident_chars`](https://rust-lang.github.io/rust-clippy/master/index.html#min_ident_chars) - - -## `accept-comment-above-statement` -Whether to accept a safety comment to be placed above the statement containing the `unsafe` block - -**Default Value:** `true` - ---- -**Affected lints:** -* [`undocumented_unsafe_blocks`](https://rust-lang.github.io/rust-clippy/master/index.html#undocumented_unsafe_blocks) - - -## `accept-comment-above-attributes` -Whether to accept a safety comment to be placed above the attributes for the `unsafe` block - -**Default Value:** `true` - ---- -**Affected lints:** -* [`undocumented_unsafe_blocks`](https://rust-lang.github.io/rust-clippy/master/index.html#undocumented_unsafe_blocks) - - -## `allow-one-hash-in-raw-strings` -Whether to allow `r#""#` when `r""` can be used - -**Default Value:** `false` - ---- -**Affected lints:** -* [`unnecessary_raw_string_hashes`](https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_raw_string_hashes) - - -## `absolute-paths-max-segments` -The maximum number of segments a path can have before being linted, anything above this will -be linted. - -**Default Value:** `2` - ---- -**Affected lints:** -* [`absolute_paths`](https://rust-lang.github.io/rust-clippy/master/index.html#absolute_paths) - - -## `absolute-paths-allowed-crates` -Which crates to allow absolute paths from - -**Default Value:** `[]` - ---- -**Affected lints:** -* [`absolute_paths`](https://rust-lang.github.io/rust-clippy/master/index.html#absolute_paths) - - -## `allowed-dotfiles` -Additional dotfiles (files or directories starting with a dot) to allow - -**Default Value:** `[]` - ---- -**Affected lints:** -* [`path_ends_with_ext`](https://rust-lang.github.io/rust-clippy/master/index.html#path_ends_with_ext) - - -## `allowed-duplicate-crates` -A list of crate names to allow duplicates of - -**Default Value:** `[]` - ---- -**Affected lints:** -* [`multiple_crate_versions`](https://rust-lang.github.io/rust-clippy/master/index.html#multiple_crate_versions) - - ## `enforce-iter-loop-reborrow` Whether to recommend using implicit into iter for reborrowed values. @@ -805,17 +429,237 @@ for _ in &mut *rmvec {} * [`explicit_iter_loop`](https://rust-lang.github.io/rust-clippy/master/index.html#explicit_iter_loop) -## `check-private-items` -Whether to also run the listed lints on private items. +## `enforced-import-renames` +The list of imports to always rename, a fully qualified path followed by the rename. + +**Default Value:** `[]` + +--- +**Affected lints:** +* [`missing_enforced_import_renames`](https://rust-lang.github.io/rust-clippy/master/index.html#missing_enforced_import_renames) + + +## `enum-variant-name-threshold` +The minimum number of enum variants for the lints about variant names to trigger + +**Default Value:** `3` + +--- +**Affected lints:** +* [`enum_variant_names`](https://rust-lang.github.io/rust-clippy/master/index.html#enum_variant_names) + + +## `enum-variant-size-threshold` +The maximum size of an enum's variant to avoid box suggestion + +**Default Value:** `200` + +--- +**Affected lints:** +* [`large_enum_variant`](https://rust-lang.github.io/rust-clippy/master/index.html#large_enum_variant) + + +## `excessive-nesting-threshold` +The maximum amount of nesting a block can reside in + +**Default Value:** `0` + +--- +**Affected lints:** +* [`excessive_nesting`](https://rust-lang.github.io/rust-clippy/master/index.html#excessive_nesting) + + +## `future-size-threshold` +The maximum byte size a `Future` can have, before it triggers the `clippy::large_futures` lint + +**Default Value:** `16384` + +--- +**Affected lints:** +* [`large_futures`](https://rust-lang.github.io/rust-clippy/master/index.html#large_futures) + + +## `ignore-interior-mutability` +A list of paths to types that should be treated like `Arc`, i.e. ignored but +for the generic parameters for determining interior mutability + +**Default Value:** `["bytes::Bytes"]` + +--- +**Affected lints:** +* [`ifs_same_cond`](https://rust-lang.github.io/rust-clippy/master/index.html#ifs_same_cond) +* [`mutable_key_type`](https://rust-lang.github.io/rust-clippy/master/index.html#mutable_key_type) + + +## `large-error-threshold` +The maximum size of the `Err`-variant in a `Result` returned from a function + +**Default Value:** `128` + +--- +**Affected lints:** +* [`result_large_err`](https://rust-lang.github.io/rust-clippy/master/index.html#result_large_err) + + +## `literal-representation-threshold` +The lower bound for linting decimal literals + +**Default Value:** `16384` + +--- +**Affected lints:** +* [`decimal_literal_representation`](https://rust-lang.github.io/rust-clippy/master/index.html#decimal_literal_representation) + + +## `matches-for-let-else` +Whether the matches should be considered by the lint, and whether there should +be filtering for common types. + +**Default Value:** `"WellKnownTypes"` + +--- +**Affected lints:** +* [`manual_let_else`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_let_else) + + +## `max-fn-params-bools` +The maximum number of bool parameters a function can have + +**Default Value:** `3` + +--- +**Affected lints:** +* [`fn_params_excessive_bools`](https://rust-lang.github.io/rust-clippy/master/index.html#fn_params_excessive_bools) + + +## `max-include-file-size` +The maximum size of a file included via `include_bytes!()` or `include_str!()`, in bytes + +**Default Value:** `1000000` + +--- +**Affected lints:** +* [`large_include_file`](https://rust-lang.github.io/rust-clippy/master/index.html#large_include_file) + + +## `max-struct-bools` +The maximum number of bool fields a struct can have + +**Default Value:** `3` + +--- +**Affected lints:** +* [`struct_excessive_bools`](https://rust-lang.github.io/rust-clippy/master/index.html#struct_excessive_bools) + + +## `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 are necessary, the lint is suppressed. +For example, `[_, _, _, e, ..]` is a slice pattern with 4 elements. + +**Default Value:** `3` + +--- +**Affected lints:** +* [`index_refutable_slice`](https://rust-lang.github.io/rust-clippy/master/index.html#index_refutable_slice) + + +## `max-trait-bounds` +The maximum number of bounds a trait can have to be linted + +**Default Value:** `3` + +--- +**Affected lints:** +* [`type_repetition_in_bounds`](https://rust-lang.github.io/rust-clippy/master/index.html#type_repetition_in_bounds) + + +## `min-ident-chars-threshold` +Minimum chars an ident can have, anything below or equal to this will be linted. + +**Default Value:** `1` + +--- +**Affected lints:** +* [`min_ident_chars`](https://rust-lang.github.io/rust-clippy/master/index.html#min_ident_chars) + + +## `missing-docs-in-crate-items` +Whether to **only** check for missing documentation in items visible within the current +crate. For example, `pub(crate)` items. **Default Value:** `false` --- **Affected lints:** -* [`missing_safety_doc`](https://rust-lang.github.io/rust-clippy/master/index.html#missing_safety_doc) -* [`unnecessary_safety_doc`](https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_safety_doc) -* [`missing_panics_doc`](https://rust-lang.github.io/rust-clippy/master/index.html#missing_panics_doc) -* [`missing_errors_doc`](https://rust-lang.github.io/rust-clippy/master/index.html#missing_errors_doc) +* [`missing_docs_in_private_items`](https://rust-lang.github.io/rust-clippy/master/index.html#missing_docs_in_private_items) + + +## `msrv` +The minimum rust version that the project supports. Defaults to the `rust-version` field in `Cargo.toml` + +--- +**Affected lints:** +* [`almost_complete_range`](https://rust-lang.github.io/rust-clippy/master/index.html#almost_complete_range) +* [`approx_constant`](https://rust-lang.github.io/rust-clippy/master/index.html#approx_constant) +* [`borrow_as_ptr`](https://rust-lang.github.io/rust-clippy/master/index.html#borrow_as_ptr) +* [`cast_abs_to_unsigned`](https://rust-lang.github.io/rust-clippy/master/index.html#cast_abs_to_unsigned) +* [`checked_conversions`](https://rust-lang.github.io/rust-clippy/master/index.html#checked_conversions) +* [`cloned_instead_of_copied`](https://rust-lang.github.io/rust-clippy/master/index.html#cloned_instead_of_copied) +* [`collapsible_str_replace`](https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_str_replace) +* [`deprecated_cfg_attr`](https://rust-lang.github.io/rust-clippy/master/index.html#deprecated_cfg_attr) +* [`derivable_impls`](https://rust-lang.github.io/rust-clippy/master/index.html#derivable_impls) +* [`err_expect`](https://rust-lang.github.io/rust-clippy/master/index.html#err_expect) +* [`filter_map_next`](https://rust-lang.github.io/rust-clippy/master/index.html#filter_map_next) +* [`from_over_into`](https://rust-lang.github.io/rust-clippy/master/index.html#from_over_into) +* [`if_then_some_else_none`](https://rust-lang.github.io/rust-clippy/master/index.html#if_then_some_else_none) +* [`index_refutable_slice`](https://rust-lang.github.io/rust-clippy/master/index.html#index_refutable_slice) +* [`iter_kv_map`](https://rust-lang.github.io/rust-clippy/master/index.html#iter_kv_map) +* [`manual_bits`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_bits) +* [`manual_c_str_literals`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_c_str_literals) +* [`manual_clamp`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_clamp) +* [`manual_hash_one`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_hash_one) +* [`manual_is_ascii_check`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_ascii_check) +* [`manual_let_else`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_let_else) +* [`manual_non_exhaustive`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_non_exhaustive) +* [`manual_range_contains`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_range_contains) +* [`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_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_strip`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_strip) +* [`manual_try_fold`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_try_fold) +* [`map_clone`](https://rust-lang.github.io/rust-clippy/master/index.html#map_clone) +* [`map_unwrap_or`](https://rust-lang.github.io/rust-clippy/master/index.html#map_unwrap_or) +* [`match_like_matches_macro`](https://rust-lang.github.io/rust-clippy/master/index.html#match_like_matches_macro) +* [`mem_replace_with_default`](https://rust-lang.github.io/rust-clippy/master/index.html#mem_replace_with_default) +* [`missing_const_for_fn`](https://rust-lang.github.io/rust-clippy/master/index.html#missing_const_for_fn) +* [`needless_borrow`](https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow) +* [`option_as_ref_deref`](https://rust-lang.github.io/rust-clippy/master/index.html#option_as_ref_deref) +* [`option_map_unwrap_or`](https://rust-lang.github.io/rust-clippy/master/index.html#option_map_unwrap_or) +* [`ptr_as_ptr`](https://rust-lang.github.io/rust-clippy/master/index.html#ptr_as_ptr) +* [`redundant_field_names`](https://rust-lang.github.io/rust-clippy/master/index.html#redundant_field_names) +* [`redundant_static_lifetimes`](https://rust-lang.github.io/rust-clippy/master/index.html#redundant_static_lifetimes) +* [`seek_from_current`](https://rust-lang.github.io/rust-clippy/master/index.html#seek_from_current) +* [`seek_rewind`](https://rust-lang.github.io/rust-clippy/master/index.html#seek_rewind) +* [`transmute_ptr_to_ref`](https://rust-lang.github.io/rust-clippy/master/index.html#transmute_ptr_to_ref) +* [`tuple_array_conversions`](https://rust-lang.github.io/rust-clippy/master/index.html#tuple_array_conversions) +* [`type_repetition_in_bounds`](https://rust-lang.github.io/rust-clippy/master/index.html#type_repetition_in_bounds) +* [`unchecked_duration_subtraction`](https://rust-lang.github.io/rust-clippy/master/index.html#unchecked_duration_subtraction) +* [`uninlined_format_args`](https://rust-lang.github.io/rust-clippy/master/index.html#uninlined_format_args) +* [`unnecessary_lazy_evaluations`](https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_lazy_evaluations) +* [`unnested_or_patterns`](https://rust-lang.github.io/rust-clippy/master/index.html#unnested_or_patterns) +* [`use_self`](https://rust-lang.github.io/rust-clippy/master/index.html#use_self) + + +## `pass-by-value-size-limit` +The minimum size (in bytes) to consider a type for passing by reference instead of by value. + +**Default Value:** `256` + +--- +**Affected lints:** +* [`large_types_passed_by_value`](https://rust-lang.github.io/rust-clippy/master/index.html#large_types_passed_by_value) ## `pub-underscore-fields-behavior` @@ -829,32 +673,188 @@ exported visibility, or whether they are marked as "pub". * [`pub_underscore_fields`](https://rust-lang.github.io/rust-clippy/master/index.html#pub_underscore_fields) -## `allow-comparison-to-zero` -Don't lint when comparing the result of a modulo operation to zero. +## `semicolon-inside-block-ignore-singleline` +Whether to lint only if it's multiline. + +**Default Value:** `false` + +--- +**Affected lints:** +* [`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` + +--- +**Affected lints:** +* [`semicolon_outside_block`](https://rust-lang.github.io/rust-clippy/master/index.html#semicolon_outside_block) + + +## `single-char-binding-names-threshold` +The maximum number of single char bindings a scope may have + +**Default Value:** `4` + +--- +**Affected lints:** +* [`many_single_char_names`](https://rust-lang.github.io/rust-clippy/master/index.html#many_single_char_names) + + +## `stack-size-threshold` +The maximum allowed stack size for functions in bytes + +**Default Value:** `512000` + +--- +**Affected lints:** +* [`large_stack_frames`](https://rust-lang.github.io/rust-clippy/master/index.html#large_stack_frames) + + +## `standard-macro-braces` +Enforce the named macros always use the braces specified. + +A `MacroMatcher` can be added like so `{ name = "macro_name", brace = "(" }`. If the macro +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:** `[]` + +--- +**Affected lints:** +* [`nonstandard_macro_braces`](https://rust-lang.github.io/rust-clippy/master/index.html#nonstandard_macro_braces) + + +## `struct-field-name-threshold` +The minimum number of struct fields for the lints about field names to trigger + +**Default Value:** `3` + +--- +**Affected lints:** +* [`struct_field_names`](https://rust-lang.github.io/rust-clippy/master/index.html#struct_field_names) + + +## `suppress-restriction-lint-in-const` +Whether to suppress a restriction lint in constant code. In same +cases the restructured operation might not be unavoidable, as the +suggested counterparts are unavailable in constant code. This +configuration will cause restriction lints to trigger even +if no suggestion can be made. + +**Default Value:** `false` + +--- +**Affected lints:** +* [`indexing_slicing`](https://rust-lang.github.io/rust-clippy/master/index.html#indexing_slicing) + + +## `too-large-for-stack` +The maximum size of objects (in bytes) that will be linted. Larger objects are ok on the heap + +**Default Value:** `200` + +--- +**Affected lints:** +* [`boxed_local`](https://rust-lang.github.io/rust-clippy/master/index.html#boxed_local) +* [`useless_vec`](https://rust-lang.github.io/rust-clippy/master/index.html#useless_vec) + + +## `too-many-arguments-threshold` +The maximum number of argument a function or method can have + +**Default Value:** `7` + +--- +**Affected lints:** +* [`too_many_arguments`](https://rust-lang.github.io/rust-clippy/master/index.html#too_many_arguments) + + +## `too-many-lines-threshold` +The maximum number of lines a function or method can have + +**Default Value:** `100` + +--- +**Affected lints:** +* [`too_many_lines`](https://rust-lang.github.io/rust-clippy/master/index.html#too_many_lines) + + +## `trivial-copy-size-limit` +The maximum size (in bytes) to consider a `Copy` type for passing by value instead of by +reference. By default there is no limit + +--- +**Affected lints:** +* [`trivially_copy_pass_by_ref`](https://rust-lang.github.io/rust-clippy/master/index.html#trivially_copy_pass_by_ref) + + +## `type-complexity-threshold` +The maximum complexity a type can have + +**Default Value:** `250` + +--- +**Affected lints:** +* [`type_complexity`](https://rust-lang.github.io/rust-clippy/master/index.html#type_complexity) + + +## `unnecessary-box-size` +The byte size a `T` in `Box` can have, below which it triggers the `clippy::unnecessary_box` lint + +**Default Value:** `128` + +--- +**Affected lints:** +* [`unnecessary_box_returns`](https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_box_returns) + + +## `unreadable-literal-lint-fractions` +Should the fraction of a decimal be linted to include separators. **Default Value:** `true` --- **Affected lints:** -* [`modulo_arithmetic`](https://rust-lang.github.io/rust-clippy/master/index.html#modulo_arithmetic) +* [`unreadable_literal`](https://rust-lang.github.io/rust-clippy/master/index.html#unreadable_literal) -## `allowed-wildcard-imports` -List of path segments allowed to have wildcard imports. +## `upper-case-acronyms-aggressive` +Enables verbose mode. Triggers if there is more than one uppercase char next to each other -#### Example +**Default Value:** `false` -```toml -allowed-wildcard-imports = [ "utils", "common" ] -``` +--- +**Affected lints:** +* [`upper_case_acronyms`](https://rust-lang.github.io/rust-clippy/master/index.html#upper_case_acronyms) -#### Noteworthy -1. This configuration has no effects if used with `warn_on_all_wildcard_imports = true`. -2. Paths with any segment that containing the word 'prelude' -are already allowed by default. +## `vec-box-size-threshold` +The size of the boxed type in bytes, where boxing in a `Vec` is allowed -**Default Value:** `[]` +**Default Value:** `4096` + +--- +**Affected lints:** +* [`vec_box`](https://rust-lang.github.io/rust-clippy/master/index.html#vec_box) + + +## `verbose-bit-mask-threshold` +The maximum allowed size of a bit mask before suggesting to use 'trailing_zeros' + +**Default Value:** `1` + +--- +**Affected lints:** +* [`verbose_bit_mask`](https://rust-lang.github.io/rust-clippy/master/index.html#verbose_bit_mask) + + +## `warn-on-all-wildcard-imports` +Whether to allow certain wildcard imports (prelude, super in tests). + +**Default Value:** `false` --- **Affected lints:** diff --git a/clippy_config/src/conf.rs b/clippy_config/src/conf.rs index b781259ad96..673b6328b39 100644 --- a/clippy_config/src/conf.rs +++ b/clippy_config/src/conf.rs @@ -193,7 +193,7 @@ fn visit_map(self, mut map: V) -> Result where V: MapA } pub fn get_configuration_metadata() -> Vec { - vec![ + let mut sorted = vec![ $( { let deprecation_reason = wrap_option!($($dep)?); @@ -206,7 +206,9 @@ pub fn get_configuration_metadata() -> Vec { ) }, )+ - ] + ]; + sorted.sort_by(|a, b| a.name.cmp(&b.name)); + sorted } }; } diff --git a/clippy_config/src/lib.rs b/clippy_config/src/lib.rs index 3d5002f1780..01e2aa6e0a6 100644 --- a/clippy_config/src/lib.rs +++ b/clippy_config/src/lib.rs @@ -5,7 +5,7 @@ clippy::must_use_candidate, clippy::missing_panics_doc, rustc::diagnostic_outside_of_impl, - rustc::untranslatable_diagnostic, + rustc::untranslatable_diagnostic )] extern crate rustc_ast; diff --git a/clippy_config/src/metadata.rs b/clippy_config/src/metadata.rs index 3ba2796e18d..400887185e8 100644 --- a/clippy_config/src/metadata.rs +++ b/clippy_config/src/metadata.rs @@ -26,9 +26,11 @@ pub fn new( doc_comment: &'static str, deprecation_reason: Option<&'static str>, ) -> Self { - let (lints, doc) = parse_config_field_doc(doc_comment) + let (mut lints, doc) = parse_config_field_doc(doc_comment) .unwrap_or_else(|| (vec![], "[ERROR] MALFORMED DOC COMMENT".to_string())); + lints.sort(); + Self { name: to_kebab(name), lints, diff --git a/clippy_config/src/msrvs.rs b/clippy_config/src/msrvs.rs index f4389db627d..a8a32f7ed20 100644 --- a/clippy_config/src/msrvs.rs +++ b/clippy_config/src/msrvs.rs @@ -24,6 +24,7 @@ macro_rules! msrv_aliases { 1,68,0 { PATH_MAIN_SEPARATOR_STR } 1,65,0 { LET_ELSE, POINTER_CAST_CONSTNESS } 1,62,0 { BOOL_THEN_SOME, DEFAULT_ENUM_ATTRIBUTE } + 1,59,0 { THREAD_LOCAL_INITIALIZER_CAN_BE_MADE_CONST } 1,58,0 { FORMAT_ARGS_CAPTURE, PATTERN_TRAIT_CHAR_ARRAY } 1,55,0 { SEEK_REWIND } 1,54,0 { INTO_KEYS } diff --git a/clippy_lints/src/assigning_clones.rs b/clippy_lints/src/assigning_clones.rs new file mode 100644 index 00000000000..b1c552c7a8d --- /dev/null +++ b/clippy_lints/src/assigning_clones.rs @@ -0,0 +1,322 @@ +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::macros::HirNode; +use clippy_utils::sugg::Sugg; +use clippy_utils::{is_trait_method, path_to_local}; +use rustc_errors::Applicability; +use rustc_hir::{self as hir, Expr, ExprKind, Node}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::{self, Instance, Mutability}; +use rustc_session::declare_lint_pass; +use rustc_span::def_id::DefId; +use rustc_span::symbol::sym; +use rustc_span::ExpnKind; + +declare_clippy_lint! { + /// ### What it does + /// Checks for code like `foo = bar.clone();` + /// + /// ### Why is this bad? + /// Custom `Clone::clone_from()` or `ToOwned::clone_into` implementations allow the objects + /// to share resources and therefore avoid allocations. + /// + /// ### Example + /// ```rust + /// struct Thing; + /// + /// impl Clone for Thing { + /// fn clone(&self) -> Self { todo!() } + /// fn clone_from(&mut self, other: &Self) { todo!() } + /// } + /// + /// pub fn assign_to_ref(a: &mut Thing, b: Thing) { + /// *a = b.clone(); + /// } + /// ``` + /// Use instead: + /// ```rust + /// struct Thing; + /// impl Clone for Thing { + /// fn clone(&self) -> Self { todo!() } + /// fn clone_from(&mut self, other: &Self) { todo!() } + /// } + /// + /// pub fn assign_to_ref(a: &mut Thing, b: Thing) { + /// a.clone_from(&b); + /// } + /// ``` + #[clippy::version = "1.77.0"] + pub ASSIGNING_CLONES, + perf, + "assigning the result of cloning may be inefficient" +} +declare_lint_pass!(AssigningClones => [ASSIGNING_CLONES]); + +impl<'tcx> LateLintPass<'tcx> for AssigningClones { + fn check_expr(&mut self, cx: &LateContext<'tcx>, assign_expr: &'tcx hir::Expr<'_>) { + // Do not fire the lint in macros + let expn_data = assign_expr.span().ctxt().outer_expn_data(); + match expn_data.kind { + ExpnKind::AstPass(_) | ExpnKind::Desugaring(_) | ExpnKind::Macro(..) => return, + ExpnKind::Root => {}, + } + + let ExprKind::Assign(lhs, rhs, _span) = assign_expr.kind else { + return; + }; + + let Some(call) = extract_call(cx, rhs) else { + return; + }; + + if is_ok_to_suggest(cx, lhs, &call) { + suggest(cx, assign_expr, lhs, &call); + } + } +} + +// Try to resolve the call to `Clone::clone` or `ToOwned::to_owned`. +fn extract_call<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option> { + let fn_def_id = clippy_utils::fn_def_id(cx, expr)?; + + // Fast paths to only check method calls without arguments or function calls with a single argument + let (target, kind, resolved_method) = match expr.kind { + ExprKind::MethodCall(path, receiver, [], _span) => { + let args = cx.typeck_results().node_args(expr.hir_id); + + // If we could not resolve the method, don't apply the lint + let Ok(Some(resolved_method)) = Instance::resolve(cx.tcx, cx.param_env, fn_def_id, args) else { + return None; + }; + if is_trait_method(cx, expr, sym::Clone) && path.ident.name == sym::clone { + (TargetTrait::Clone, CallKind::MethodCall { receiver }, resolved_method) + } else if is_trait_method(cx, expr, sym::ToOwned) && path.ident.name.as_str() == "to_owned" { + (TargetTrait::ToOwned, CallKind::MethodCall { receiver }, resolved_method) + } else { + return None; + } + }, + ExprKind::Call(function, [arg]) => { + let kind = cx.typeck_results().node_type(function.hir_id).kind(); + + // If we could not resolve the method, don't apply the lint + let Ok(Some(resolved_method)) = (match kind { + ty::FnDef(_, args) => Instance::resolve(cx.tcx, cx.param_env, fn_def_id, args), + _ => Ok(None), + }) else { + return None; + }; + if cx.tcx.is_diagnostic_item(sym::to_owned_method, fn_def_id) { + ( + TargetTrait::ToOwned, + CallKind::FunctionCall { self_arg: arg }, + resolved_method, + ) + } else if let Some(trait_did) = cx.tcx.trait_of_item(fn_def_id) + && cx.tcx.is_diagnostic_item(sym::Clone, trait_did) + { + ( + TargetTrait::Clone, + CallKind::FunctionCall { self_arg: arg }, + resolved_method, + ) + } else { + return None; + } + }, + _ => return None, + }; + + Some(CallCandidate { + target, + kind, + method_def_id: resolved_method.def_id(), + }) +} + +// Return true if we find that the called method has a custom implementation and isn't derived or +// provided by default by the corresponding trait. +fn is_ok_to_suggest<'tcx>(cx: &LateContext<'tcx>, lhs: &Expr<'tcx>, call: &CallCandidate<'tcx>) -> bool { + // If the left-hand side is a local variable, it might be uninitialized at this point. + // In that case we do not want to suggest the lint. + if let Some(local) = path_to_local(lhs) { + // TODO: This check currently bails if the local variable has no initializer. + // That is overly conservative - the lint should fire even if there was no initializer, + // but the variable has been initialized before `lhs` was evaluated. + if let Some(Node::Local(local)) = cx.tcx.hir().parent_id_iter(local).next().map(|p| cx.tcx.hir_node(p)) + && local.init.is_none() + { + return false; + } + } + + let Some(impl_block) = cx.tcx.impl_of_method(call.method_def_id) else { + return false; + }; + + // If the method implementation comes from #[derive(Clone)], then don't suggest the lint. + // Automatically generated Clone impls do not currently override `clone_from`. + // See e.g. https://github.com/rust-lang/rust/pull/98445#issuecomment-1190681305 for more details. + if cx.tcx.is_builtin_derived(impl_block) { + return false; + } + + // Find the function for which we want to check that it is implemented. + let provided_fn = match call.target { + TargetTrait::Clone => cx.tcx.get_diagnostic_item(sym::Clone).and_then(|clone| { + cx.tcx + .provided_trait_methods(clone) + .find(|item| item.name == sym::clone_from) + }), + TargetTrait::ToOwned => cx.tcx.get_diagnostic_item(sym::ToOwned).and_then(|to_owned| { + cx.tcx + .provided_trait_methods(to_owned) + .find(|item| item.name.as_str() == "clone_into") + }), + }; + let Some(provided_fn) = provided_fn else { + return false; + }; + + // Now take a look if the impl block defines an implementation for the method that we're interested + // in. If not, then we're using a default implementation, which is not interesting, so we will + // not suggest the lint. + let implemented_fns = cx.tcx.impl_item_implementor_ids(impl_block); + implemented_fns.contains_key(&provided_fn.def_id) +} + +fn suggest<'tcx>( + cx: &LateContext<'tcx>, + assign_expr: &hir::Expr<'tcx>, + lhs: &hir::Expr<'tcx>, + call: &CallCandidate<'tcx>, +) { + span_lint_and_then(cx, ASSIGNING_CLONES, assign_expr.span, call.message(), |diag| { + let mut applicability = Applicability::MachineApplicable; + + diag.span_suggestion( + assign_expr.span, + call.suggestion_msg(), + call.suggested_replacement(cx, lhs, &mut applicability), + applicability, + ); + }); +} + +#[derive(Copy, Clone, Debug)] +enum CallKind<'tcx> { + MethodCall { receiver: &'tcx Expr<'tcx> }, + FunctionCall { self_arg: &'tcx Expr<'tcx> }, +} + +#[derive(Copy, Clone, Debug)] +enum TargetTrait { + Clone, + ToOwned, +} + +#[derive(Debug)] +struct CallCandidate<'tcx> { + target: TargetTrait, + kind: CallKind<'tcx>, + // DefId of the called method from an impl block that implements the target trait + method_def_id: DefId, +} + +impl<'tcx> CallCandidate<'tcx> { + #[inline] + fn message(&self) -> &'static str { + match self.target { + TargetTrait::Clone => "assigning the result of `Clone::clone()` may be inefficient", + TargetTrait::ToOwned => "assigning the result of `ToOwned::to_owned()` may be inefficient", + } + } + + #[inline] + fn suggestion_msg(&self) -> &'static str { + match self.target { + TargetTrait::Clone => "use `clone_from()`", + TargetTrait::ToOwned => "use `clone_into()`", + } + } + + fn suggested_replacement( + &self, + cx: &LateContext<'tcx>, + lhs: &hir::Expr<'tcx>, + applicability: &mut Applicability, + ) -> String { + match self.target { + TargetTrait::Clone => { + match self.kind { + CallKind::MethodCall { receiver } => { + let receiver_sugg = if let ExprKind::Unary(hir::UnOp::Deref, ref_expr) = lhs.kind { + // `*lhs = self_expr.clone();` -> `lhs.clone_from(self_expr)` + Sugg::hir_with_applicability(cx, ref_expr, "_", applicability) + } else { + // `lhs = self_expr.clone();` -> `lhs.clone_from(self_expr)` + Sugg::hir_with_applicability(cx, lhs, "_", applicability) + } + .maybe_par(); + + // Determine whether we need to reference the argument to clone_from(). + let clone_receiver_type = cx.typeck_results().expr_ty(receiver); + let clone_receiver_adj_type = cx.typeck_results().expr_ty_adjusted(receiver); + let mut arg_sugg = Sugg::hir_with_applicability(cx, receiver, "_", applicability); + if clone_receiver_type != clone_receiver_adj_type { + // The receiver may have been a value type, so we need to add an `&` to + // be sure the argument to clone_from will be a reference. + arg_sugg = arg_sugg.addr(); + }; + + format!("{receiver_sugg}.clone_from({arg_sugg})") + }, + CallKind::FunctionCall { self_arg, .. } => { + let self_sugg = if let ExprKind::Unary(hir::UnOp::Deref, ref_expr) = lhs.kind { + // `*lhs = Clone::clone(self_expr);` -> `Clone::clone_from(lhs, self_expr)` + Sugg::hir_with_applicability(cx, ref_expr, "_", applicability) + } else { + // `lhs = Clone::clone(self_expr);` -> `Clone::clone_from(&mut lhs, self_expr)` + Sugg::hir_with_applicability(cx, lhs, "_", applicability).mut_addr() + }; + // The RHS had to be exactly correct before the call, there is no auto-deref for function calls. + let rhs_sugg = Sugg::hir_with_applicability(cx, self_arg, "_", applicability); + + format!("Clone::clone_from({self_sugg}, {rhs_sugg})") + }, + } + }, + TargetTrait::ToOwned => { + let rhs_sugg = if let ExprKind::Unary(hir::UnOp::Deref, ref_expr) = lhs.kind { + // `*lhs = rhs.to_owned()` -> `rhs.clone_into(lhs)` + // `*lhs = ToOwned::to_owned(rhs)` -> `ToOwned::clone_into(rhs, lhs)` + let sugg = Sugg::hir_with_applicability(cx, ref_expr, "_", applicability).maybe_par(); + let inner_type = cx.typeck_results().expr_ty(ref_expr); + // If after unwrapping the dereference, the type is not a mutable reference, we add &mut to make it + // deref to a mutable reference. + if matches!(inner_type.kind(), ty::Ref(_, _, Mutability::Mut)) { + sugg + } else { + sugg.mut_addr() + } + } else { + // `lhs = rhs.to_owned()` -> `rhs.clone_into(&mut lhs)` + // `lhs = ToOwned::to_owned(rhs)` -> `ToOwned::clone_into(rhs, &mut lhs)` + Sugg::hir_with_applicability(cx, lhs, "_", applicability) + .maybe_par() + .mut_addr() + }; + + match self.kind { + CallKind::MethodCall { receiver } => { + let receiver_sugg = Sugg::hir_with_applicability(cx, receiver, "_", applicability); + format!("{receiver_sugg}.clone_into({rhs_sugg})") + }, + CallKind::FunctionCall { self_arg, .. } => { + let self_sugg = Sugg::hir_with_applicability(cx, self_arg, "_", applicability); + format!("ToOwned::clone_into({self_sugg}, {rhs_sugg})") + }, + } + }, + } + } +} diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs deleted file mode 100644 index f2937d51340..00000000000 --- a/clippy_lints/src/attrs.rs +++ /dev/null @@ -1,1210 +0,0 @@ -//! checks for attributes - -use clippy_config::msrvs::{self, Msrv}; -use clippy_utils::diagnostics::{ - span_lint, span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then, -}; -use clippy_utils::is_from_proc_macro; -use clippy_utils::macros::{is_panic, macro_backtrace}; -use clippy_utils::source::{first_line_of_span, is_present_in_source, snippet_opt, without_block_comments}; -use rustc_ast::token::{Token, TokenKind}; -use rustc_ast::tokenstream::TokenTree; -use rustc_ast::{ - AttrArgs, AttrArgsEq, AttrKind, AttrStyle, Attribute, LitKind, MetaItemKind, MetaItemLit, NestedMetaItem, -}; -use rustc_errors::Applicability; -use rustc_hir::{ - Block, Expr, ExprKind, ImplItem, ImplItemKind, Item, ItemKind, StmtKind, TraitFn, TraitItem, TraitItemKind, -}; -use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, Level, LintContext}; -use rustc_middle::lint::in_external_macro; -use rustc_middle::ty; -use rustc_session::{declare_lint_pass, impl_lint_pass}; -use rustc_span::symbol::Symbol; -use rustc_span::{sym, Span, DUMMY_SP}; -use semver::Version; - -static UNIX_SYSTEMS: &[&str] = &[ - "android", - "dragonfly", - "emscripten", - "freebsd", - "fuchsia", - "haiku", - "illumos", - "ios", - "l4re", - "linux", - "macos", - "netbsd", - "openbsd", - "redox", - "solaris", - "vxworks", -]; - -// NOTE: windows is excluded from the list because it's also a valid target family. -static NON_UNIX_SYSTEMS: &[&str] = &["hermit", "none", "wasi"]; - -declare_clippy_lint! { - /// ### What it does - /// Checks for items annotated with `#[inline(always)]`, - /// unless the annotated function is empty or simply panics. - /// - /// ### Why is this bad? - /// While there are valid uses of this annotation (and once - /// you know when to use it, by all means `allow` this lint), it's a common - /// newbie-mistake to pepper one's code with it. - /// - /// As a rule of thumb, before slapping `#[inline(always)]` on a function, - /// measure if that additional function call really affects your runtime profile - /// sufficiently to make up for the increase in compile time. - /// - /// ### Known problems - /// False positives, big time. This lint is meant to be - /// deactivated by everyone doing serious performance work. This means having - /// done the measurement. - /// - /// ### Example - /// ```ignore - /// #[inline(always)] - /// fn not_quite_hot_code(..) { ... } - /// ``` - #[clippy::version = "pre 1.29.0"] - pub INLINE_ALWAYS, - pedantic, - "use of `#[inline(always)]`" -} - -declare_clippy_lint! { - /// ### What it does - /// Checks for `extern crate` and `use` items annotated with - /// lint attributes. - /// - /// This lint permits lint attributes for lints emitted on the items themself. - /// For `use` items these lints are: - /// * deprecated - /// * unreachable_pub - /// * unused_imports - /// * clippy::enum_glob_use - /// * clippy::macro_use_imports - /// * clippy::wildcard_imports - /// - /// For `extern crate` items these lints are: - /// * `unused_imports` on items with `#[macro_use]` - /// - /// ### Why is this bad? - /// Lint attributes have no effect on crate imports. Most - /// likely a `!` was forgotten. - /// - /// ### Example - /// ```ignore - /// #[deny(dead_code)] - /// extern crate foo; - /// #[forbid(dead_code)] - /// use foo::bar; - /// ``` - /// - /// Use instead: - /// ```rust,ignore - /// #[allow(unused_imports)] - /// use foo::baz; - /// #[allow(unused_imports)] - /// #[macro_use] - /// extern crate baz; - /// ``` - #[clippy::version = "pre 1.29.0"] - pub USELESS_ATTRIBUTE, - correctness, - "use of lint attributes on `extern crate` items" -} - -declare_clippy_lint! { - /// ### What it does - /// Checks for `#[deprecated]` annotations with a `since` - /// field that is not a valid semantic version. Also allows "TBD" to signal - /// future deprecation. - /// - /// ### Why is this bad? - /// For checking the version of the deprecation, it must be - /// a valid semver. Failing that, the contained information is useless. - /// - /// ### Example - /// ```no_run - /// #[deprecated(since = "forever")] - /// fn something_else() { /* ... */ } - /// ``` - #[clippy::version = "pre 1.29.0"] - pub DEPRECATED_SEMVER, - correctness, - "use of `#[deprecated(since = \"x\")]` where x is not semver" -} - -declare_clippy_lint! { - /// ### What it does - /// Checks for empty lines after outer attributes - /// - /// ### Why is this bad? - /// Most likely the attribute was meant to be an inner attribute using a '!'. - /// If it was meant to be an outer attribute, then the following item - /// should not be separated by empty lines. - /// - /// ### Known problems - /// Can cause false positives. - /// - /// From the clippy side it's difficult to detect empty lines between an attributes and the - /// following item because empty lines and comments are not part of the AST. The parsing - /// currently works for basic cases but is not perfect. - /// - /// ### Example - /// ```no_run - /// #[allow(dead_code)] - /// - /// fn not_quite_good_code() { } - /// ``` - /// - /// Use instead: - /// ```no_run - /// // Good (as inner attribute) - /// #![allow(dead_code)] - /// - /// fn this_is_fine() { } - /// - /// // or - /// - /// // Good (as outer attribute) - /// #[allow(dead_code)] - /// fn this_is_fine_too() { } - /// ``` - #[clippy::version = "pre 1.29.0"] - pub EMPTY_LINE_AFTER_OUTER_ATTR, - nursery, - "empty line after outer attribute" -} - -declare_clippy_lint! { - /// ### What it does - /// Checks for empty lines after documentation comments. - /// - /// ### Why is this bad? - /// The documentation comment was most likely meant to be an inner attribute or regular comment. - /// If it was intended to be a documentation comment, then the empty line should be removed to - /// be more idiomatic. - /// - /// ### Known problems - /// Only detects empty lines immediately following the documentation. If the doc comment is followed - /// by an attribute and then an empty line, this lint will not trigger. Use `empty_line_after_outer_attr` - /// in combination with this lint to detect both cases. - /// - /// Does not detect empty lines after doc attributes (e.g. `#[doc = ""]`). - /// - /// ### Example - /// ```no_run - /// /// Some doc comment with a blank line after it. - /// - /// fn not_quite_good_code() { } - /// ``` - /// - /// Use instead: - /// ```no_run - /// /// Good (no blank line) - /// fn this_is_fine() { } - /// ``` - /// - /// ```no_run - /// // Good (convert to a regular comment) - /// - /// fn this_is_fine_too() { } - /// ``` - /// - /// ```no_run - /// //! Good (convert to a comment on an inner attribute) - /// - /// fn this_is_fine_as_well() { } - /// ``` - #[clippy::version = "1.70.0"] - pub EMPTY_LINE_AFTER_DOC_COMMENTS, - nursery, - "empty line after documentation comments" -} - -declare_clippy_lint! { - /// ### What it does - /// Checks for `warn`/`deny`/`forbid` attributes targeting the whole clippy::restriction category. - /// - /// ### Why is this bad? - /// Restriction lints sometimes are in contrast with other lints or even go against idiomatic rust. - /// These lints should only be enabled on a lint-by-lint basis and with careful consideration. - /// - /// ### Example - /// ```no_run - /// #![deny(clippy::restriction)] - /// ``` - /// - /// Use instead: - /// ```no_run - /// #![deny(clippy::as_conversions)] - /// ``` - #[clippy::version = "1.47.0"] - pub BLANKET_CLIPPY_RESTRICTION_LINTS, - suspicious, - "enabling the complete restriction group" -} - -declare_clippy_lint! { - /// ### What it does - /// Checks for `#[cfg_attr(rustfmt, rustfmt_skip)]` and suggests to replace it - /// with `#[rustfmt::skip]`. - /// - /// ### Why is this bad? - /// Since tool_attributes ([rust-lang/rust#44690](https://github.com/rust-lang/rust/issues/44690)) - /// are stable now, they should be used instead of the old `cfg_attr(rustfmt)` attributes. - /// - /// ### Known problems - /// This lint doesn't detect crate level inner attributes, because they get - /// processed before the PreExpansionPass lints get executed. See - /// [#3123](https://github.com/rust-lang/rust-clippy/pull/3123#issuecomment-422321765) - /// - /// ### Example - /// ```no_run - /// #[cfg_attr(rustfmt, rustfmt_skip)] - /// fn main() { } - /// ``` - /// - /// Use instead: - /// ```no_run - /// #[rustfmt::skip] - /// fn main() { } - /// ``` - #[clippy::version = "1.32.0"] - pub DEPRECATED_CFG_ATTR, - complexity, - "usage of `cfg_attr(rustfmt)` instead of tool attributes" -} - -declare_clippy_lint! { - /// ### What it does - /// Checks for cfg attributes having operating systems used in target family position. - /// - /// ### Why is this bad? - /// The configuration option will not be recognised and the related item will not be included - /// by the conditional compilation engine. - /// - /// ### Example - /// ```no_run - /// #[cfg(linux)] - /// fn conditional() { } - /// ``` - /// - /// Use instead: - /// ```no_run - /// # mod hidden { - /// #[cfg(target_os = "linux")] - /// fn conditional() { } - /// # } - /// - /// // or - /// - /// #[cfg(unix)] - /// fn conditional() { } - /// ``` - /// Check the [Rust Reference](https://doc.rust-lang.org/reference/conditional-compilation.html#target_os) for more details. - #[clippy::version = "1.45.0"] - pub MISMATCHED_TARGET_OS, - correctness, - "usage of `cfg(operating_system)` instead of `cfg(target_os = \"operating_system\")`" -} - -declare_clippy_lint! { - /// ### What it does - /// Checks for attributes that allow lints without a reason. - /// - /// (This requires the `lint_reasons` feature) - /// - /// ### Why is this bad? - /// Allowing a lint should always have a reason. This reason should be documented to - /// ensure that others understand the reasoning - /// - /// ### Example - /// ```no_run - /// #![feature(lint_reasons)] - /// - /// #![allow(clippy::some_lint)] - /// ``` - /// - /// Use instead: - /// ```no_run - /// #![feature(lint_reasons)] - /// - /// #![allow(clippy::some_lint, reason = "False positive rust-lang/rust-clippy#1002020")] - /// ``` - #[clippy::version = "1.61.0"] - pub ALLOW_ATTRIBUTES_WITHOUT_REASON, - restriction, - "ensures that all `allow` and `expect` attributes have a reason" -} - -declare_clippy_lint! { - /// ### What it does - /// Checks for `#[should_panic]` attributes without specifying the expected panic message. - /// - /// ### Why is this bad? - /// The expected panic message should be specified to ensure that the test is actually - /// panicking with the expected message, and not another unrelated panic. - /// - /// ### Example - /// ```no_run - /// fn random() -> i32 { 0 } - /// - /// #[should_panic] - /// #[test] - /// fn my_test() { - /// let _ = 1 / random(); - /// } - /// ``` - /// - /// Use instead: - /// ```no_run - /// fn random() -> i32 { 0 } - /// - /// #[should_panic = "attempt to divide by zero"] - /// #[test] - /// fn my_test() { - /// let _ = 1 / random(); - /// } - /// ``` - #[clippy::version = "1.74.0"] - pub SHOULD_PANIC_WITHOUT_EXPECT, - pedantic, - "ensures that all `should_panic` attributes specify its expected panic message" -} - -declare_clippy_lint! { - /// ### What it does - /// Checks for `any` and `all` combinators in `cfg` with only one condition. - /// - /// ### Why is this bad? - /// If there is only one condition, no need to wrap it into `any` or `all` combinators. - /// - /// ### Example - /// ```no_run - /// #[cfg(any(unix))] - /// pub struct Bar; - /// ``` - /// - /// Use instead: - /// ```no_run - /// #[cfg(unix)] - /// pub struct Bar; - /// ``` - #[clippy::version = "1.71.0"] - pub NON_MINIMAL_CFG, - style, - "ensure that all `cfg(any())` and `cfg(all())` have more than one condition" -} - -declare_clippy_lint! { - /// ### What it does - /// Checks for `#[cfg(features = "...")]` and suggests to replace it with - /// `#[cfg(feature = "...")]`. - /// - /// It also checks if `cfg(test)` was misspelled. - /// - /// ### Why is this bad? - /// Misspelling `feature` as `features` or `test` as `tests` can be sometimes hard to spot. It - /// may cause conditional compilation not work quietly. - /// - /// ### Example - /// ```no_run - /// #[cfg(features = "some-feature")] - /// fn conditional() { } - /// #[cfg(tests)] - /// mod tests { } - /// ``` - /// - /// Use instead: - /// ```no_run - /// #[cfg(feature = "some-feature")] - /// fn conditional() { } - /// #[cfg(test)] - /// mod tests { } - /// ``` - #[clippy::version = "1.69.0"] - pub MAYBE_MISUSED_CFG, - suspicious, - "prevent from misusing the wrong attr name" -} - -declare_clippy_lint! { - /// ### What it does - /// Checks for `#[cfg_attr(feature = "cargo-clippy", ...)]` and for - /// `#[cfg(feature = "cargo-clippy")]` and suggests to replace it with - /// `#[cfg_attr(clippy, ...)]` or `#[cfg(clippy)]`. - /// - /// ### Why is this bad? - /// This feature has been deprecated for years and shouldn't be used anymore. - /// - /// ### Example - /// ```no_run - /// #[cfg(feature = "cargo-clippy")] - /// struct Bar; - /// ``` - /// - /// Use instead: - /// ```no_run - /// #[cfg(clippy)] - /// struct Bar; - /// ``` - #[clippy::version = "1.78.0"] - pub DEPRECATED_CLIPPY_CFG_ATTR, - suspicious, - "usage of `cfg(feature = \"cargo-clippy\")` instead of `cfg(clippy)`" -} - -declare_clippy_lint! { - /// ### What it does - /// Checks for `#[cfg_attr(clippy, allow(clippy::lint))]` - /// and suggests to replace it with `#[allow(clippy::lint)]`. - /// - /// ### Why is this bad? - /// There is no reason to put clippy attributes behind a clippy `cfg` as they are not - /// run by anything else than clippy. - /// - /// ### Example - /// ```no_run - /// #![cfg_attr(clippy, allow(clippy::deprecated_cfg_attr))] - /// ``` - /// - /// Use instead: - /// ```no_run - /// #![allow(clippy::deprecated_cfg_attr)] - /// ``` - #[clippy::version = "1.78.0"] - pub UNNECESSARY_CLIPPY_CFG, - suspicious, - "usage of `cfg_attr(clippy, allow(clippy::lint))` instead of `allow(clippy::lint)`" -} - -declare_lint_pass!(Attributes => [ - ALLOW_ATTRIBUTES_WITHOUT_REASON, - INLINE_ALWAYS, - DEPRECATED_SEMVER, - USELESS_ATTRIBUTE, - BLANKET_CLIPPY_RESTRICTION_LINTS, - SHOULD_PANIC_WITHOUT_EXPECT, -]); - -impl<'tcx> LateLintPass<'tcx> for Attributes { - fn check_crate(&mut self, cx: &LateContext<'tcx>) { - for (name, level) in &cx.sess().opts.lint_opts { - if name == "clippy::restriction" && *level > Level::Allow { - span_lint_and_then( - cx, - BLANKET_CLIPPY_RESTRICTION_LINTS, - DUMMY_SP, - "`clippy::restriction` is not meant to be enabled as a group", - |diag| { - diag.note(format!( - "because of the command line `--{} clippy::restriction`", - level.as_str() - )); - diag.help("enable the restriction lints you need individually"); - }, - ); - } - } - } - - fn check_attribute(&mut self, cx: &LateContext<'tcx>, attr: &'tcx Attribute) { - if let Some(items) = &attr.meta_item_list() { - if let Some(ident) = attr.ident() { - if is_lint_level(ident.name) { - check_clippy_lint_names(cx, ident.name, items); - } - if matches!(ident.name, sym::allow | sym::expect) { - check_lint_reason(cx, ident.name, items, attr); - } - if items.is_empty() || !attr.has_name(sym::deprecated) { - return; - } - for item in items { - if let NestedMetaItem::MetaItem(mi) = &item - && let MetaItemKind::NameValue(lit) = &mi.kind - && mi.has_name(sym::since) - { - check_deprecated_since(cx, item.span(), lit); - } - } - } - } - if attr.has_name(sym::should_panic) { - check_should_panic_reason(cx, attr); - } - } - - fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { - let attrs = cx.tcx.hir().attrs(item.hir_id()); - if is_relevant_item(cx, item) { - check_attrs(cx, item.span, item.ident.name, attrs); - } - match item.kind { - ItemKind::ExternCrate(..) | ItemKind::Use(..) => { - let skip_unused_imports = attrs.iter().any(|attr| attr.has_name(sym::macro_use)); - - for attr in attrs { - if in_external_macro(cx.sess(), attr.span) { - return; - } - if let Some(lint_list) = &attr.meta_item_list() { - if attr.ident().map_or(false, |ident| is_lint_level(ident.name)) { - for lint in lint_list { - match item.kind { - ItemKind::Use(..) => { - if is_word(lint, sym::unused_imports) - || is_word(lint, sym::deprecated) - || is_word(lint, sym!(unreachable_pub)) - || is_word(lint, sym!(unused)) - || is_word(lint, sym!(unused_import_braces)) - || extract_clippy_lint(lint).map_or(false, |s| { - matches!( - s.as_str(), - "wildcard_imports" - | "enum_glob_use" - | "redundant_pub_crate" - | "macro_use_imports" - | "unsafe_removed_from_name" - | "module_name_repetitions" - | "single_component_path_imports" - ) - }) - { - return; - } - }, - ItemKind::ExternCrate(..) => { - if is_word(lint, sym::unused_imports) && skip_unused_imports { - return; - } - if is_word(lint, sym!(unused_extern_crates)) { - return; - } - }, - _ => {}, - } - } - let line_span = first_line_of_span(cx, attr.span); - - if let Some(mut sugg) = snippet_opt(cx, line_span) { - if sugg.contains("#[") { - span_lint_and_then( - cx, - USELESS_ATTRIBUTE, - line_span, - "useless lint attribute", - |diag| { - sugg = sugg.replacen("#[", "#![", 1); - diag.span_suggestion( - line_span, - "if you just forgot a `!`, use", - sugg, - Applicability::MaybeIncorrect, - ); - }, - ); - } - } - } - } - } - }, - _ => {}, - } - } - - fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>) { - if is_relevant_impl(cx, item) { - check_attrs(cx, item.span, item.ident.name, cx.tcx.hir().attrs(item.hir_id())); - } - } - - fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) { - if is_relevant_trait(cx, item) { - check_attrs(cx, item.span, item.ident.name, cx.tcx.hir().attrs(item.hir_id())); - } - } -} - -/// Returns the lint name if it is clippy lint. -fn extract_clippy_lint(lint: &NestedMetaItem) -> Option { - if let Some(meta_item) = lint.meta_item() - && meta_item.path.segments.len() > 1 - && let tool_name = meta_item.path.segments[0].ident - && tool_name.name == sym::clippy - { - let lint_name = meta_item.path.segments.last().unwrap().ident.name; - return Some(lint_name); - } - None -} - -fn check_should_panic_reason(cx: &LateContext<'_>, attr: &Attribute) { - if let AttrKind::Normal(normal_attr) = &attr.kind { - if let AttrArgs::Eq(_, AttrArgsEq::Hir(_)) = &normal_attr.item.args { - // `#[should_panic = ".."]` found, good - return; - } - - if let AttrArgs::Delimited(args) = &normal_attr.item.args - && let mut tt_iter = args.tokens.trees() - && let Some(TokenTree::Token( - Token { - kind: TokenKind::Ident(sym::expected, _), - .. - }, - _, - )) = tt_iter.next() - && let Some(TokenTree::Token( - Token { - kind: TokenKind::Eq, .. - }, - _, - )) = tt_iter.next() - && let Some(TokenTree::Token( - Token { - kind: TokenKind::Literal(_), - .. - }, - _, - )) = tt_iter.next() - { - // `#[should_panic(expected = "..")]` found, good - return; - } - - span_lint_and_sugg( - cx, - SHOULD_PANIC_WITHOUT_EXPECT, - attr.span, - "#[should_panic] attribute without a reason", - "consider specifying the expected panic", - "#[should_panic(expected = /* panic message */)]".into(), - Applicability::HasPlaceholders, - ); - } -} - -fn check_clippy_lint_names(cx: &LateContext<'_>, name: Symbol, items: &[NestedMetaItem]) { - for lint in items { - if let Some(lint_name) = extract_clippy_lint(lint) { - if lint_name.as_str() == "restriction" && name != sym::allow { - span_lint_and_help( - cx, - BLANKET_CLIPPY_RESTRICTION_LINTS, - lint.span(), - "`clippy::restriction` is not meant to be enabled as a group", - None, - "enable the restriction lints you need individually", - ); - } - } - } -} - -fn check_lint_reason<'cx>(cx: &LateContext<'cx>, name: Symbol, items: &[NestedMetaItem], attr: &'cx Attribute) { - // Check for the feature - if !cx.tcx.features().lint_reasons { - return; - } - - // Check if the reason is present - if let Some(item) = items.last().and_then(NestedMetaItem::meta_item) - && let MetaItemKind::NameValue(_) = &item.kind - && item.path == sym::reason - { - return; - } - - // Check if the attribute is in an external macro and therefore out of the developer's control - if in_external_macro(cx.sess(), attr.span) || is_from_proc_macro(cx, &attr) { - return; - } - - span_lint_and_help( - cx, - ALLOW_ATTRIBUTES_WITHOUT_REASON, - attr.span, - &format!("`{}` attribute without specifying a reason", name.as_str()), - None, - "try adding a reason at the end with `, reason = \"..\"`", - ); -} - -fn is_relevant_item(cx: &LateContext<'_>, item: &Item<'_>) -> bool { - if let ItemKind::Fn(_, _, eid) = item.kind { - is_relevant_expr(cx, cx.tcx.typeck_body(eid), cx.tcx.hir().body(eid).value) - } else { - true - } -} - -fn is_relevant_impl(cx: &LateContext<'_>, item: &ImplItem<'_>) -> bool { - match item.kind { - ImplItemKind::Fn(_, eid) => is_relevant_expr(cx, cx.tcx.typeck_body(eid), cx.tcx.hir().body(eid).value), - _ => false, - } -} - -fn is_relevant_trait(cx: &LateContext<'_>, item: &TraitItem<'_>) -> bool { - match item.kind { - TraitItemKind::Fn(_, TraitFn::Required(_)) => true, - TraitItemKind::Fn(_, TraitFn::Provided(eid)) => { - is_relevant_expr(cx, cx.tcx.typeck_body(eid), cx.tcx.hir().body(eid).value) - }, - _ => false, - } -} - -fn is_relevant_block(cx: &LateContext<'_>, typeck_results: &ty::TypeckResults<'_>, block: &Block<'_>) -> bool { - block.stmts.first().map_or( - block - .expr - .as_ref() - .map_or(false, |e| is_relevant_expr(cx, typeck_results, e)), - |stmt| match &stmt.kind { - StmtKind::Local(_) => true, - StmtKind::Expr(expr) | StmtKind::Semi(expr) => is_relevant_expr(cx, typeck_results, expr), - StmtKind::Item(_) => false, - }, - ) -} - -fn is_relevant_expr(cx: &LateContext<'_>, typeck_results: &ty::TypeckResults<'_>, expr: &Expr<'_>) -> bool { - if macro_backtrace(expr.span).last().map_or(false, |macro_call| { - is_panic(cx, macro_call.def_id) || cx.tcx.item_name(macro_call.def_id) == sym::unreachable - }) { - return false; - } - match &expr.kind { - ExprKind::Block(block, _) => is_relevant_block(cx, typeck_results, block), - ExprKind::Ret(Some(e)) => is_relevant_expr(cx, typeck_results, e), - ExprKind::Ret(None) | ExprKind::Break(_, None) => false, - _ => true, - } -} - -fn check_attrs(cx: &LateContext<'_>, span: Span, name: Symbol, attrs: &[Attribute]) { - if span.from_expansion() { - return; - } - - for attr in attrs { - if let Some(values) = attr.meta_item_list() { - if values.len() != 1 || !attr.has_name(sym::inline) { - continue; - } - if is_word(&values[0], sym::always) { - span_lint( - cx, - INLINE_ALWAYS, - attr.span, - &format!("you have declared `#[inline(always)]` on `{name}`. This is usually a bad idea"), - ); - } - } - } -} - -fn check_deprecated_since(cx: &LateContext<'_>, span: Span, lit: &MetaItemLit) { - if let LitKind::Str(is, _) = lit.kind { - if is.as_str() == "TBD" || Version::parse(is.as_str()).is_ok() { - return; - } - } - span_lint( - cx, - DEPRECATED_SEMVER, - span, - "the since field must contain a semver-compliant version", - ); -} - -fn is_word(nmi: &NestedMetaItem, expected: Symbol) -> bool { - if let NestedMetaItem::MetaItem(mi) = &nmi { - mi.is_word() && mi.has_name(expected) - } else { - false - } -} - -pub struct EarlyAttributes { - pub msrv: Msrv, -} - -impl_lint_pass!(EarlyAttributes => [ - DEPRECATED_CFG_ATTR, - MISMATCHED_TARGET_OS, - EMPTY_LINE_AFTER_OUTER_ATTR, - EMPTY_LINE_AFTER_DOC_COMMENTS, - NON_MINIMAL_CFG, - MAYBE_MISUSED_CFG, - DEPRECATED_CLIPPY_CFG_ATTR, - UNNECESSARY_CLIPPY_CFG, -]); - -impl EarlyLintPass for EarlyAttributes { - fn check_item(&mut self, cx: &EarlyContext<'_>, item: &rustc_ast::Item) { - check_empty_line_after_outer_attr(cx, item); - } - - fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &Attribute) { - check_deprecated_cfg_attr(cx, attr, &self.msrv); - check_deprecated_cfg(cx, attr); - check_mismatched_target_os(cx, attr); - check_minimal_cfg_condition(cx, attr); - check_misused_cfg(cx, attr); - } - - extract_msrv_attr!(EarlyContext); -} - -/// Check for empty lines after outer attributes. -/// -/// Attributes and documentation comments are both considered outer attributes -/// by the AST. However, the average user likely considers them to be different. -/// Checking for empty lines after each of these attributes is split into two different -/// lints but can share the same logic. -fn check_empty_line_after_outer_attr(cx: &EarlyContext<'_>, item: &rustc_ast::Item) { - let mut iter = item.attrs.iter().peekable(); - while let Some(attr) = iter.next() { - if (matches!(attr.kind, AttrKind::Normal(..)) || matches!(attr.kind, AttrKind::DocComment(..))) - && attr.style == AttrStyle::Outer - && is_present_in_source(cx, attr.span) - { - let begin_of_attr_to_item = Span::new(attr.span.lo(), item.span.lo(), item.span.ctxt(), item.span.parent()); - let end_of_attr_to_next_attr_or_item = Span::new( - attr.span.hi(), - iter.peek().map_or(item.span.lo(), |next_attr| next_attr.span.lo()), - item.span.ctxt(), - item.span.parent(), - ); - - if let Some(snippet) = snippet_opt(cx, end_of_attr_to_next_attr_or_item) { - let lines = snippet.split('\n').collect::>(); - let lines = without_block_comments(lines); - - if lines.iter().filter(|l| l.trim().is_empty()).count() > 2 { - let (lint_msg, lint_type) = match attr.kind { - AttrKind::DocComment(..) => ( - "found an empty line after a doc comment. \ - Perhaps you need to use `//!` to make a comment on a module, remove the empty line, or make a regular comment with `//`?", - EMPTY_LINE_AFTER_DOC_COMMENTS, - ), - AttrKind::Normal(..) => ( - "found an empty line after an outer attribute. \ - Perhaps you forgot to add a `!` to make it an inner attribute?", - EMPTY_LINE_AFTER_OUTER_ATTR, - ), - }; - - span_lint(cx, lint_type, begin_of_attr_to_item, lint_msg); - } - } - } - } -} - -fn check_cargo_clippy_attr(cx: &EarlyContext<'_>, item: &rustc_ast::MetaItem) { - if item.has_name(sym::feature) && item.value_str().is_some_and(|v| v.as_str() == "cargo-clippy") { - span_lint_and_sugg( - cx, - DEPRECATED_CLIPPY_CFG_ATTR, - item.span, - "`feature = \"cargo-clippy\"` was replaced by `clippy`", - "replace with", - "clippy".to_string(), - Applicability::MachineApplicable, - ); - } -} - -fn check_deprecated_cfg_recursively(cx: &EarlyContext<'_>, attr: &rustc_ast::MetaItem) { - if let Some(ident) = attr.ident() { - if ["any", "all", "not"].contains(&ident.name.as_str()) { - let Some(list) = attr.meta_item_list() else { return }; - for item in list.iter().filter_map(|item| item.meta_item()) { - check_deprecated_cfg_recursively(cx, item); - } - } else { - check_cargo_clippy_attr(cx, attr); - } - } -} - -fn check_deprecated_cfg(cx: &EarlyContext<'_>, attr: &Attribute) { - if attr.has_name(sym::cfg) - && let Some(list) = attr.meta_item_list() - { - for item in list.iter().filter_map(|item| item.meta_item()) { - check_deprecated_cfg_recursively(cx, item); - } - } -} - -fn check_deprecated_cfg_attr(cx: &EarlyContext<'_>, attr: &Attribute, msrv: &Msrv) { - // check cfg_attr - if attr.has_name(sym::cfg_attr) - && let Some(items) = attr.meta_item_list() - && items.len() == 2 - && let Some(feature_item) = items[0].meta_item() - { - // check for `rustfmt` - if feature_item.has_name(sym::rustfmt) - && msrv.meets(msrvs::TOOL_ATTRIBUTES) - // check for `rustfmt_skip` and `rustfmt::skip` - && let Some(skip_item) = &items[1].meta_item() - && (skip_item.has_name(sym!(rustfmt_skip)) - || skip_item - .path - .segments - .last() - .expect("empty path in attribute") - .ident - .name - == sym::skip) - // Only lint outer attributes, because custom inner attributes are unstable - // Tracking issue: https://github.com/rust-lang/rust/issues/54726 - && attr.style == AttrStyle::Outer - { - span_lint_and_sugg( - cx, - DEPRECATED_CFG_ATTR, - attr.span, - "`cfg_attr` is deprecated for rustfmt and got replaced by tool attributes", - "use", - "#[rustfmt::skip]".to_string(), - Applicability::MachineApplicable, - ); - } else { - check_deprecated_cfg_recursively(cx, feature_item); - if let Some(behind_cfg_attr) = items[1].meta_item() { - check_clippy_cfg_attr(cx, feature_item, behind_cfg_attr, attr); - } - } - } -} - -fn check_clippy_cfg_attr( - cx: &EarlyContext<'_>, - cfg_attr: &rustc_ast::MetaItem, - behind_cfg_attr: &rustc_ast::MetaItem, - attr: &Attribute, -) { - if cfg_attr.has_name(sym::clippy) - && let Some(ident) = behind_cfg_attr.ident() - && Level::from_symbol(ident.name, Some(attr.id)).is_some() - && let Some(items) = behind_cfg_attr.meta_item_list() - { - let nb_items = items.len(); - let mut clippy_lints = Vec::with_capacity(items.len()); - for item in items { - if let Some(meta_item) = item.meta_item() - && let [part1, _] = meta_item.path.segments.as_slice() - && part1.ident.name == sym::clippy - { - clippy_lints.push(item.span()); - } - } - if clippy_lints.is_empty() { - return; - } - if nb_items == clippy_lints.len() { - if let Some(snippet) = snippet_opt(cx, behind_cfg_attr.span) { - span_lint_and_sugg( - cx, - UNNECESSARY_CLIPPY_CFG, - attr.span, - "no need to put clippy lints behind a `clippy` cfg", - "replace with", - format!( - "#{}[{}]", - if attr.style == AttrStyle::Inner { "!" } else { "" }, - snippet - ), - Applicability::MachineApplicable, - ); - } - } else { - let snippet = clippy_lints - .iter() - .filter_map(|sp| snippet_opt(cx, *sp)) - .collect::>() - .join(","); - span_lint_and_note( - cx, - UNNECESSARY_CLIPPY_CFG, - clippy_lints, - "no need to put clippy lints behind a `clippy` cfg", - None, - &format!( - "write instead: `#{}[{}({})]`", - if attr.style == AttrStyle::Inner { "!" } else { "" }, - ident.name, - snippet - ), - ); - } - } -} - -fn check_nested_cfg(cx: &EarlyContext<'_>, items: &[NestedMetaItem]) { - for item in items { - if let NestedMetaItem::MetaItem(meta) = item { - if !meta.has_name(sym::any) && !meta.has_name(sym::all) { - continue; - } - if let MetaItemKind::List(list) = &meta.kind { - check_nested_cfg(cx, list); - if list.len() == 1 { - span_lint_and_then( - cx, - NON_MINIMAL_CFG, - meta.span, - "unneeded sub `cfg` when there is only one condition", - |diag| { - if let Some(snippet) = snippet_opt(cx, list[0].span()) { - diag.span_suggestion(meta.span, "try", snippet, Applicability::MaybeIncorrect); - } - }, - ); - } else if list.is_empty() && meta.has_name(sym::all) { - span_lint_and_then( - cx, - NON_MINIMAL_CFG, - meta.span, - "unneeded sub `cfg` when there is no condition", - |_| {}, - ); - } - } - } - } -} - -fn check_nested_misused_cfg(cx: &EarlyContext<'_>, items: &[NestedMetaItem]) { - for item in items { - if let NestedMetaItem::MetaItem(meta) = item { - if let Some(ident) = meta.ident() - && ident.name.as_str() == "features" - && let Some(val) = meta.value_str() - { - span_lint_and_sugg( - cx, - MAYBE_MISUSED_CFG, - meta.span, - "'feature' may be misspelled as 'features'", - "did you mean", - format!("feature = \"{val}\""), - Applicability::MaybeIncorrect, - ); - } - if let MetaItemKind::List(list) = &meta.kind { - check_nested_misused_cfg(cx, list); - // If this is not a list, then we check for `cfg(test)`. - } else if let Some(ident) = meta.ident() - && matches!(ident.name.as_str(), "tests" | "Test") - { - span_lint_and_sugg( - cx, - MAYBE_MISUSED_CFG, - meta.span, - &format!("'test' may be misspelled as '{}'", ident.name.as_str()), - "did you mean", - "test".to_string(), - Applicability::MaybeIncorrect, - ); - } - } - } -} - -fn check_minimal_cfg_condition(cx: &EarlyContext<'_>, attr: &Attribute) { - if attr.has_name(sym::cfg) - && let Some(items) = attr.meta_item_list() - { - check_nested_cfg(cx, &items); - } -} - -fn check_misused_cfg(cx: &EarlyContext<'_>, attr: &Attribute) { - if attr.has_name(sym::cfg) - && let Some(items) = attr.meta_item_list() - { - check_nested_misused_cfg(cx, &items); - } -} - -fn check_mismatched_target_os(cx: &EarlyContext<'_>, attr: &Attribute) { - fn find_os(name: &str) -> Option<&'static str> { - UNIX_SYSTEMS - .iter() - .chain(NON_UNIX_SYSTEMS.iter()) - .find(|&&os| os == name) - .copied() - } - - fn is_unix(name: &str) -> bool { - UNIX_SYSTEMS.iter().any(|&os| os == name) - } - - fn find_mismatched_target_os(items: &[NestedMetaItem]) -> Vec<(&str, Span)> { - let mut mismatched = Vec::new(); - - for item in items { - if let NestedMetaItem::MetaItem(meta) = item { - match &meta.kind { - MetaItemKind::List(list) => { - mismatched.extend(find_mismatched_target_os(list)); - }, - MetaItemKind::Word => { - if let Some(ident) = meta.ident() - && let Some(os) = find_os(ident.name.as_str()) - { - mismatched.push((os, ident.span)); - } - }, - MetaItemKind::NameValue(..) => {}, - } - } - } - - mismatched - } - - if attr.has_name(sym::cfg) - && let Some(list) = attr.meta_item_list() - && let mismatched = find_mismatched_target_os(&list) - && !mismatched.is_empty() - { - let mess = "operating system used in target family position"; - - span_lint_and_then(cx, MISMATCHED_TARGET_OS, attr.span, mess, |diag| { - // Avoid showing the unix suggestion multiple times in case - // we have more than one mismatch for unix-like systems - let mut unix_suggested = false; - - for (os, span) in mismatched { - let sugg = format!("target_os = \"{os}\""); - diag.span_suggestion(span, "try", sugg, Applicability::MaybeIncorrect); - - if !unix_suggested && is_unix(os) { - diag.help("did you mean `unix`?"); - unix_suggested = true; - } - } - }); - } -} - -fn is_lint_level(symbol: Symbol) -> bool { - matches!(symbol, sym::allow | sym::expect | sym::warn | sym::deny | sym::forbid) -} diff --git a/clippy_lints/src/attrs/allow_attributes_without_reason.rs b/clippy_lints/src/attrs/allow_attributes_without_reason.rs new file mode 100644 index 00000000000..df00f23e37e --- /dev/null +++ b/clippy_lints/src/attrs/allow_attributes_without_reason.rs @@ -0,0 +1,37 @@ +use super::{Attribute, ALLOW_ATTRIBUTES_WITHOUT_REASON}; +use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::is_from_proc_macro; +use rustc_ast::{MetaItemKind, NestedMetaItem}; +use rustc_lint::{LateContext, LintContext}; +use rustc_middle::lint::in_external_macro; +use rustc_span::sym; +use rustc_span::symbol::Symbol; + +pub(super) fn check<'cx>(cx: &LateContext<'cx>, name: Symbol, items: &[NestedMetaItem], attr: &'cx Attribute) { + // Check for the feature + if !cx.tcx.features().lint_reasons { + return; + } + + // Check if the reason is present + if let Some(item) = items.last().and_then(NestedMetaItem::meta_item) + && let MetaItemKind::NameValue(_) = &item.kind + && item.path == sym::reason + { + return; + } + + // Check if the attribute is in an external macro and therefore out of the developer's control + if in_external_macro(cx.sess(), attr.span) || is_from_proc_macro(cx, &attr) { + return; + } + + span_lint_and_help( + cx, + ALLOW_ATTRIBUTES_WITHOUT_REASON, + attr.span, + &format!("`{}` attribute without specifying a reason", name.as_str()), + None, + "try adding a reason at the end with `, reason = \"..\"`", + ); +} diff --git a/clippy_lints/src/attrs/blanket_clippy_restriction_lints.rs b/clippy_lints/src/attrs/blanket_clippy_restriction_lints.rs new file mode 100644 index 00000000000..9b08fd6d654 --- /dev/null +++ b/clippy_lints/src/attrs/blanket_clippy_restriction_lints.rs @@ -0,0 +1,44 @@ +use super::utils::extract_clippy_lint; +use super::BLANKET_CLIPPY_RESTRICTION_LINTS; +use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then}; +use rustc_ast::NestedMetaItem; +use rustc_lint::{LateContext, Level, LintContext}; +use rustc_span::symbol::Symbol; +use rustc_span::{sym, DUMMY_SP}; + +pub(super) fn check(cx: &LateContext<'_>, name: Symbol, items: &[NestedMetaItem]) { + for lint in items { + if let Some(lint_name) = extract_clippy_lint(lint) { + if lint_name.as_str() == "restriction" && name != sym::allow { + span_lint_and_help( + cx, + BLANKET_CLIPPY_RESTRICTION_LINTS, + lint.span(), + "`clippy::restriction` is not meant to be enabled as a group", + None, + "enable the restriction lints you need individually", + ); + } + } + } +} + +pub(super) fn check_command_line(cx: &LateContext<'_>) { + for (name, level) in &cx.sess().opts.lint_opts { + if name == "clippy::restriction" && *level > Level::Allow { + span_lint_and_then( + cx, + BLANKET_CLIPPY_RESTRICTION_LINTS, + DUMMY_SP, + "`clippy::restriction` is not meant to be enabled as a group", + |diag| { + diag.note(format!( + "because of the command line `--{} clippy::restriction`", + level.as_str() + )); + diag.help("enable the restriction lints you need individually"); + }, + ); + } + } +} diff --git a/clippy_lints/src/attrs/deprecated_cfg_attr.rs b/clippy_lints/src/attrs/deprecated_cfg_attr.rs new file mode 100644 index 00000000000..e872ab6b4b5 --- /dev/null +++ b/clippy_lints/src/attrs/deprecated_cfg_attr.rs @@ -0,0 +1,87 @@ +use super::{unnecessary_clippy_cfg, Attribute, DEPRECATED_CFG_ATTR, DEPRECATED_CLIPPY_CFG_ATTR}; +use clippy_config::msrvs::{self, Msrv}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use rustc_ast::AttrStyle; +use rustc_errors::Applicability; +use rustc_lint::EarlyContext; +use rustc_span::sym; + +pub(super) fn check(cx: &EarlyContext<'_>, attr: &Attribute, msrv: &Msrv) { + // check cfg_attr + if attr.has_name(sym::cfg_attr) + && let Some(items) = attr.meta_item_list() + && items.len() == 2 + && let Some(feature_item) = items[0].meta_item() + { + // check for `rustfmt` + if feature_item.has_name(sym::rustfmt) + && msrv.meets(msrvs::TOOL_ATTRIBUTES) + // check for `rustfmt_skip` and `rustfmt::skip` + && let Some(skip_item) = &items[1].meta_item() + && (skip_item.has_name(sym!(rustfmt_skip)) + || skip_item + .path + .segments + .last() + .expect("empty path in attribute") + .ident + .name + == sym::skip) + // Only lint outer attributes, because custom inner attributes are unstable + // Tracking issue: https://github.com/rust-lang/rust/issues/54726 + && attr.style == AttrStyle::Outer + { + span_lint_and_sugg( + cx, + DEPRECATED_CFG_ATTR, + attr.span, + "`cfg_attr` is deprecated for rustfmt and got replaced by tool attributes", + "use", + "#[rustfmt::skip]".to_string(), + Applicability::MachineApplicable, + ); + } else { + check_deprecated_cfg_recursively(cx, feature_item); + if let Some(behind_cfg_attr) = items[1].meta_item() { + unnecessary_clippy_cfg::check(cx, feature_item, behind_cfg_attr, attr); + } + } + } +} + +pub(super) fn check_clippy(cx: &EarlyContext<'_>, attr: &Attribute) { + if attr.has_name(sym::cfg) + && let Some(list) = attr.meta_item_list() + { + for item in list.iter().filter_map(|item| item.meta_item()) { + check_deprecated_cfg_recursively(cx, item); + } + } +} + +fn check_deprecated_cfg_recursively(cx: &EarlyContext<'_>, attr: &rustc_ast::MetaItem) { + if let Some(ident) = attr.ident() { + if ["any", "all", "not"].contains(&ident.name.as_str()) { + let Some(list) = attr.meta_item_list() else { return }; + for item in list.iter().filter_map(|item| item.meta_item()) { + check_deprecated_cfg_recursively(cx, item); + } + } else { + check_cargo_clippy_attr(cx, attr); + } + } +} + +fn check_cargo_clippy_attr(cx: &EarlyContext<'_>, item: &rustc_ast::MetaItem) { + if item.has_name(sym::feature) && item.value_str().is_some_and(|v| v.as_str() == "cargo-clippy") { + span_lint_and_sugg( + cx, + DEPRECATED_CLIPPY_CFG_ATTR, + item.span, + "`feature = \"cargo-clippy\"` was replaced by `clippy`", + "replace with", + "clippy".to_string(), + Applicability::MachineApplicable, + ); + } +} diff --git a/clippy_lints/src/attrs/deprecated_semver.rs b/clippy_lints/src/attrs/deprecated_semver.rs new file mode 100644 index 00000000000..1898c145c76 --- /dev/null +++ b/clippy_lints/src/attrs/deprecated_semver.rs @@ -0,0 +1,20 @@ +use super::DEPRECATED_SEMVER; +use clippy_utils::diagnostics::span_lint; +use rustc_ast::{LitKind, MetaItemLit}; +use rustc_lint::LateContext; +use rustc_span::Span; +use semver::Version; + +pub(super) fn check(cx: &LateContext<'_>, span: Span, lit: &MetaItemLit) { + if let LitKind::Str(is, _) = lit.kind { + if is.as_str() == "TBD" || Version::parse(is.as_str()).is_ok() { + return; + } + } + span_lint( + cx, + DEPRECATED_SEMVER, + span, + "the since field must contain a semver-compliant version", + ); +} diff --git a/clippy_lints/src/attrs/empty_line_after.rs b/clippy_lints/src/attrs/empty_line_after.rs new file mode 100644 index 00000000000..ca43e76ac57 --- /dev/null +++ b/clippy_lints/src/attrs/empty_line_after.rs @@ -0,0 +1,52 @@ +use super::{EMPTY_LINE_AFTER_DOC_COMMENTS, EMPTY_LINE_AFTER_OUTER_ATTR}; +use clippy_utils::diagnostics::span_lint; +use clippy_utils::source::{is_present_in_source, snippet_opt, without_block_comments}; +use rustc_ast::{AttrKind, AttrStyle}; +use rustc_lint::EarlyContext; +use rustc_span::Span; + +/// Check for empty lines after outer attributes. +/// +/// Attributes and documentation comments are both considered outer attributes +/// by the AST. However, the average user likely considers them to be different. +/// Checking for empty lines after each of these attributes is split into two different +/// lints but can share the same logic. +pub(super) fn check(cx: &EarlyContext<'_>, item: &rustc_ast::Item) { + let mut iter = item.attrs.iter().peekable(); + while let Some(attr) = iter.next() { + if (matches!(attr.kind, AttrKind::Normal(..)) || matches!(attr.kind, AttrKind::DocComment(..))) + && attr.style == AttrStyle::Outer + && is_present_in_source(cx, attr.span) + { + let begin_of_attr_to_item = Span::new(attr.span.lo(), item.span.lo(), item.span.ctxt(), item.span.parent()); + let end_of_attr_to_next_attr_or_item = Span::new( + attr.span.hi(), + iter.peek().map_or(item.span.lo(), |next_attr| next_attr.span.lo()), + item.span.ctxt(), + item.span.parent(), + ); + + if let Some(snippet) = snippet_opt(cx, end_of_attr_to_next_attr_or_item) { + let lines = snippet.split('\n').collect::>(); + let lines = without_block_comments(lines); + + if lines.iter().filter(|l| l.trim().is_empty()).count() > 2 { + let (lint_msg, lint_type) = match attr.kind { + AttrKind::DocComment(..) => ( + "found an empty line after a doc comment. \ + Perhaps you need to use `//!` to make a comment on a module, remove the empty line, or make a regular comment with `//`?", + EMPTY_LINE_AFTER_DOC_COMMENTS, + ), + AttrKind::Normal(..) => ( + "found an empty line after an outer attribute. \ + Perhaps you forgot to add a `!` to make it an inner attribute?", + EMPTY_LINE_AFTER_OUTER_ATTR, + ), + }; + + span_lint(cx, lint_type, begin_of_attr_to_item, lint_msg); + } + } + } + } +} diff --git a/clippy_lints/src/attrs/inline_always.rs b/clippy_lints/src/attrs/inline_always.rs new file mode 100644 index 00000000000..cfcd2cc6a00 --- /dev/null +++ b/clippy_lints/src/attrs/inline_always.rs @@ -0,0 +1,29 @@ +use super::utils::is_word; +use super::INLINE_ALWAYS; +use clippy_utils::diagnostics::span_lint; +use rustc_ast::Attribute; +use rustc_lint::LateContext; +use rustc_span::symbol::Symbol; +use rustc_span::{sym, Span}; + +pub(super) fn check(cx: &LateContext<'_>, span: Span, name: Symbol, attrs: &[Attribute]) { + if span.from_expansion() { + return; + } + + for attr in attrs { + if let Some(values) = attr.meta_item_list() { + if values.len() != 1 || !attr.has_name(sym::inline) { + continue; + } + if is_word(&values[0], sym::always) { + span_lint( + cx, + INLINE_ALWAYS, + attr.span, + &format!("you have declared `#[inline(always)]` on `{name}`. This is usually a bad idea"), + ); + } + } + } +} diff --git a/clippy_lints/src/attrs/maybe_misused_cfg.rs b/clippy_lints/src/attrs/maybe_misused_cfg.rs new file mode 100644 index 00000000000..5a70866eda5 --- /dev/null +++ b/clippy_lints/src/attrs/maybe_misused_cfg.rs @@ -0,0 +1,51 @@ +use super::{Attribute, MAYBE_MISUSED_CFG}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use rustc_ast::{MetaItemKind, NestedMetaItem}; +use rustc_errors::Applicability; +use rustc_lint::EarlyContext; +use rustc_span::sym; + +pub(super) fn check(cx: &EarlyContext<'_>, attr: &Attribute) { + if attr.has_name(sym::cfg) + && let Some(items) = attr.meta_item_list() + { + check_nested_misused_cfg(cx, &items); + } +} + +fn check_nested_misused_cfg(cx: &EarlyContext<'_>, items: &[NestedMetaItem]) { + for item in items { + if let NestedMetaItem::MetaItem(meta) = item { + if let Some(ident) = meta.ident() + && ident.name.as_str() == "features" + && let Some(val) = meta.value_str() + { + span_lint_and_sugg( + cx, + MAYBE_MISUSED_CFG, + meta.span, + "'feature' may be misspelled as 'features'", + "did you mean", + format!("feature = \"{val}\""), + Applicability::MaybeIncorrect, + ); + } + if let MetaItemKind::List(list) = &meta.kind { + check_nested_misused_cfg(cx, list); + // If this is not a list, then we check for `cfg(test)`. + } else if let Some(ident) = meta.ident() + && matches!(ident.name.as_str(), "tests" | "Test") + { + span_lint_and_sugg( + cx, + MAYBE_MISUSED_CFG, + meta.span, + &format!("'test' may be misspelled as '{}'", ident.name.as_str()), + "did you mean", + "test".to_string(), + Applicability::MaybeIncorrect, + ); + } + } + } +} diff --git a/clippy_lints/src/attrs/mismatched_target_os.rs b/clippy_lints/src/attrs/mismatched_target_os.rs new file mode 100644 index 00000000000..b1cc0a763c5 --- /dev/null +++ b/clippy_lints/src/attrs/mismatched_target_os.rs @@ -0,0 +1,90 @@ +use super::{Attribute, MISMATCHED_TARGET_OS}; +use clippy_utils::diagnostics::span_lint_and_then; +use rustc_ast::{MetaItemKind, NestedMetaItem}; +use rustc_errors::Applicability; +use rustc_lint::EarlyContext; +use rustc_span::{sym, Span}; + +static UNIX_SYSTEMS: &[&str] = &[ + "android", + "dragonfly", + "emscripten", + "freebsd", + "fuchsia", + "haiku", + "illumos", + "ios", + "l4re", + "linux", + "macos", + "netbsd", + "openbsd", + "redox", + "solaris", + "vxworks", +]; + +// NOTE: windows is excluded from the list because it's also a valid target family. +static NON_UNIX_SYSTEMS: &[&str] = &["hermit", "none", "wasi"]; + +pub(super) fn check(cx: &EarlyContext<'_>, attr: &Attribute) { + fn find_os(name: &str) -> Option<&'static str> { + UNIX_SYSTEMS + .iter() + .chain(NON_UNIX_SYSTEMS.iter()) + .find(|&&os| os == name) + .copied() + } + + fn is_unix(name: &str) -> bool { + UNIX_SYSTEMS.iter().any(|&os| os == name) + } + + fn find_mismatched_target_os(items: &[NestedMetaItem]) -> Vec<(&str, Span)> { + let mut mismatched = Vec::new(); + + for item in items { + if let NestedMetaItem::MetaItem(meta) = item { + match &meta.kind { + MetaItemKind::List(list) => { + mismatched.extend(find_mismatched_target_os(list)); + }, + MetaItemKind::Word => { + if let Some(ident) = meta.ident() + && let Some(os) = find_os(ident.name.as_str()) + { + mismatched.push((os, ident.span)); + } + }, + MetaItemKind::NameValue(..) => {}, + } + } + } + + mismatched + } + + if attr.has_name(sym::cfg) + && let Some(list) = attr.meta_item_list() + && let mismatched = find_mismatched_target_os(&list) + && !mismatched.is_empty() + { + let mess = "operating system used in target family position"; + + span_lint_and_then(cx, MISMATCHED_TARGET_OS, attr.span, mess, |diag| { + // Avoid showing the unix suggestion multiple times in case + // we have more than one mismatch for unix-like systems + let mut unix_suggested = false; + + for (os, span) in mismatched { + let sugg = format!("target_os = \"{os}\""); + diag.span_suggestion(span, "try", sugg, Applicability::MaybeIncorrect); + + if !unix_suggested && is_unix(os) { + diag.help("did you mean `unix`?"); + unix_suggested = true; + } + } + }); + } +} diff --git a/clippy_lints/src/attrs/mixed_attributes_style.rs b/clippy_lints/src/attrs/mixed_attributes_style.rs new file mode 100644 index 00000000000..c2e21cfd330 --- /dev/null +++ b/clippy_lints/src/attrs/mixed_attributes_style.rs @@ -0,0 +1,30 @@ +use super::MIXED_ATTRIBUTES_STYLE; +use clippy_utils::diagnostics::span_lint; +use rustc_ast::AttrStyle; +use rustc_lint::EarlyContext; + +pub(super) fn check(cx: &EarlyContext<'_>, item: &rustc_ast::Item) { + let mut has_outer = false; + let mut has_inner = false; + + for attr in &item.attrs { + if attr.span.from_expansion() { + continue; + } + match attr.style { + AttrStyle::Inner => has_inner = true, + AttrStyle::Outer => has_outer = true, + } + } + if !has_outer || !has_inner { + return; + } + let mut attrs_iter = item.attrs.iter().filter(|attr| !attr.span.from_expansion()); + let span = attrs_iter.next().unwrap().span; + span_lint( + cx, + MIXED_ATTRIBUTES_STYLE, + span.with_hi(attrs_iter.last().unwrap().span.hi()), + "item has both inner and outer attributes", + ); +} diff --git a/clippy_lints/src/attrs/mod.rs b/clippy_lints/src/attrs/mod.rs new file mode 100644 index 00000000000..c4c65d3248a --- /dev/null +++ b/clippy_lints/src/attrs/mod.rs @@ -0,0 +1,588 @@ +//! checks for attributes + +mod allow_attributes_without_reason; +mod blanket_clippy_restriction_lints; +mod deprecated_cfg_attr; +mod deprecated_semver; +mod empty_line_after; +mod inline_always; +mod maybe_misused_cfg; +mod mismatched_target_os; +mod mixed_attributes_style; +mod non_minimal_cfg; +mod should_panic_without_expect; +mod unnecessary_clippy_cfg; +mod useless_attribute; +mod utils; + +use clippy_config::msrvs::Msrv; +use rustc_ast::{Attribute, MetaItemKind, NestedMetaItem}; +use rustc_hir::{ImplItem, Item, ItemKind, TraitItem}; +use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass}; +use rustc_session::{declare_lint_pass, impl_lint_pass}; +use rustc_span::sym; +use utils::{is_lint_level, is_relevant_impl, is_relevant_item, is_relevant_trait}; + +declare_clippy_lint! { + /// ### What it does + /// Checks for items annotated with `#[inline(always)]`, + /// unless the annotated function is empty or simply panics. + /// + /// ### Why is this bad? + /// While there are valid uses of this annotation (and once + /// you know when to use it, by all means `allow` this lint), it's a common + /// newbie-mistake to pepper one's code with it. + /// + /// As a rule of thumb, before slapping `#[inline(always)]` on a function, + /// measure if that additional function call really affects your runtime profile + /// sufficiently to make up for the increase in compile time. + /// + /// ### Known problems + /// False positives, big time. This lint is meant to be + /// deactivated by everyone doing serious performance work. This means having + /// done the measurement. + /// + /// ### Example + /// ```ignore + /// #[inline(always)] + /// fn not_quite_hot_code(..) { ... } + /// ``` + #[clippy::version = "pre 1.29.0"] + pub INLINE_ALWAYS, + pedantic, + "use of `#[inline(always)]`" +} + +declare_clippy_lint! { + /// ### What it does + /// Checks for `extern crate` and `use` items annotated with + /// lint attributes. + /// + /// This lint permits lint attributes for lints emitted on the items themself. + /// For `use` items these lints are: + /// * deprecated + /// * unreachable_pub + /// * unused_imports + /// * clippy::enum_glob_use + /// * clippy::macro_use_imports + /// * clippy::wildcard_imports + /// + /// For `extern crate` items these lints are: + /// * `unused_imports` on items with `#[macro_use]` + /// + /// ### Why is this bad? + /// Lint attributes have no effect on crate imports. Most + /// likely a `!` was forgotten. + /// + /// ### Example + /// ```ignore + /// #[deny(dead_code)] + /// extern crate foo; + /// #[forbid(dead_code)] + /// use foo::bar; + /// ``` + /// + /// Use instead: + /// ```rust,ignore + /// #[allow(unused_imports)] + /// use foo::baz; + /// #[allow(unused_imports)] + /// #[macro_use] + /// extern crate baz; + /// ``` + #[clippy::version = "pre 1.29.0"] + pub USELESS_ATTRIBUTE, + correctness, + "use of lint attributes on `extern crate` items" +} + +declare_clippy_lint! { + /// ### What it does + /// Checks for `#[deprecated]` annotations with a `since` + /// field that is not a valid semantic version. Also allows "TBD" to signal + /// future deprecation. + /// + /// ### Why is this bad? + /// For checking the version of the deprecation, it must be + /// a valid semver. Failing that, the contained information is useless. + /// + /// ### Example + /// ```no_run + /// #[deprecated(since = "forever")] + /// fn something_else() { /* ... */ } + /// ``` + #[clippy::version = "pre 1.29.0"] + pub DEPRECATED_SEMVER, + correctness, + "use of `#[deprecated(since = \"x\")]` where x is not semver" +} + +declare_clippy_lint! { + /// ### What it does + /// Checks for empty lines after outer attributes + /// + /// ### Why is this bad? + /// Most likely the attribute was meant to be an inner attribute using a '!'. + /// If it was meant to be an outer attribute, then the following item + /// should not be separated by empty lines. + /// + /// ### Known problems + /// Can cause false positives. + /// + /// From the clippy side it's difficult to detect empty lines between an attributes and the + /// following item because empty lines and comments are not part of the AST. The parsing + /// currently works for basic cases but is not perfect. + /// + /// ### Example + /// ```no_run + /// #[allow(dead_code)] + /// + /// fn not_quite_good_code() { } + /// ``` + /// + /// Use instead: + /// ```no_run + /// // Good (as inner attribute) + /// #![allow(dead_code)] + /// + /// fn this_is_fine() { } + /// + /// // or + /// + /// // Good (as outer attribute) + /// #[allow(dead_code)] + /// fn this_is_fine_too() { } + /// ``` + #[clippy::version = "pre 1.29.0"] + pub EMPTY_LINE_AFTER_OUTER_ATTR, + nursery, + "empty line after outer attribute" +} + +declare_clippy_lint! { + /// ### What it does + /// Checks for empty lines after documentation comments. + /// + /// ### Why is this bad? + /// The documentation comment was most likely meant to be an inner attribute or regular comment. + /// If it was intended to be a documentation comment, then the empty line should be removed to + /// be more idiomatic. + /// + /// ### Known problems + /// Only detects empty lines immediately following the documentation. If the doc comment is followed + /// by an attribute and then an empty line, this lint will not trigger. Use `empty_line_after_outer_attr` + /// in combination with this lint to detect both cases. + /// + /// Does not detect empty lines after doc attributes (e.g. `#[doc = ""]`). + /// + /// ### Example + /// ```no_run + /// /// Some doc comment with a blank line after it. + /// + /// fn not_quite_good_code() { } + /// ``` + /// + /// Use instead: + /// ```no_run + /// /// Good (no blank line) + /// fn this_is_fine() { } + /// ``` + /// + /// ```no_run + /// // Good (convert to a regular comment) + /// + /// fn this_is_fine_too() { } + /// ``` + /// + /// ```no_run + /// //! Good (convert to a comment on an inner attribute) + /// + /// fn this_is_fine_as_well() { } + /// ``` + #[clippy::version = "1.70.0"] + pub EMPTY_LINE_AFTER_DOC_COMMENTS, + nursery, + "empty line after documentation comments" +} + +declare_clippy_lint! { + /// ### What it does + /// Checks for `warn`/`deny`/`forbid` attributes targeting the whole clippy::restriction category. + /// + /// ### Why is this bad? + /// Restriction lints sometimes are in contrast with other lints or even go against idiomatic rust. + /// These lints should only be enabled on a lint-by-lint basis and with careful consideration. + /// + /// ### Example + /// ```no_run + /// #![deny(clippy::restriction)] + /// ``` + /// + /// Use instead: + /// ```no_run + /// #![deny(clippy::as_conversions)] + /// ``` + #[clippy::version = "1.47.0"] + pub BLANKET_CLIPPY_RESTRICTION_LINTS, + suspicious, + "enabling the complete restriction group" +} + +declare_clippy_lint! { + /// ### What it does + /// Checks for `#[cfg_attr(rustfmt, rustfmt_skip)]` and suggests to replace it + /// with `#[rustfmt::skip]`. + /// + /// ### Why is this bad? + /// Since tool_attributes ([rust-lang/rust#44690](https://github.com/rust-lang/rust/issues/44690)) + /// are stable now, they should be used instead of the old `cfg_attr(rustfmt)` attributes. + /// + /// ### Known problems + /// This lint doesn't detect crate level inner attributes, because they get + /// processed before the PreExpansionPass lints get executed. See + /// [#3123](https://github.com/rust-lang/rust-clippy/pull/3123#issuecomment-422321765) + /// + /// ### Example + /// ```no_run + /// #[cfg_attr(rustfmt, rustfmt_skip)] + /// fn main() { } + /// ``` + /// + /// Use instead: + /// ```no_run + /// #[rustfmt::skip] + /// fn main() { } + /// ``` + #[clippy::version = "1.32.0"] + pub DEPRECATED_CFG_ATTR, + complexity, + "usage of `cfg_attr(rustfmt)` instead of tool attributes" +} + +declare_clippy_lint! { + /// ### What it does + /// Checks for cfg attributes having operating systems used in target family position. + /// + /// ### Why is this bad? + /// The configuration option will not be recognised and the related item will not be included + /// by the conditional compilation engine. + /// + /// ### Example + /// ```no_run + /// #[cfg(linux)] + /// fn conditional() { } + /// ``` + /// + /// Use instead: + /// ```no_run + /// # mod hidden { + /// #[cfg(target_os = "linux")] + /// fn conditional() { } + /// # } + /// + /// // or + /// + /// #[cfg(unix)] + /// fn conditional() { } + /// ``` + /// Check the [Rust Reference](https://doc.rust-lang.org/reference/conditional-compilation.html#target_os) for more details. + #[clippy::version = "1.45.0"] + pub MISMATCHED_TARGET_OS, + correctness, + "usage of `cfg(operating_system)` instead of `cfg(target_os = \"operating_system\")`" +} + +declare_clippy_lint! { + /// ### What it does + /// Checks for attributes that allow lints without a reason. + /// + /// (This requires the `lint_reasons` feature) + /// + /// ### Why is this bad? + /// Allowing a lint should always have a reason. This reason should be documented to + /// ensure that others understand the reasoning + /// + /// ### Example + /// ```no_run + /// #![feature(lint_reasons)] + /// + /// #![allow(clippy::some_lint)] + /// ``` + /// + /// Use instead: + /// ```no_run + /// #![feature(lint_reasons)] + /// + /// #![allow(clippy::some_lint, reason = "False positive rust-lang/rust-clippy#1002020")] + /// ``` + #[clippy::version = "1.61.0"] + pub ALLOW_ATTRIBUTES_WITHOUT_REASON, + restriction, + "ensures that all `allow` and `expect` attributes have a reason" +} + +declare_clippy_lint! { + /// ### What it does + /// Checks for `#[should_panic]` attributes without specifying the expected panic message. + /// + /// ### Why is this bad? + /// The expected panic message should be specified to ensure that the test is actually + /// panicking with the expected message, and not another unrelated panic. + /// + /// ### Example + /// ```no_run + /// fn random() -> i32 { 0 } + /// + /// #[should_panic] + /// #[test] + /// fn my_test() { + /// let _ = 1 / random(); + /// } + /// ``` + /// + /// Use instead: + /// ```no_run + /// fn random() -> i32 { 0 } + /// + /// #[should_panic = "attempt to divide by zero"] + /// #[test] + /// fn my_test() { + /// let _ = 1 / random(); + /// } + /// ``` + #[clippy::version = "1.74.0"] + pub SHOULD_PANIC_WITHOUT_EXPECT, + pedantic, + "ensures that all `should_panic` attributes specify its expected panic message" +} + +declare_clippy_lint! { + /// ### What it does + /// Checks for `any` and `all` combinators in `cfg` with only one condition. + /// + /// ### Why is this bad? + /// If there is only one condition, no need to wrap it into `any` or `all` combinators. + /// + /// ### Example + /// ```no_run + /// #[cfg(any(unix))] + /// pub struct Bar; + /// ``` + /// + /// Use instead: + /// ```no_run + /// #[cfg(unix)] + /// pub struct Bar; + /// ``` + #[clippy::version = "1.71.0"] + pub NON_MINIMAL_CFG, + style, + "ensure that all `cfg(any())` and `cfg(all())` have more than one condition" +} + +declare_clippy_lint! { + /// ### What it does + /// Checks for `#[cfg(features = "...")]` and suggests to replace it with + /// `#[cfg(feature = "...")]`. + /// + /// It also checks if `cfg(test)` was misspelled. + /// + /// ### Why is this bad? + /// Misspelling `feature` as `features` or `test` as `tests` can be sometimes hard to spot. It + /// may cause conditional compilation not work quietly. + /// + /// ### Example + /// ```no_run + /// #[cfg(features = "some-feature")] + /// fn conditional() { } + /// #[cfg(tests)] + /// mod tests { } + /// ``` + /// + /// Use instead: + /// ```no_run + /// #[cfg(feature = "some-feature")] + /// fn conditional() { } + /// #[cfg(test)] + /// mod tests { } + /// ``` + #[clippy::version = "1.69.0"] + pub MAYBE_MISUSED_CFG, + suspicious, + "prevent from misusing the wrong attr name" +} + +declare_clippy_lint! { + /// ### What it does + /// Checks for `#[cfg_attr(feature = "cargo-clippy", ...)]` and for + /// `#[cfg(feature = "cargo-clippy")]` and suggests to replace it with + /// `#[cfg_attr(clippy, ...)]` or `#[cfg(clippy)]`. + /// + /// ### Why is this bad? + /// This feature has been deprecated for years and shouldn't be used anymore. + /// + /// ### Example + /// ```no_run + /// #[cfg(feature = "cargo-clippy")] + /// struct Bar; + /// ``` + /// + /// Use instead: + /// ```no_run + /// #[cfg(clippy)] + /// struct Bar; + /// ``` + #[clippy::version = "1.78.0"] + pub DEPRECATED_CLIPPY_CFG_ATTR, + suspicious, + "usage of `cfg(feature = \"cargo-clippy\")` instead of `cfg(clippy)`" +} + +declare_clippy_lint! { + /// ### What it does + /// Checks for `#[cfg_attr(clippy, allow(clippy::lint))]` + /// and suggests to replace it with `#[allow(clippy::lint)]`. + /// + /// ### Why is this bad? + /// There is no reason to put clippy attributes behind a clippy `cfg` as they are not + /// run by anything else than clippy. + /// + /// ### Example + /// ```no_run + /// #![cfg_attr(clippy, allow(clippy::deprecated_cfg_attr))] + /// ``` + /// + /// Use instead: + /// ```no_run + /// #![allow(clippy::deprecated_cfg_attr)] + /// ``` + #[clippy::version = "1.78.0"] + pub UNNECESSARY_CLIPPY_CFG, + suspicious, + "usage of `cfg_attr(clippy, allow(clippy::lint))` instead of `allow(clippy::lint)`" +} + +declare_clippy_lint! { + /// ### What it does + /// Checks that an item has only one kind of attributes. + /// + /// ### Why is this bad? + /// Having both kinds of attributes makes it more complicated to read code. + /// + /// ### Example + /// ```no_run + /// #[cfg(linux)] + /// pub fn foo() { + /// #![cfg(windows)] + /// } + /// ``` + /// Use instead: + /// ```no_run + /// #[cfg(linux)] + /// #[cfg(windows)] + /// pub fn foo() { + /// } + /// ``` + #[clippy::version = "1.78.0"] + pub MIXED_ATTRIBUTES_STYLE, + suspicious, + "item has both inner and outer attributes" +} + +declare_lint_pass!(Attributes => [ + ALLOW_ATTRIBUTES_WITHOUT_REASON, + INLINE_ALWAYS, + DEPRECATED_SEMVER, + USELESS_ATTRIBUTE, + BLANKET_CLIPPY_RESTRICTION_LINTS, + SHOULD_PANIC_WITHOUT_EXPECT, +]); + +impl<'tcx> LateLintPass<'tcx> for Attributes { + fn check_crate(&mut self, cx: &LateContext<'tcx>) { + blanket_clippy_restriction_lints::check_command_line(cx); + } + + fn check_attribute(&mut self, cx: &LateContext<'tcx>, attr: &'tcx Attribute) { + if let Some(items) = &attr.meta_item_list() { + if let Some(ident) = attr.ident() { + if is_lint_level(ident.name, attr.id) { + blanket_clippy_restriction_lints::check(cx, ident.name, items); + } + if matches!(ident.name, sym::allow | sym::expect) { + allow_attributes_without_reason::check(cx, ident.name, items, attr); + } + if items.is_empty() || !attr.has_name(sym::deprecated) { + return; + } + for item in items { + if let NestedMetaItem::MetaItem(mi) = &item + && let MetaItemKind::NameValue(lit) = &mi.kind + && mi.has_name(sym::since) + { + deprecated_semver::check(cx, item.span(), lit); + } + } + } + } + if attr.has_name(sym::should_panic) { + should_panic_without_expect::check(cx, attr); + } + } + + fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { + let attrs = cx.tcx.hir().attrs(item.hir_id()); + if is_relevant_item(cx, item) { + inline_always::check(cx, item.span, item.ident.name, attrs); + } + match item.kind { + ItemKind::ExternCrate(..) | ItemKind::Use(..) => useless_attribute::check(cx, item, attrs), + _ => {}, + } + } + + fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>) { + if is_relevant_impl(cx, item) { + inline_always::check(cx, item.span, item.ident.name, cx.tcx.hir().attrs(item.hir_id())); + } + } + + fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) { + if is_relevant_trait(cx, item) { + inline_always::check(cx, item.span, item.ident.name, cx.tcx.hir().attrs(item.hir_id())); + } + } +} + +pub struct EarlyAttributes { + pub msrv: Msrv, +} + +impl_lint_pass!(EarlyAttributes => [ + DEPRECATED_CFG_ATTR, + MISMATCHED_TARGET_OS, + EMPTY_LINE_AFTER_OUTER_ATTR, + EMPTY_LINE_AFTER_DOC_COMMENTS, + NON_MINIMAL_CFG, + MAYBE_MISUSED_CFG, + DEPRECATED_CLIPPY_CFG_ATTR, + UNNECESSARY_CLIPPY_CFG, + MIXED_ATTRIBUTES_STYLE, +]); + +impl EarlyLintPass for EarlyAttributes { + fn check_item(&mut self, cx: &EarlyContext<'_>, item: &rustc_ast::Item) { + empty_line_after::check(cx, item); + mixed_attributes_style::check(cx, item); + } + + fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &Attribute) { + deprecated_cfg_attr::check(cx, attr, &self.msrv); + deprecated_cfg_attr::check_clippy(cx, attr); + mismatched_target_os::check(cx, attr); + non_minimal_cfg::check(cx, attr); + maybe_misused_cfg::check(cx, attr); + } + + extract_msrv_attr!(EarlyContext); +} diff --git a/clippy_lints/src/attrs/non_minimal_cfg.rs b/clippy_lints/src/attrs/non_minimal_cfg.rs new file mode 100644 index 00000000000..3fde7061585 --- /dev/null +++ b/clippy_lints/src/attrs/non_minimal_cfg.rs @@ -0,0 +1,49 @@ +use super::{Attribute, NON_MINIMAL_CFG}; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::source::snippet_opt; +use rustc_ast::{MetaItemKind, NestedMetaItem}; +use rustc_errors::Applicability; +use rustc_lint::EarlyContext; +use rustc_span::sym; + +pub(super) fn check(cx: &EarlyContext<'_>, attr: &Attribute) { + if attr.has_name(sym::cfg) + && let Some(items) = attr.meta_item_list() + { + check_nested_cfg(cx, &items); + } +} + +fn check_nested_cfg(cx: &EarlyContext<'_>, items: &[NestedMetaItem]) { + for item in items { + if let NestedMetaItem::MetaItem(meta) = item { + if !meta.has_name(sym::any) && !meta.has_name(sym::all) { + continue; + } + if let MetaItemKind::List(list) = &meta.kind { + check_nested_cfg(cx, list); + if list.len() == 1 { + span_lint_and_then( + cx, + NON_MINIMAL_CFG, + meta.span, + "unneeded sub `cfg` when there is only one condition", + |diag| { + if let Some(snippet) = snippet_opt(cx, list[0].span()) { + diag.span_suggestion(meta.span, "try", snippet, Applicability::MaybeIncorrect); + } + }, + ); + } else if list.is_empty() && meta.has_name(sym::all) { + span_lint_and_then( + cx, + NON_MINIMAL_CFG, + meta.span, + "unneeded sub `cfg` when there is no condition", + |_| {}, + ); + } + } + } + } +} diff --git a/clippy_lints/src/attrs/should_panic_without_expect.rs b/clippy_lints/src/attrs/should_panic_without_expect.rs new file mode 100644 index 00000000000..2d45cbbf621 --- /dev/null +++ b/clippy_lints/src/attrs/should_panic_without_expect.rs @@ -0,0 +1,54 @@ +use super::{Attribute, SHOULD_PANIC_WITHOUT_EXPECT}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use rustc_ast::token::{Token, TokenKind}; +use rustc_ast::tokenstream::TokenTree; +use rustc_ast::{AttrArgs, AttrArgsEq, AttrKind}; +use rustc_errors::Applicability; +use rustc_lint::LateContext; +use rustc_span::sym; + +pub(super) fn check(cx: &LateContext<'_>, attr: &Attribute) { + if let AttrKind::Normal(normal_attr) = &attr.kind { + if let AttrArgs::Eq(_, AttrArgsEq::Hir(_)) = &normal_attr.item.args { + // `#[should_panic = ".."]` found, good + return; + } + + if let AttrArgs::Delimited(args) = &normal_attr.item.args + && let mut tt_iter = args.tokens.trees() + && let Some(TokenTree::Token( + Token { + kind: TokenKind::Ident(sym::expected, _), + .. + }, + _, + )) = tt_iter.next() + && let Some(TokenTree::Token( + Token { + kind: TokenKind::Eq, .. + }, + _, + )) = tt_iter.next() + && let Some(TokenTree::Token( + Token { + kind: TokenKind::Literal(_), + .. + }, + _, + )) = tt_iter.next() + { + // `#[should_panic(expected = "..")]` found, good + return; + } + + span_lint_and_sugg( + cx, + SHOULD_PANIC_WITHOUT_EXPECT, + attr.span, + "#[should_panic] attribute without a reason", + "consider specifying the expected panic", + "#[should_panic(expected = /* panic message */)]".into(), + Applicability::HasPlaceholders, + ); + } +} diff --git a/clippy_lints/src/attrs/unnecessary_clippy_cfg.rs b/clippy_lints/src/attrs/unnecessary_clippy_cfg.rs new file mode 100644 index 00000000000..05da69636c6 --- /dev/null +++ b/clippy_lints/src/attrs/unnecessary_clippy_cfg.rs @@ -0,0 +1,70 @@ +use super::{Attribute, UNNECESSARY_CLIPPY_CFG}; +use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_sugg}; +use clippy_utils::source::snippet_opt; +use rustc_ast::AttrStyle; +use rustc_errors::Applicability; +use rustc_lint::{EarlyContext, Level}; +use rustc_span::sym; + +pub(super) fn check( + cx: &EarlyContext<'_>, + cfg_attr: &rustc_ast::MetaItem, + behind_cfg_attr: &rustc_ast::MetaItem, + attr: &Attribute, +) { + if cfg_attr.has_name(sym::clippy) + && let Some(ident) = behind_cfg_attr.ident() + && Level::from_symbol(ident.name, Some(attr.id)).is_some() + && let Some(items) = behind_cfg_attr.meta_item_list() + { + let nb_items = items.len(); + let mut clippy_lints = Vec::with_capacity(items.len()); + for item in items { + if let Some(meta_item) = item.meta_item() + && let [part1, _] = meta_item.path.segments.as_slice() + && part1.ident.name == sym::clippy + { + clippy_lints.push(item.span()); + } + } + if clippy_lints.is_empty() { + return; + } + if nb_items == clippy_lints.len() { + if let Some(snippet) = snippet_opt(cx, behind_cfg_attr.span) { + span_lint_and_sugg( + cx, + UNNECESSARY_CLIPPY_CFG, + attr.span, + "no need to put clippy lints behind a `clippy` cfg", + "replace with", + format!( + "#{}[{}]", + if attr.style == AttrStyle::Inner { "!" } else { "" }, + snippet + ), + Applicability::MachineApplicable, + ); + } + } else { + let snippet = clippy_lints + .iter() + .filter_map(|sp| snippet_opt(cx, *sp)) + .collect::>() + .join(","); + span_lint_and_note( + cx, + UNNECESSARY_CLIPPY_CFG, + clippy_lints, + "no need to put clippy lints behind a `clippy` cfg", + None, + &format!( + "write instead: `#{}[{}({})]`", + if attr.style == AttrStyle::Inner { "!" } else { "" }, + ident.name, + snippet + ), + ); + } + } +} diff --git a/clippy_lints/src/attrs/useless_attribute.rs b/clippy_lints/src/attrs/useless_attribute.rs new file mode 100644 index 00000000000..7575f502a7c --- /dev/null +++ b/clippy_lints/src/attrs/useless_attribute.rs @@ -0,0 +1,73 @@ +use super::utils::{extract_clippy_lint, is_lint_level, is_word}; +use super::{Attribute, USELESS_ATTRIBUTE}; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::source::{first_line_of_span, snippet_opt}; +use rustc_errors::Applicability; +use rustc_hir::{Item, ItemKind}; +use rustc_lint::{LateContext, LintContext}; +use rustc_middle::lint::in_external_macro; +use rustc_span::sym; + +pub(super) fn check(cx: &LateContext<'_>, item: &Item<'_>, attrs: &[Attribute]) { + let skip_unused_imports = attrs.iter().any(|attr| attr.has_name(sym::macro_use)); + + for attr in attrs { + if in_external_macro(cx.sess(), attr.span) { + return; + } + if let Some(lint_list) = &attr.meta_item_list() { + if attr.ident().map_or(false, |ident| is_lint_level(ident.name, attr.id)) { + for lint in lint_list { + match item.kind { + ItemKind::Use(..) => { + if is_word(lint, sym::unused_imports) + || is_word(lint, sym::deprecated) + || is_word(lint, sym!(unreachable_pub)) + || is_word(lint, sym!(unused)) + || is_word(lint, sym!(unused_import_braces)) + || extract_clippy_lint(lint).map_or(false, |s| { + matches!( + s.as_str(), + "wildcard_imports" + | "enum_glob_use" + | "redundant_pub_crate" + | "macro_use_imports" + | "unsafe_removed_from_name" + | "module_name_repetitions" + | "single_component_path_imports" + ) + }) + { + return; + } + }, + ItemKind::ExternCrate(..) => { + if is_word(lint, sym::unused_imports) && skip_unused_imports { + return; + } + if is_word(lint, sym!(unused_extern_crates)) { + return; + } + }, + _ => {}, + } + } + let line_span = first_line_of_span(cx, attr.span); + + if let Some(mut sugg) = snippet_opt(cx, line_span) { + if sugg.contains("#[") { + span_lint_and_then(cx, USELESS_ATTRIBUTE, line_span, "useless lint attribute", |diag| { + sugg = sugg.replacen("#[", "#![", 1); + diag.span_suggestion( + line_span, + "if you just forgot a `!`, use", + sugg, + Applicability::MaybeIncorrect, + ); + }); + } + } + } + } + } +} diff --git a/clippy_lints/src/attrs/utils.rs b/clippy_lints/src/attrs/utils.rs new file mode 100644 index 00000000000..9b36cc00444 --- /dev/null +++ b/clippy_lints/src/attrs/utils.rs @@ -0,0 +1,87 @@ +use clippy_utils::macros::{is_panic, macro_backtrace}; +use rustc_ast::{AttrId, NestedMetaItem}; +use rustc_hir::{ + Block, Expr, ExprKind, ImplItem, ImplItemKind, Item, ItemKind, StmtKind, TraitFn, TraitItem, TraitItemKind, +}; +use rustc_lint::{LateContext, Level}; +use rustc_middle::ty; +use rustc_span::sym; +use rustc_span::symbol::Symbol; + +pub(super) fn is_word(nmi: &NestedMetaItem, expected: Symbol) -> bool { + if let NestedMetaItem::MetaItem(mi) = &nmi { + mi.is_word() && mi.has_name(expected) + } else { + false + } +} + +pub(super) fn is_lint_level(symbol: Symbol, attr_id: AttrId) -> bool { + Level::from_symbol(symbol, Some(attr_id)).is_some() +} + +pub(super) fn is_relevant_item(cx: &LateContext<'_>, item: &Item<'_>) -> bool { + if let ItemKind::Fn(_, _, eid) = item.kind { + is_relevant_expr(cx, cx.tcx.typeck_body(eid), cx.tcx.hir().body(eid).value) + } else { + true + } +} + +pub(super) fn is_relevant_impl(cx: &LateContext<'_>, item: &ImplItem<'_>) -> bool { + match item.kind { + ImplItemKind::Fn(_, eid) => is_relevant_expr(cx, cx.tcx.typeck_body(eid), cx.tcx.hir().body(eid).value), + _ => false, + } +} + +pub(super) fn is_relevant_trait(cx: &LateContext<'_>, item: &TraitItem<'_>) -> bool { + match item.kind { + TraitItemKind::Fn(_, TraitFn::Required(_)) => true, + TraitItemKind::Fn(_, TraitFn::Provided(eid)) => { + is_relevant_expr(cx, cx.tcx.typeck_body(eid), cx.tcx.hir().body(eid).value) + }, + _ => false, + } +} + +fn is_relevant_block(cx: &LateContext<'_>, typeck_results: &ty::TypeckResults<'_>, block: &Block<'_>) -> bool { + block.stmts.first().map_or( + block + .expr + .as_ref() + .map_or(false, |e| is_relevant_expr(cx, typeck_results, e)), + |stmt| match &stmt.kind { + StmtKind::Local(_) => true, + StmtKind::Expr(expr) | StmtKind::Semi(expr) => is_relevant_expr(cx, typeck_results, expr), + StmtKind::Item(_) => false, + }, + ) +} + +fn is_relevant_expr(cx: &LateContext<'_>, typeck_results: &ty::TypeckResults<'_>, expr: &Expr<'_>) -> bool { + if macro_backtrace(expr.span).last().map_or(false, |macro_call| { + is_panic(cx, macro_call.def_id) || cx.tcx.item_name(macro_call.def_id) == sym::unreachable + }) { + return false; + } + match &expr.kind { + ExprKind::Block(block, _) => is_relevant_block(cx, typeck_results, block), + ExprKind::Ret(Some(e)) => is_relevant_expr(cx, typeck_results, e), + ExprKind::Ret(None) | ExprKind::Break(_, None) => false, + _ => true, + } +} + +/// Returns the lint name if it is clippy lint. +pub(super) fn extract_clippy_lint(lint: &NestedMetaItem) -> Option { + if let Some(meta_item) = lint.meta_item() + && meta_item.path.segments.len() > 1 + && let tool_name = meta_item.path.segments[0].ident + && tool_name.name == sym::clippy + { + let lint_name = meta_item.path.segments.last().unwrap().ident.name; + return Some(lint_name); + } + None +} diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs index 0d66f2d644d..a474356608f 100644 --- a/clippy_lints/src/booleans.rs +++ b/clippy_lints/src/booleans.rs @@ -88,7 +88,6 @@ fn check_fn( fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { match expr.kind { - ExprKind::Unary(UnOp::Not, sub) => check_inverted_condition(cx, expr.span, sub), // This check the case where an element in a boolean comparison is inverted, like: // // ``` @@ -119,27 +118,6 @@ fn bin_op_eq_str(op: BinOpKind) -> Option<&'static str> { } } -fn check_inverted_condition(cx: &LateContext<'_>, expr_span: Span, sub_expr: &Expr<'_>) { - if !expr_span.from_expansion() - && let ExprKind::Binary(op, left, right) = sub_expr.kind - && let Some(left) = snippet_opt(cx, left.span) - && let Some(right) = snippet_opt(cx, right.span) - { - let Some(op) = inverted_bin_op_eq_str(op.node) else { - return; - }; - span_lint_and_sugg( - cx, - NONMINIMAL_BOOL, - expr_span, - "this boolean expression can be simplified", - "try", - format!("{left} {op} {right}",), - Applicability::MachineApplicable, - ); - } -} - fn check_inverted_bool_in_condition( cx: &LateContext<'_>, expr_span: Span, @@ -148,8 +126,8 @@ fn check_inverted_bool_in_condition( right: &Expr<'_>, ) { if expr_span.from_expansion() - && (!cx.typeck_results().node_types()[left.hir_id].is_bool() - || !cx.typeck_results().node_types()[right.hir_id].is_bool()) + || !cx.typeck_results().node_types()[left.hir_id].is_bool() + || !cx.typeck_results().node_types()[right.hir_id].is_bool() { return; } diff --git a/clippy_lints/src/casts/unnecessary_cast.rs b/clippy_lints/src/casts/unnecessary_cast.rs index cc513d46bf4..08341ff32f3 100644 --- a/clippy_lints/src/casts/unnecessary_cast.rs +++ b/clippy_lints/src/casts/unnecessary_cast.rs @@ -151,13 +151,24 @@ pub(super) fn check<'tcx>( return false; } + // If the whole cast expression is a unary expression (`(*x as T)`) or an addressof + // expression (`(&x as T)`), then not surrounding the suggestion into a block risks us + // changing the precedence of operators if the cast expression is followed by an operation + // with higher precedence than the unary operator (`(*x as T).foo()` would become + // `*x.foo()`, which changes what the `*` applies on). + // The same is true if the expression encompassing the cast expression is a unary + // expression or an addressof expression. + let needs_block = matches!(cast_expr.kind, ExprKind::Unary(..) | ExprKind::AddrOf(..)) + || get_parent_expr(cx, expr) + .map_or(false, |e| matches!(e.kind, ExprKind::Unary(..) | ExprKind::AddrOf(..))); + span_lint_and_sugg( cx, UNNECESSARY_CAST, expr.span, &format!("casting to the same type is unnecessary (`{cast_from}` -> `{cast_to}`)"), "try", - if get_parent_expr(cx, expr).map_or(false, |e| matches!(e.kind, ExprKind::AddrOf(..))) { + if needs_block { format!("{{ {cast_str} }}") } else { cast_str diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index fb3ae2457e3..2b324f5f96e 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -47,6 +47,7 @@ crate::asm_syntax::INLINE_ASM_X86_INTEL_SYNTAX_INFO, crate::assertions_on_constants::ASSERTIONS_ON_CONSTANTS_INFO, crate::assertions_on_result_states::ASSERTIONS_ON_RESULT_STATES_INFO, + crate::assigning_clones::ASSIGNING_CLONES_INFO, crate::async_yields_async::ASYNC_YIELDS_ASYNC_INFO, crate::attrs::ALLOW_ATTRIBUTES_WITHOUT_REASON_INFO, crate::attrs::BLANKET_CLIPPY_RESTRICTION_LINTS_INFO, @@ -58,6 +59,7 @@ crate::attrs::INLINE_ALWAYS_INFO, crate::attrs::MAYBE_MISUSED_CFG_INFO, crate::attrs::MISMATCHED_TARGET_OS_INFO, + crate::attrs::MIXED_ATTRIBUTES_STYLE_INFO, crate::attrs::NON_MINIMAL_CFG_INFO, crate::attrs::SHOULD_PANIC_WITHOUT_EXPECT_INFO, crate::attrs::UNNECESSARY_CLIPPY_CFG_INFO, diff --git a/clippy_lints/src/derive.rs b/clippy_lints/src/derive.rs index 6144ec7b3ca..f0f2c7d6658 100644 --- a/clippy_lints/src/derive.rs +++ b/clippy_lints/src/derive.rs @@ -451,8 +451,8 @@ fn check_partial_eq_without_eq<'tcx>(cx: &LateContext<'tcx>, span: Span, trait_r && let Some(def_id) = trait_ref.trait_def_id() && cx.tcx.is_diagnostic_item(sym::PartialEq, def_id) && !has_non_exhaustive_attr(cx.tcx, *adt) + && !ty_implements_eq_trait(cx.tcx, ty, eq_trait_def_id) && let param_env = param_env_for_derived_eq(cx.tcx, adt.did(), eq_trait_def_id) - && !implements_trait_with_env(cx.tcx, param_env, ty, eq_trait_def_id, None, &[]) // If all of our fields implement `Eq`, we can implement `Eq` too && adt .all_fields() @@ -471,6 +471,10 @@ fn check_partial_eq_without_eq<'tcx>(cx: &LateContext<'tcx>, span: Span, trait_r } } +fn ty_implements_eq_trait<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, eq_trait_id: DefId) -> bool { + tcx.non_blanket_impls_for_ty(eq_trait_id, ty).next().is_some() +} + /// Creates the `ParamEnv` used for the give type's derived `Eq` impl. fn param_env_for_derived_eq(tcx: TyCtxt<'_>, did: DefId, eq_trait_id: DefId) -> ParamEnv<'_> { // Initial map from generic index to param def. diff --git a/clippy_lints/src/doc/markdown.rs b/clippy_lints/src/doc/markdown.rs index a58219c2946..d2f14756591 100644 --- a/clippy_lints/src/doc/markdown.rs +++ b/clippy_lints/src/doc/markdown.rs @@ -8,7 +8,7 @@ use crate::doc::DOC_MARKDOWN; -pub fn check(cx: &LateContext<'_>, valid_idents: &FxHashSet, text: &str, span: Span) { +pub fn check(cx: &LateContext<'_>, valid_idents: &FxHashSet, text: &str, span: Span, code_level: isize) { for orig_word in text.split(|c: char| c.is_whitespace() || c == '\'') { // Trim punctuation as in `some comment (see foo::bar).` // ^^ @@ -46,11 +46,11 @@ pub fn check(cx: &LateContext<'_>, valid_idents: &FxHashSet, text: &str, span.parent(), ); - check_word(cx, word, span); + check_word(cx, word, span, code_level); } } -fn check_word(cx: &LateContext<'_>, word: &str, span: Span) { +fn check_word(cx: &LateContext<'_>, word: &str, span: Span, code_level: isize) { /// Checks if a string is upper-camel-case, i.e., starts with an uppercase and /// contains at least two uppercase letters (`Clippy` is ok) and one lower-case /// letter (`NASA` is ok). @@ -60,7 +60,14 @@ fn is_camel_case(s: &str) -> bool { return false; } - let s = s.strip_suffix('s').unwrap_or(s); + let s = if let Some(prefix) = s.strip_suffix("es") + && prefix.chars().all(|c| c.is_ascii_uppercase()) + && matches!(prefix.chars().last(), Some('S' | 'X')) + { + prefix + } else { + s.strip_suffix('s').unwrap_or(s) + }; s.chars().all(char::is_alphanumeric) && s.chars().filter(|&c| c.is_uppercase()).take(2).count() > 1 @@ -90,7 +97,7 @@ fn has_hyphen(s: &str) -> bool { } // We assume that mixed-case words are not meant to be put inside backticks. (Issue #2343) - if has_underscore(word) && has_hyphen(word) { + if code_level > 0 || (has_underscore(word) && has_hyphen(word)) { return; } diff --git a/clippy_lints/src/doc/mod.rs b/clippy_lints/src/doc/mod.rs index 9af34c3a7bf..003d26b7b89 100644 --- a/clippy_lints/src/doc/mod.rs +++ b/clippy_lints/src/doc/mod.rs @@ -599,10 +599,19 @@ fn check_doc<'a, Events: Iterator, Range, Range)> = Vec::new(); + let mut text_to_check: Vec<(CowStr<'_>, Range, isize)> = Vec::new(); let mut paragraph_range = 0..0; + let mut code_level = 0; + for (event, range) in events { match event { + Html(tag) => { + if tag.starts_with(" { in_code = true; if let CodeBlockKind::Fenced(lang) = kind { @@ -652,16 +661,15 @@ fn check_doc<'a, Events: Iterator, Range (), // We don't care about other tags - Html(_html) => (), // HTML is weird, just ignore it SoftBreak | HardBreak | TaskListMarker(_) | Code(_) | Rule => (), FootnoteReference(text) | Text(text) => { paragraph_range.end = range.end; @@ -694,7 +702,7 @@ fn check_doc<'a, Events: Iterator, Range &'static str { } } +/// Details on an expression checking whether a map contains a key. +/// +/// For instance, with the following: +/// ```ignore +/// !!!self.the_map.contains_key("the_key") +/// ``` +/// +/// - `negated` will be set to `true` (the 3 `!` negate the condition) +/// - `map` will be the `self.the_map` expression +/// - `key` will be the `"the_key"` expression struct ContainsExpr<'tcx> { + /// Whether the check for `contains_key` was negated. negated: bool, + /// The map on which the check is performed. map: &'tcx Expr<'tcx>, + /// The key that is checked to be contained. key: &'tcx Expr<'tcx>, + /// The context of the whole condition expression. call_ctxt: SyntaxContext, } + +/// Inspect the given expression and return details about the `contains_key` check. +/// +/// If the given expression is not a `contains_key` check against a `BTreeMap` or a `HashMap`, +/// return `None`. fn try_parse_contains<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Option<(MapType, ContainsExpr<'tcx>)> { let mut negated = false; let expr = peel_hir_expr_while(expr, |e| match e.kind { @@ -229,6 +248,7 @@ fn try_parse_contains<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Optio }, _ => None, }); + match expr.kind { ExprKind::MethodCall( _, @@ -261,11 +281,28 @@ fn try_parse_contains<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Optio } } +/// Details on an expression inserting a key into a map. +/// +/// For instance, on the following: +/// ```ignore +/// self.the_map.insert("the_key", 3 + 4); +/// ``` +/// +/// - `map` will be the `self.the_map` expression +/// - `key` will be the `"the_key"` expression +/// - `value` will be the `3 + 4` expression struct InsertExpr<'tcx> { + /// The map into which the insertion is performed. map: &'tcx Expr<'tcx>, + /// The key at which to insert. key: &'tcx Expr<'tcx>, + /// The value to insert. value: &'tcx Expr<'tcx>, } + +/// Inspect the given expression and return details about the `insert` call. +/// +/// If the given expression is not an `insert` call into a `BTreeMap` or a `HashMap`, return `None`. fn try_parse_insert<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option> { if let ExprKind::MethodCall(_, map, [key, value], _) = expr.kind { let id = cx.typeck_results().type_dependent_def_id(expr.hir_id)?; @@ -298,7 +335,7 @@ struct Insertion<'tcx> { value: &'tcx Expr<'tcx>, } -/// This visitor needs to do a multiple things: +/// This visitor needs to do multiple things: /// * Find all usages of the map. An insertion can only be made before any other usages of the map. /// * Determine if there's an insertion using the same key. There's no need for the entry api /// otherwise. @@ -346,7 +383,7 @@ fn visit_cond_arm(&mut self, e: &'tcx Expr<'_>) -> bool { res } - /// Visits an expression which is not itself in a tail position, but other sibling expressions + /// Visit an expression which is not itself in a tail position, but other sibling expressions /// may be. e.g. if conditions fn visit_non_tail_expr(&mut self, e: &'tcx Expr<'_>) { let in_tail_pos = self.in_tail_pos; @@ -354,6 +391,19 @@ fn visit_non_tail_expr(&mut self, e: &'tcx Expr<'_>) { self.visit_expr(e); self.in_tail_pos = in_tail_pos; } + + /// Visit the key and value expression of an insert expression. + /// There may not be uses of the map in either of those two either. + fn visit_insert_expr_arguments(&mut self, e: &InsertExpr<'tcx>) { + let in_tail_pos = self.in_tail_pos; + let allow_insert_closure = self.allow_insert_closure; + let is_single_insert = self.is_single_insert; + walk_expr(self, e.key); + walk_expr(self, e.value); + self.in_tail_pos = in_tail_pos; + self.allow_insert_closure = allow_insert_closure; + self.is_single_insert = is_single_insert; + } } impl<'tcx> Visitor<'tcx> for InsertSearcher<'_, 'tcx> { fn visit_stmt(&mut self, stmt: &'tcx Stmt<'_>) { @@ -425,6 +475,7 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { match try_parse_insert(self.cx, expr) { Some(insert_expr) if SpanlessEq::new(self.cx).eq_expr(self.map, insert_expr.map) => { + self.visit_insert_expr_arguments(&insert_expr); // Multiple inserts, inserts with a different key, and inserts from a macro can't use the entry api. if self.is_map_used || !SpanlessEq::new(self.cx).eq_expr(self.key, insert_expr.key) diff --git a/clippy_lints/src/let_underscore.rs b/clippy_lints/src/let_underscore.rs index 606c2ed72be..0ea53c39280 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_from_proc_macro, is_must_use_func_call, paths}; -use rustc_hir::{Local, PatKind}; +use rustc_hir::{Local, LocalSource, PatKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{GenericArgKind, IsSuggestable}; @@ -139,7 +139,8 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { fn check_local(&mut self, cx: &LateContext<'tcx>, local: &Local<'tcx>) { - if !in_external_macro(cx.tcx.sess, local.span) + if matches!(local.source, LocalSource::Normal) + && !in_external_macro(cx.tcx.sess, local.span) && let PatKind::Wild = local.pat.kind && let Some(init) = local.init { diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 76e75968314..b930175c4d8 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -80,6 +80,7 @@ mod asm_syntax; mod assertions_on_constants; mod assertions_on_result_states; +mod assigning_clones; mod async_yields_async; mod attrs; mod await_holding_invalid; @@ -1118,6 +1119,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_late_pass(move |_| Box::new(incompatible_msrv::IncompatibleMsrv::new(msrv()))); store.register_late_pass(|_| Box::new(to_string_trait_impl::ToStringTraitImpl)); store.register_early_pass(|| Box::new(multiple_bound_locations::MultipleBoundLocations)); + store.register_late_pass(|_| Box::new(assigning_clones::AssigningClones)); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/clippy_lints/src/loops/manual_memcpy.rs b/clippy_lints/src/loops/manual_memcpy.rs index 58f713d8187..18f799e875a 100644 --- a/clippy_lints/src/loops/manual_memcpy.rs +++ b/clippy_lints/src/loops/manual_memcpy.rs @@ -3,6 +3,7 @@ use clippy_utils::source::snippet; use clippy_utils::sugg::Sugg; use clippy_utils::ty::is_copy; +use clippy_utils::usage::local_used_in; use clippy_utils::{get_enclosing_block, higher, path_to_local, sugg}; use rustc_ast::ast; use rustc_errors::Applicability; @@ -63,8 +64,9 @@ pub(super) fn check<'tcx>( && get_slice_like_element_ty(cx, cx.typeck_results().expr_ty(base_right)).is_some() && let Some((start_left, offset_left)) = get_details_from_idx(cx, idx_left, &starts) && let Some((start_right, offset_right)) = get_details_from_idx(cx, idx_right, &starts) - - // Source and destination must be different + && !local_used_in(cx, canonical_id, base_left) + && !local_used_in(cx, canonical_id, base_right) + // Source and destination must be different && path_to_local(base_left) != path_to_local(base_right) { Some(( diff --git a/clippy_lints/src/matches/significant_drop_in_scrutinee.rs b/clippy_lints/src/matches/significant_drop_in_scrutinee.rs index 69f86836775..b770ad0ddb5 100644 --- a/clippy_lints/src/matches/significant_drop_in_scrutinee.rs +++ b/clippy_lints/src/matches/significant_drop_in_scrutinee.rs @@ -37,12 +37,7 @@ pub(super) fn check<'tcx>( } } -fn set_diagnostic<'tcx>( - diag: &mut Diag<'_, ()>, - cx: &LateContext<'tcx>, - expr: &'tcx Expr<'tcx>, - found: FoundSigDrop, -) { +fn set_diagnostic<'tcx>(diag: &mut Diag<'_, ()>, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, found: FoundSigDrop) { if found.lint_suggestion == LintSuggestion::MoveAndClone { // If our suggestion is to move and clone, then we want to leave it to the user to // decide how to address this lint, since it may be that cloning is inappropriate. diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index adb696ad509..8a24ccea3a1 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3875,6 +3875,7 @@ } declare_clippy_lint! { + /// ### What it does /// Checks for usage of `option.map(f).unwrap_or_default()` and `result.map(f).unwrap_or_default()` where f is a function or closure that returns the `bool` type. /// /// ### Why is this bad? @@ -3981,6 +3982,7 @@ } declare_clippy_lint! { + /// ### What it does /// Checks for the manual creation of C strings (a string with a `NUL` byte at the end), either /// through one of the `CStr` constructor functions, or more plainly by calling `.as_ptr()` /// on a (byte) string literal with a hardcoded `\0` byte at the end. diff --git a/clippy_lints/src/operators/identity_op.rs b/clippy_lints/src/operators/identity_op.rs index f671517c134..0879dcd9bcd 100644 --- a/clippy_lints/src/operators/identity_op.rs +++ b/clippy_lints/src/operators/identity_op.rs @@ -42,7 +42,7 @@ pub(crate) fn check<'tcx>( match op { BinOpKind::Add | BinOpKind::BitOr | BinOpKind::BitXor => { - check_op( + let _ = check_op( cx, left, 0, @@ -50,8 +50,7 @@ pub(crate) fn check<'tcx>( peeled_right_span, needs_parenthesis(cx, expr, right), right_is_coerced_to_value, - ); - check_op( + ) || check_op( cx, right, 0, @@ -62,7 +61,7 @@ pub(crate) fn check<'tcx>( ); }, BinOpKind::Shl | BinOpKind::Shr | BinOpKind::Sub => { - check_op( + let _ = check_op( cx, right, 0, @@ -73,7 +72,7 @@ pub(crate) fn check<'tcx>( ); }, BinOpKind::Mul => { - check_op( + let _ = check_op( cx, left, 1, @@ -81,8 +80,18 @@ pub(crate) fn check<'tcx>( peeled_right_span, needs_parenthesis(cx, expr, right), right_is_coerced_to_value, - ); - check_op( + ) || check_op( + cx, + right, + 1, + expr.span, + peeled_left_span, + Parens::Unneeded, + left_is_coerced_to_value, + ); + }, + BinOpKind::Div => { + let _ = check_op( cx, right, 1, @@ -92,17 +101,8 @@ pub(crate) fn check<'tcx>( left_is_coerced_to_value, ); }, - BinOpKind::Div => check_op( - cx, - right, - 1, - expr.span, - peeled_left_span, - Parens::Unneeded, - left_is_coerced_to_value, - ), BinOpKind::BitAnd => { - check_op( + let _ = check_op( cx, left, -1, @@ -110,8 +110,7 @@ pub(crate) fn check<'tcx>( peeled_right_span, needs_parenthesis(cx, expr, right), right_is_coerced_to_value, - ); - check_op( + ) || check_op( cx, right, -1, @@ -201,12 +200,12 @@ fn check_remainder(cx: &LateContext<'_>, left: &Expr<'_>, right: &Expr<'_>, span } } -fn check_op(cx: &LateContext<'_>, e: &Expr<'_>, m: i8, span: Span, arg: Span, parens: Parens, is_erased: bool) { +fn check_op(cx: &LateContext<'_>, e: &Expr<'_>, m: i8, span: Span, arg: Span, parens: Parens, is_erased: bool) -> bool { if let Some(Constant::Int(v)) = constant_simple(cx, cx.typeck_results(), e).map(Constant::peel_refs) { let check = match *cx.typeck_results().expr_ty(e).peel_refs().kind() { ty::Int(ity) => unsext(cx.tcx, -1_i128, ity), ty::Uint(uty) => clip(cx.tcx, !0, uty), - _ => return, + _ => return false, }; if match m { 0 => v == 0, @@ -215,8 +214,10 @@ fn check_op(cx: &LateContext<'_>, e: &Expr<'_>, m: i8, span: Span, arg: Span, pa _ => unreachable!(), } { span_ineffective_operation(cx, span, arg, parens, is_erased); + return true; } } + false } fn span_ineffective_operation( diff --git a/clippy_lints/src/operators/misrefactored_assign_op.rs b/clippy_lints/src/operators/misrefactored_assign_op.rs index fecc5a8578e..311cbd050a1 100644 --- a/clippy_lints/src/operators/misrefactored_assign_op.rs +++ b/clippy_lints/src/operators/misrefactored_assign_op.rs @@ -21,9 +21,8 @@ pub(super) fn check<'tcx>( // lhs op= l op r if eq_expr_value(cx, lhs, l) { lint_misrefactored_assign_op(cx, expr, op, rhs, lhs, r); - } - // lhs op= l commutative_op r - if is_commutative(op) && eq_expr_value(cx, lhs, r) { + } else if is_commutative(op) && eq_expr_value(cx, lhs, r) { + // lhs op= l commutative_op r lint_misrefactored_assign_op(cx, expr, op, rhs, lhs, l); } } diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs index 1df2d5e4602..cf7f730140c 100644 --- a/clippy_lints/src/question_mark.rs +++ b/clippy_lints/src/question_mark.rs @@ -203,109 +203,107 @@ fn expr_return_none_or_err( } } +/// Checks if the given expression on the given context matches the following structure: +/// +/// ```ignore +/// if option.is_none() { +/// return None; +/// } +/// ``` +/// +/// ```ignore +/// if result.is_err() { +/// return result; +/// } +/// ``` +/// +/// If it matches, it will suggest to use the question mark operator instead +fn check_is_none_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) { + if let Some(higher::If { cond, then, r#else }) = higher::If::hir(expr) + && !is_else_clause(cx.tcx, expr) + && let ExprKind::MethodCall(segment, caller, ..) = &cond.kind + && let caller_ty = cx.typeck_results().expr_ty(caller) + && let if_block = IfBlockType::IfIs(caller, caller_ty, segment.ident.name, then) + && (is_early_return(sym::Option, cx, &if_block) || is_early_return(sym::Result, cx, &if_block)) + { + let mut applicability = Applicability::MachineApplicable; + let receiver_str = snippet_with_applicability(cx, caller.span, "..", &mut applicability); + let by_ref = !caller_ty.is_copy_modulo_regions(cx.tcx, cx.param_env) + && !matches!(caller.kind, ExprKind::Call(..) | ExprKind::MethodCall(..)); + let sugg = if let Some(else_inner) = r#else { + if eq_expr_value(cx, caller, peel_blocks(else_inner)) { + format!("Some({receiver_str}?)") + } else { + return; + } + } else { + format!("{receiver_str}{}?;", if by_ref { ".as_ref()" } else { "" }) + }; + + span_lint_and_sugg( + cx, + QUESTION_MARK, + expr.span, + "this block may be rewritten with the `?` operator", + "replace it with", + sugg, + applicability, + ); + } +} + +fn check_if_let_some_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) { + if let Some(higher::IfLet { + let_pat, + let_expr, + if_then, + if_else, + .. + }) = higher::IfLet::hir(cx, expr) + && !is_else_clause(cx.tcx, expr) + && let PatKind::TupleStruct(ref path1, [field], ddpos) = let_pat.kind + && ddpos.as_opt_usize().is_none() + && let PatKind::Binding(BindingAnnotation(by_ref, _), bind_id, ident, None) = field.kind + && let caller_ty = cx.typeck_results().expr_ty(let_expr) + && let if_block = IfBlockType::IfLet( + cx.qpath_res(path1, let_pat.hir_id), + caller_ty, + ident.name, + let_expr, + if_then, + if_else, + ) + && ((is_early_return(sym::Option, cx, &if_block) && path_to_local_id(peel_blocks(if_then), bind_id)) + || is_early_return(sym::Result, cx, &if_block)) + && if_else + .map(|e| eq_expr_value(cx, let_expr, peel_blocks(e))) + .filter(|e| *e) + .is_none() + { + let mut applicability = Applicability::MachineApplicable; + let receiver_str = snippet_with_applicability(cx, let_expr.span, "..", &mut applicability); + let requires_semi = matches!(cx.tcx.parent_hir_node(expr.hir_id), Node::Stmt(_)); + let sugg = format!( + "{receiver_str}{}?{}", + if by_ref == ByRef::Yes { ".as_ref()" } else { "" }, + if requires_semi { ";" } else { "" } + ); + span_lint_and_sugg( + cx, + QUESTION_MARK, + expr.span, + "this block may be rewritten with the `?` operator", + "replace it with", + sugg, + applicability, + ); + } +} + impl QuestionMark { fn inside_try_block(&self) -> bool { self.try_block_depth_stack.last() > Some(&0) } - - /// Checks if the given expression on the given context matches the following structure: - /// - /// ```ignore - /// if option.is_none() { - /// return None; - /// } - /// ``` - /// - /// ```ignore - /// if result.is_err() { - /// return result; - /// } - /// ``` - /// - /// If it matches, it will suggest to use the question mark operator instead - fn check_is_none_or_err_and_early_return<'tcx>(&self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) { - if !self.inside_try_block() - && let Some(higher::If { cond, then, r#else }) = higher::If::hir(expr) - && !is_else_clause(cx.tcx, expr) - && let ExprKind::MethodCall(segment, caller, ..) = &cond.kind - && let caller_ty = cx.typeck_results().expr_ty(caller) - && let if_block = IfBlockType::IfIs(caller, caller_ty, segment.ident.name, then) - && (is_early_return(sym::Option, cx, &if_block) || is_early_return(sym::Result, cx, &if_block)) - { - let mut applicability = Applicability::MachineApplicable; - let receiver_str = snippet_with_applicability(cx, caller.span, "..", &mut applicability); - let by_ref = !caller_ty.is_copy_modulo_regions(cx.tcx, cx.param_env) - && !matches!(caller.kind, ExprKind::Call(..) | ExprKind::MethodCall(..)); - let sugg = if let Some(else_inner) = r#else { - if eq_expr_value(cx, caller, peel_blocks(else_inner)) { - format!("Some({receiver_str}?)") - } else { - return; - } - } else { - format!("{receiver_str}{}?;", if by_ref { ".as_ref()" } else { "" }) - }; - - span_lint_and_sugg( - cx, - QUESTION_MARK, - expr.span, - "this block may be rewritten with the `?` operator", - "replace it with", - sugg, - applicability, - ); - } - } - - fn check_if_let_some_or_err_and_early_return<'tcx>(&self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) { - if !self.inside_try_block() - && let Some(higher::IfLet { - let_pat, - let_expr, - if_then, - if_else, - .. - }) = higher::IfLet::hir(cx, expr) - && !is_else_clause(cx.tcx, expr) - && let PatKind::TupleStruct(ref path1, [field], ddpos) = let_pat.kind - && ddpos.as_opt_usize().is_none() - && let PatKind::Binding(BindingAnnotation(by_ref, _), bind_id, ident, None) = field.kind - && let caller_ty = cx.typeck_results().expr_ty(let_expr) - && let if_block = IfBlockType::IfLet( - cx.qpath_res(path1, let_pat.hir_id), - caller_ty, - ident.name, - let_expr, - if_then, - if_else, - ) - && ((is_early_return(sym::Option, cx, &if_block) && path_to_local_id(peel_blocks(if_then), bind_id)) - || is_early_return(sym::Result, cx, &if_block)) - && if_else - .map(|e| eq_expr_value(cx, let_expr, peel_blocks(e))) - .filter(|e| *e) - .is_none() - { - let mut applicability = Applicability::MachineApplicable; - let receiver_str = snippet_with_applicability(cx, let_expr.span, "..", &mut applicability); - let requires_semi = matches!(cx.tcx.parent_hir_node(expr.hir_id), Node::Stmt(_)); - let sugg = format!( - "{receiver_str}{}?{}", - if by_ref == ByRef::Yes { ".as_ref()" } else { "" }, - if requires_semi { ";" } else { "" } - ); - span_lint_and_sugg( - cx, - QUESTION_MARK, - expr.span, - "this block may be rewritten with the `?` operator", - "replace it with", - sugg, - applicability, - ); - } - } } fn is_try_block(cx: &LateContext<'_>, bl: &rustc_hir::Block<'_>) -> bool { @@ -324,15 +322,18 @@ fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) { return; } - if !in_constant(cx, stmt.hir_id) { + if !self.inside_try_block() && !in_constant(cx, stmt.hir_id) { check_let_some_else_return_none(cx, stmt); } self.check_manual_let_else(cx, stmt); } fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if !in_constant(cx, expr.hir_id) && is_lint_allowed(cx, QUESTION_MARK_USED, expr.hir_id) { - self.check_is_none_or_err_and_early_return(cx, expr); - self.check_if_let_some_or_err_and_early_return(cx, expr); + if !self.inside_try_block() + && !in_constant(cx, expr.hir_id) + && is_lint_allowed(cx, QUESTION_MARK_USED, expr.hir_id) + { + check_is_none_or_err_and_early_return(cx, expr); + check_if_let_some_or_err_and_early_return(cx, expr); } } diff --git a/clippy_lints/src/redundant_closure_call.rs b/clippy_lints/src/redundant_closure_call.rs index e3f0ce2a922..f61527cc0a9 100644 --- a/clippy_lints/src/redundant_closure_call.rs +++ b/clippy_lints/src/redundant_closure_call.rs @@ -159,6 +159,15 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) { // ^^ we only want to lint for this call (but we walk up the calls to consider both calls). // without this check, we'd end up linting twice. && !matches!(recv.kind, hir::ExprKind::Call(..)) + // Check if `recv` comes from a macro expansion. If it does, make sure that it's an expansion that is + // the same as the one the call is in. + // For instance, let's assume `x!()` returns a closure: + // B ---v + // x!()() + // ^- A + // The call happens in the expansion `A`, while the closure originates from the expansion `B`. + // We don't want to suggest replacing `x!()()` with `x!()`. + && recv.span.ctxt().outer_expn() == expr.span.ctxt().outer_expn() && let (full_expr, call_depth) = get_parent_call_exprs(cx, expr) && let Some((body, fn_decl, coroutine_kind, params)) = find_innermost_closure(cx, recv, call_depth) // outside macros we lint properly. Inside macros, we lint only ||() style closures. diff --git a/clippy_lints/src/redundant_field_names.rs b/clippy_lints/src/redundant_field_names.rs index fb000cd7184..17b031d5f01 100644 --- a/clippy_lints/src/redundant_field_names.rs +++ b/clippy_lints/src/redundant_field_names.rs @@ -59,24 +59,22 @@ fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { } if let ExprKind::Struct(ref se) = expr.kind { for field in &se.fields { - if field.is_shorthand { - continue; - } - if let ExprKind::Path(None, path) = &field.expr.kind { - if path.segments.len() == 1 - && path.segments[0].ident == field.ident - && path.segments[0].args.is_none() - { - span_lint_and_sugg( - cx, - REDUNDANT_FIELD_NAMES, - field.span, - "redundant field names in struct initialization", - "replace it with", - field.ident.to_string(), - Applicability::MachineApplicable, - ); - } + if !field.is_shorthand + && let ExprKind::Path(None, path) = &field.expr.kind + && let [segment] = path.segments.as_slice() + && segment.args.is_none() + && segment.ident == field.ident + && field.span.eq_ctxt(field.ident.span) + { + span_lint_and_sugg( + cx, + REDUNDANT_FIELD_NAMES, + field.span, + "redundant field names in struct initialization", + "replace it with", + field.ident.to_string(), + Applicability::MachineApplicable, + ); } } } diff --git a/clippy_lints/src/std_instead_of_core.rs b/clippy_lints/src/std_instead_of_core.rs index 38fd54a0f1e..c0e4f3c368a 100644 --- a/clippy_lints/src/std_instead_of_core.rs +++ b/clippy_lints/src/std_instead_of_core.rs @@ -109,7 +109,6 @@ fn check_path(&mut self, cx: &LateContext<'tcx>, path: &Path<'tcx>, _: HirId) { sym::core => (STD_INSTEAD_OF_CORE, "std", "core"), sym::alloc => (STD_INSTEAD_OF_ALLOC, "std", "alloc"), _ => { - self.prev_span = path.span; return; }, }, @@ -117,13 +116,12 @@ fn check_path(&mut self, cx: &LateContext<'tcx>, path: &Path<'tcx>, _: HirId) { if cx.tcx.crate_name(def_id.krate) == sym::core { (ALLOC_INSTEAD_OF_CORE, "alloc", "core") } else { - self.prev_span = path.span; return; } }, _ => return, }; - if path.span != self.prev_span { + if first_segment.ident.span != self.prev_span { span_lint_and_sugg( cx, lint, @@ -133,7 +131,7 @@ fn check_path(&mut self, cx: &LateContext<'tcx>, path: &Path<'tcx>, _: HirId) { replace_with.to_string(), Applicability::MachineApplicable, ); - self.prev_span = path.span; + self.prev_span = first_segment.ident.span; } } } diff --git a/clippy_lints/src/thread_local_initializer_can_be_made_const.rs b/clippy_lints/src/thread_local_initializer_can_be_made_const.rs index 9fee4c06200..1af3733ebfa 100644 --- a/clippy_lints/src/thread_local_initializer_can_be_made_const.rs +++ b/clippy_lints/src/thread_local_initializer_can_be_made_const.rs @@ -1,12 +1,11 @@ -use clippy_config::msrvs::Msrv; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::fn_has_unsatisfiable_preds; use clippy_utils::qualify_min_const_fn::is_min_const_fn; use clippy_utils::source::snippet; +use clippy_utils::{fn_has_unsatisfiable_preds, peel_blocks}; use rustc_errors::Applicability; use rustc_hir::{intravisit, ExprKind}; -use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::lint::in_external_macro; +use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; use rustc_span::sym::thread_local_macro; @@ -57,6 +56,31 @@ pub fn new(msrv: Msrv) -> Self { impl_lint_pass!(ThreadLocalInitializerCanBeMadeConst => [THREAD_LOCAL_INITIALIZER_CAN_BE_MADE_CONST]); +#[inline] +fn is_thread_local_initializer( + cx: &LateContext<'_>, + fn_kind: rustc_hir::intravisit::FnKind<'_>, + span: rustc_span::Span, +) -> Option { + let macro_def_id = span.source_callee()?.macro_def_id?; + Some( + cx.tcx.is_diagnostic_item(thread_local_macro, macro_def_id) + && matches!(fn_kind, intravisit::FnKind::ItemFn(..)), + ) +} + +#[inline] +fn initializer_can_be_made_const(cx: &LateContext<'_>, defid: rustc_span::def_id::DefId, msrv: &Msrv) -> bool { + // Building MIR for `fn`s with unsatisfiable preds results in ICE. + if !fn_has_unsatisfiable_preds(cx, defid) + && let mir = cx.tcx.optimized_mir(defid) + && let Ok(()) = is_min_const_fn(cx.tcx, mir, msrv) + { + return true; + } + false +} + impl<'tcx> LateLintPass<'tcx> for ThreadLocalInitializerCanBeMadeConst { fn check_fn( &mut self, @@ -65,31 +89,32 @@ fn check_fn( _: &'tcx rustc_hir::FnDecl<'tcx>, body: &'tcx rustc_hir::Body<'tcx>, span: rustc_span::Span, - defid: rustc_span::def_id::LocalDefId, + local_defid: rustc_span::def_id::LocalDefId, ) { - if in_external_macro(cx.sess(), span) - && let Some(callee) = span.source_callee() - && let Some(macro_def_id) = callee.macro_def_id - && cx.tcx.is_diagnostic_item(thread_local_macro, macro_def_id) - && let intravisit::FnKind::ItemFn(..) = fn_kind - // Building MIR for `fn`s with unsatisfiable preds results in ICE. - && !fn_has_unsatisfiable_preds(cx, defid.to_def_id()) - && let mir = cx.tcx.optimized_mir(defid.to_def_id()) - && let Ok(()) = is_min_const_fn(cx.tcx, mir, &self.msrv) - // this is the `__init` function emitted by the `thread_local!` macro - // when the `const` keyword is not used. We avoid checking the `__init` directly - // as that is not a public API. - // we know that the function is const-qualifiable, so now we need only to get the - // initializer expression to span-lint it. + let defid = local_defid.to_def_id(); + if self.msrv.meets(msrvs::THREAD_LOCAL_INITIALIZER_CAN_BE_MADE_CONST) + && is_thread_local_initializer(cx, fn_kind, span).unwrap_or(false) + // Some implementations of `thread_local!` include an initializer fn. + // In the case of a const initializer, the init fn is also const, + // so we can skip the lint in that case. This occurs only on some + // backends due to conditional compilation: + // https://doc.rust-lang.org/src/std/sys/common/thread_local/mod.rs.html + // for details on this issue, see: + // https://github.com/rust-lang/rust-clippy/pull/12276 + && !cx.tcx.is_const_fn(defid) + && initializer_can_be_made_const(cx, defid, &self.msrv) + // we know that the function is const-qualifiable, so now + // we need only to get the initializer expression to span-lint it. && let ExprKind::Block(block, _) = body.value.kind - && let Some(ret_expr) = block.expr + && let Some(unpeeled) = block.expr + && let ret_expr = peel_blocks(unpeeled) && let initializer_snippet = snippet(cx, ret_expr.span, "thread_local! { ... }") && initializer_snippet != "thread_local! { ... }" { span_lint_and_sugg( cx, THREAD_LOCAL_INITIALIZER_CAN_BE_MADE_CONST, - ret_expr.span, + unpeeled.span, "initializer for `thread_local` value can be made `const`", "replace with", format!("const {{ {initializer_snippet} }}"), diff --git a/clippy_lints/src/transmute/mod.rs b/clippy_lints/src/transmute/mod.rs index 06de7a11031..e47b14bf63b 100644 --- a/clippy_lints/src/transmute/mod.rs +++ b/clippy_lints/src/transmute/mod.rs @@ -592,7 +592,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { | (eager_transmute::check(cx, e, arg, from_ty, to_ty)); if !linted { - transmutes_expressible_as_ptr_casts::check(cx, e, from_ty, from_ty_adjusted, to_ty, arg); + transmutes_expressible_as_ptr_casts::check(cx, e, from_ty, from_ty_adjusted, to_ty, arg, const_context); } } } 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 bbecc39a813..043c9c88601 100644 --- a/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs +++ b/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs @@ -18,10 +18,12 @@ pub(super) fn check<'tcx>( from_ty_adjusted: bool, to_ty: Ty<'tcx>, arg: &'tcx Expr<'_>, + const_context: bool, ) -> bool { use CastKind::{AddrPtrCast, ArrayPtrCast, FnPtrAddrCast, FnPtrPtrCast, PtrAddrCast, PtrPtrCast}; let mut app = Applicability::MachineApplicable; let mut sugg = match check_cast(cx, e, from_ty, to_ty) { + Some(FnPtrAddrCast | PtrAddrCast) if const_context => return false, Some(PtrPtrCast | AddrPtrCast | ArrayPtrCast | FnPtrPtrCast | FnPtrAddrCast) => { Sugg::hir_with_context(cx, arg, e.span.ctxt(), "..", &mut app) .as_ty(to_ty.to_string()) diff --git a/clippy_lints/src/types/vec_box.rs b/clippy_lints/src/types/vec_box.rs index a285f771f1b..7926738d68f 100644 --- a/clippy_lints/src/types/vec_box.rs +++ b/clippy_lints/src/types/vec_box.rs @@ -1,10 +1,9 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::paths::ALLOCATOR_GLOBAL; +use clippy_utils::last_path_segment; use clippy_utils::source::snippet; -use clippy_utils::{last_path_segment, match_def_path}; use rustc_errors::Applicability; use rustc_hir::def_id::DefId; -use rustc_hir::{self as hir, GenericArg, QPath, TyKind}; +use rustc_hir::{self as hir, GenericArg, LangItem, QPath, TyKind}; use rustc_hir_analysis::hir_ty_to_ty; use rustc_lint::LateContext; use rustc_middle::ty::layout::LayoutOf; @@ -50,7 +49,7 @@ pub(super) fn check<'tcx>( (None, Some(GenericArg::Type(inner))) | (Some(GenericArg::Type(inner)), None) => { if let TyKind::Path(path) = inner.kind && let Some(did) = cx.qpath_res(&path, inner.hir_id).opt_def_id() { - match_def_path(cx, did, &ALLOCATOR_GLOBAL) + cx.tcx.lang_items().get(LangItem::GlobalAlloc) == Some(did) } else { false } diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index 2f728b62754..987f28192a8 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -115,4 +115,3 @@ pub const OPTION_EXPECT: [&str; 4] = ["core", "option", "Option", "expect"]; #[expect(clippy::invalid_paths)] // not sure why it thinks this, it works so pub const BOOL_THEN: [&str; 4] = ["core", "bool", "", "then"]; -pub const ALLOCATOR_GLOBAL: [&str; 3] = ["alloc", "alloc", "Global"]; diff --git a/clippy_utils/src/sugg.rs b/clippy_utils/src/sugg.rs index e74621a0fbb..5090d0bd98b 100644 --- a/clippy_utils/src/sugg.rs +++ b/clippy_utils/src/sugg.rs @@ -995,7 +995,7 @@ fn borrow(&mut self, cmt: &PlaceWithHirId<'tcx>, _: HirId, _: ty::BorrowKind) { // no adjustment needed here, as field projections are handled by the compiler ProjectionKind::Field(..) => match cmt.place.ty_before_projection(i).kind() { ty::Adt(..) | ty::Tuple(_) => { - replacement_str = ident_str_with_proj.clone(); + replacement_str.clone_from(&ident_str_with_proj); projections_handled = true; }, _ => (), diff --git a/rust-toolchain b/rust-toolchain index fb038b617df..070b62887d5 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2024-02-22" +channel = "nightly-2024-03-07" components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] diff --git a/src/main.rs b/src/main.rs index dffa854177b..30beaae34d2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -174,8 +174,13 @@ pub fn help_message() -> &'static str { You can use tool lints to allow or deny lints from your code, e.g.: #[allow(clippy::needless_lifetimes)] -" - ) + +Manifest Options: + --manifest-path <> Path to Cargo.toml + --frozen Require Cargo.lock and cache are up to date + --locked Require Cargo.lock is up to date + --offline Run without accessing the network +") } #[cfg(test)] mod tests { diff --git a/tests/compile-test.rs b/tests/compile-test.rs index a088896b6b0..a0c8bf9334c 100644 --- a/tests/compile-test.rs +++ b/tests/compile-test.rs @@ -138,6 +138,7 @@ fn base_config(test_dir: &str) -> (Config, Args) { "-Aunused", "-Ainternal_features", "-Zui-testing", + "-Zdeduplicate-diagnostics=no", "-Dwarnings", &format!("-Ldependency={}", deps_path.display()), ] diff --git a/tests/missing-test-files.rs b/tests/missing-test-files.rs index 0d35a22cd9a..141c11ddb47 100644 --- a/tests/missing-test-files.rs +++ b/tests/missing-test-files.rs @@ -54,7 +54,7 @@ fn explore_directory(dir: &Path) -> Vec { let file_prefix = path.file_prefix().unwrap().to_str().unwrap().to_string(); if let Some(ext) = path.extension() { match ext.to_str().unwrap() { - "rs" | "toml" => current_file = file_prefix.clone(), + "rs" | "toml" => current_file.clone_from(&file_prefix), "stderr" | "stdout" => { if file_prefix != current_file { missing_files.push(path.to_str().unwrap().to_string()); diff --git a/tests/ui-internal/custom_ice_message.rs b/tests/ui-internal/custom_ice_message.rs index 9b0db660c99..400bfd5d975 100644 --- a/tests/ui-internal/custom_ice_message.rs +++ b/tests/ui-internal/custom_ice_message.rs @@ -5,6 +5,7 @@ //@normalize-stderr-test: "'rustc'" -> "''" //@normalize-stderr-test: "rustc 1\.\d+.* running on .*" -> "rustc running on " //@normalize-stderr-test: "(?ms)query stack during panic:\n.*end of query stack\n" -> "" +//@normalize-stderr-test: "this compiler `.*` is outdated" -> "this compiler is outdated" #![deny(clippy::internal)] #![allow(clippy::missing_clippy_version_attribute)] diff --git a/tests/ui-internal/custom_ice_message.stderr b/tests/ui-internal/custom_ice_message.stderr index d8b158816c9..b84f4e87e07 100644 --- a/tests/ui-internal/custom_ice_message.stderr +++ b/tests/ui-internal/custom_ice_message.stderr @@ -4,11 +4,14 @@ note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace error: the compiler unexpectedly panicked. this is a bug. -note: we would appreciate a bug report: https://github.com/rust-lang/rust-clippy/issues/new?template=ice.yml +note: it seems that this compiler is outdated, a newer nightly should have been released in the mean time + | + = note: please consider running `rustup update nightly` to update the nightly channel and check if this problem still persists + = note: if the problem still persists, we would appreciate a bug report: https://github.com/rust-lang/rust-clippy/issues/new?template=ice.yml note: rustc running on -note: compiler flags: -Z ui-testing +note: compiler flags: -Z ui-testing -Z deduplicate-diagnostics=no note: Clippy version: foo diff --git a/tests/ui-internal/disallow_span_lint.rs b/tests/ui-internal/disallow_span_lint.rs index c5029bbd9a4..5a2a868ed3e 100644 --- a/tests/ui-internal/disallow_span_lint.rs +++ b/tests/ui-internal/disallow_span_lint.rs @@ -10,22 +10,11 @@ use rustc_lint::{Lint, LintContext}; use rustc_middle::ty::TyCtxt; -pub fn a( - cx: impl LintContext, - lint: &'static Lint, - span: impl Into, - msg: impl Into) -{ +pub fn a(cx: impl LintContext, lint: &'static Lint, span: impl Into, msg: impl Into) { cx.span_lint(lint, span, msg, |_| {}); } -pub fn b( - tcx: TyCtxt<'_>, - lint: &'static Lint, - hir_id: HirId, - span: impl Into, - msg: impl Into, -) { +pub fn b(tcx: TyCtxt<'_>, lint: &'static Lint, hir_id: HirId, span: impl Into, msg: impl Into) { tcx.node_span_lint(lint, hir_id, span, msg, |_| {}); } diff --git a/tests/ui-internal/disallow_span_lint.stderr b/tests/ui-internal/disallow_span_lint.stderr index 1a1ad26290c..ae5d6843406 100644 --- a/tests/ui-internal/disallow_span_lint.stderr +++ b/tests/ui-internal/disallow_span_lint.stderr @@ -8,7 +8,7 @@ LL | cx.span_lint(lint, span, msg, |_| {}); = help: to override `-D warnings` add `#[allow(clippy::disallowed_methods)]` error: use of a disallowed method `rustc_middle::ty::context::TyCtxt::node_span_lint` - --> tests/ui-internal/disallow_span_lint.rs:24:5 + --> tests/ui-internal/disallow_span_lint.rs:18:5 | LL | tcx.node_span_lint(lint, hir_id, span, msg, |_| {}); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.default.stderr b/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.default.stderr index 87f84d8f7dd..37d69055737 100644 --- a/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.default.stderr +++ b/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.default.stderr @@ -1,5 +1,5 @@ error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:266:19 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:271:19 | LL | /* Safety: */ unsafe {} | ^^^^^^^^^ @@ -9,7 +9,7 @@ LL | /* Safety: */ unsafe {} = help: to override `-D warnings` add `#[allow(clippy::undocumented_unsafe_blocks)]` error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:270:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:275:5 | LL | unsafe {} | ^^^^^^^^^ @@ -17,7 +17,7 @@ LL | unsafe {} = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:274:14 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:279:14 | LL | let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }]; | ^^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL | let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }]; = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:274:29 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:279:29 | LL | let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }]; | ^^^^^^^^^^^^^ @@ -33,7 +33,7 @@ LL | let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }]; = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:274:48 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:279:48 | LL | let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }]; | ^^^^^^^^^^^^^ @@ -41,7 +41,7 @@ LL | let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }]; = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:278:18 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:283:18 | LL | let _ = (42, unsafe {}, "test", unsafe {}); | ^^^^^^^^^ @@ -49,7 +49,7 @@ LL | let _ = (42, unsafe {}, "test", unsafe {}); = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:278:37 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:283:37 | LL | let _ = (42, unsafe {}, "test", unsafe {}); | ^^^^^^^^^ @@ -57,7 +57,7 @@ LL | let _ = (42, unsafe {}, "test", unsafe {}); = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:282:14 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:287:14 | LL | let _ = *unsafe { &42 }; | ^^^^^^^^^^^^^^ @@ -65,7 +65,7 @@ LL | let _ = *unsafe { &42 }; = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:287:19 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:292:19 | LL | let _ = match unsafe {} { | ^^^^^^^^^ @@ -73,7 +73,7 @@ LL | let _ = match unsafe {} { = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:293:14 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:298:14 | LL | let _ = &unsafe {}; | ^^^^^^^^^ @@ -81,7 +81,7 @@ LL | let _ = &unsafe {}; = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:297:14 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:302:14 | LL | let _ = [unsafe {}; 5]; | ^^^^^^^^^ @@ -89,7 +89,7 @@ LL | let _ = [unsafe {}; 5]; = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:301:13 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:306:13 | LL | let _ = unsafe {}; | ^^^^^^^^^ @@ -97,7 +97,7 @@ LL | let _ = unsafe {}; = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:311:8 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:316:8 | LL | t!(unsafe {}); | ^^^^^^^^^ @@ -105,7 +105,7 @@ LL | t!(unsafe {}); = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:317:13 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:322:13 | LL | unsafe {} | ^^^^^^^^^ @@ -117,7 +117,7 @@ LL | t!(); = note: this error originates in the macro `t` (in Nightly builds, run with -Z macro-backtrace for more info) error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:325:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:330:5 | LL | unsafe {} // SAFETY: | ^^^^^^^^^ @@ -125,7 +125,7 @@ LL | unsafe {} // SAFETY: = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:329:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:334:5 | LL | unsafe { | ^^^^^^^^ @@ -133,7 +133,7 @@ LL | unsafe { = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:339:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:344:5 | LL | unsafe {}; | ^^^^^^^^^ @@ -141,7 +141,7 @@ LL | unsafe {}; = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:343:20 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:348:20 | LL | println!("{}", unsafe { String::from_utf8_unchecked(vec![]) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -149,7 +149,7 @@ LL | println!("{}", unsafe { String::from_utf8_unchecked(vec![]) }); = help: consider adding a safety comment on the preceding line error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:350:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:355:5 | LL | unsafe impl A for () {} | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -157,7 +157,7 @@ LL | unsafe impl A for () {} = help: consider adding a safety comment on the preceding line error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:357:9 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:362:9 | LL | unsafe impl B for (u32) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -165,7 +165,7 @@ LL | unsafe impl B for (u32) {} = help: consider adding a safety comment on the preceding line error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:378:13 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:383:13 | LL | unsafe impl T for $t {} | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -177,7 +177,7 @@ LL | no_safety_comment!(()); = note: this error originates in the macro `no_safety_comment` (in Nightly builds, run with -Z macro-backtrace for more info) error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:403:13 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:408:13 | LL | unsafe impl T for $t {} | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -189,7 +189,7 @@ LL | no_safety_comment!(()); = note: this error originates in the macro `no_safety_comment` (in Nightly builds, run with -Z macro-backtrace for more info) error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:411:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:416:5 | LL | unsafe impl T for (i32) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -197,7 +197,7 @@ LL | unsafe impl T for (i32) {} = help: consider adding a safety comment on the preceding line error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:403:13 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:408:13 | LL | unsafe impl T for $t {} | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -209,7 +209,7 @@ LL | no_safety_comment!(u32); = note: this error originates in the macro `no_safety_comment` (in Nightly builds, run with -Z macro-backtrace for more info) error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:417:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:422:5 | LL | unsafe impl T for (bool) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -217,7 +217,7 @@ LL | unsafe impl T for (bool) {} = help: consider adding a safety comment on the preceding line error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:463:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:468:5 | LL | unsafe impl NoComment for () {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -225,7 +225,7 @@ LL | unsafe impl NoComment for () {} = help: consider adding a safety comment on the preceding line error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:467:19 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:472:19 | LL | /* SAFETY: */ unsafe impl InlineComment for () {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -233,7 +233,7 @@ LL | /* SAFETY: */ unsafe impl InlineComment for () {} = help: consider adding a safety comment on the preceding line error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:471:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:476:5 | LL | unsafe impl TrailingComment for () {} // SAFETY: | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -241,13 +241,13 @@ LL | unsafe impl TrailingComment for () {} // SAFETY: = help: consider adding a safety comment on the preceding line error: constant item has unnecessary safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:475:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:480:5 | LL | const BIG_NUMBER: i32 = 1000000; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: consider removing the safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:474:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:479:5 | LL | // SAFETY: | ^^^^^^^^^^ @@ -255,7 +255,7 @@ LL | // SAFETY: = help: to override `-D warnings` add `#[allow(clippy::unnecessary_safety_comment)]` error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:476:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:481:5 | LL | unsafe impl Interference for () {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -263,7 +263,7 @@ LL | unsafe impl Interference for () {} = help: consider adding a safety comment on the preceding line error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:483:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:488:5 | LL | unsafe impl ImplInFn for () {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -271,7 +271,7 @@ LL | unsafe impl ImplInFn for () {} = help: consider adding a safety comment on the preceding line error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:492:1 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:497:1 | LL | unsafe impl CrateRoot for () {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -279,7 +279,7 @@ LL | unsafe impl CrateRoot for () {} = help: consider adding a safety comment on the preceding line error: statement has unnecessary safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:505:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:510:5 | LL | / let _ = { LL | | if unsafe { true } { @@ -291,13 +291,13 @@ LL | | }; | |______^ | help: consider removing the safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:504:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:509:5 | LL | // SAFETY: this is more than one level away, so it should warn | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:506:12 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:511:12 | LL | if unsafe { true } { | ^^^^^^^^^^^^^^^ @@ -305,7 +305,7 @@ LL | if unsafe { true } { = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:509:23 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:514:23 | LL | let bar = unsafe {}; | ^^^^^^^^^ diff --git a/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.disabled.stderr b/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.disabled.stderr index 5ffe73f5a2f..400fde997e9 100644 --- a/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.disabled.stderr +++ b/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.disabled.stderr @@ -1,5 +1,5 @@ error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:266:19 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:271:19 | LL | /* Safety: */ unsafe {} | ^^^^^^^^^ @@ -9,7 +9,7 @@ LL | /* Safety: */ unsafe {} = help: to override `-D warnings` add `#[allow(clippy::undocumented_unsafe_blocks)]` error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:270:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:275:5 | LL | unsafe {} | ^^^^^^^^^ @@ -17,7 +17,7 @@ LL | unsafe {} = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:274:14 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:279:14 | LL | let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }]; | ^^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL | let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }]; = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:274:29 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:279:29 | LL | let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }]; | ^^^^^^^^^^^^^ @@ -33,7 +33,7 @@ LL | let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }]; = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:274:48 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:279:48 | LL | let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }]; | ^^^^^^^^^^^^^ @@ -41,7 +41,7 @@ LL | let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }]; = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:278:18 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:283:18 | LL | let _ = (42, unsafe {}, "test", unsafe {}); | ^^^^^^^^^ @@ -49,7 +49,7 @@ LL | let _ = (42, unsafe {}, "test", unsafe {}); = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:278:37 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:283:37 | LL | let _ = (42, unsafe {}, "test", unsafe {}); | ^^^^^^^^^ @@ -57,7 +57,7 @@ LL | let _ = (42, unsafe {}, "test", unsafe {}); = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:282:14 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:287:14 | LL | let _ = *unsafe { &42 }; | ^^^^^^^^^^^^^^ @@ -65,7 +65,7 @@ LL | let _ = *unsafe { &42 }; = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:287:19 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:292:19 | LL | let _ = match unsafe {} { | ^^^^^^^^^ @@ -73,7 +73,7 @@ LL | let _ = match unsafe {} { = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:293:14 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:298:14 | LL | let _ = &unsafe {}; | ^^^^^^^^^ @@ -81,7 +81,7 @@ LL | let _ = &unsafe {}; = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:297:14 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:302:14 | LL | let _ = [unsafe {}; 5]; | ^^^^^^^^^ @@ -89,7 +89,7 @@ LL | let _ = [unsafe {}; 5]; = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:301:13 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:306:13 | LL | let _ = unsafe {}; | ^^^^^^^^^ @@ -97,7 +97,7 @@ LL | let _ = unsafe {}; = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:311:8 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:316:8 | LL | t!(unsafe {}); | ^^^^^^^^^ @@ -105,7 +105,7 @@ LL | t!(unsafe {}); = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:317:13 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:322:13 | LL | unsafe {} | ^^^^^^^^^ @@ -117,7 +117,7 @@ LL | t!(); = note: this error originates in the macro `t` (in Nightly builds, run with -Z macro-backtrace for more info) error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:325:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:330:5 | LL | unsafe {} // SAFETY: | ^^^^^^^^^ @@ -125,7 +125,7 @@ LL | unsafe {} // SAFETY: = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:329:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:334:5 | LL | unsafe { | ^^^^^^^^ @@ -133,7 +133,7 @@ LL | unsafe { = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:339:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:344:5 | LL | unsafe {}; | ^^^^^^^^^ @@ -141,7 +141,7 @@ LL | unsafe {}; = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:343:20 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:348:20 | LL | println!("{}", unsafe { String::from_utf8_unchecked(vec![]) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -149,7 +149,7 @@ LL | println!("{}", unsafe { String::from_utf8_unchecked(vec![]) }); = help: consider adding a safety comment on the preceding line error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:350:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:355:5 | LL | unsafe impl A for () {} | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -157,7 +157,7 @@ LL | unsafe impl A for () {} = help: consider adding a safety comment on the preceding line error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:357:9 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:362:9 | LL | unsafe impl B for (u32) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -165,7 +165,7 @@ LL | unsafe impl B for (u32) {} = help: consider adding a safety comment on the preceding line error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:378:13 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:383:13 | LL | unsafe impl T for $t {} | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -177,7 +177,7 @@ LL | no_safety_comment!(()); = note: this error originates in the macro `no_safety_comment` (in Nightly builds, run with -Z macro-backtrace for more info) error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:403:13 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:408:13 | LL | unsafe impl T for $t {} | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -189,7 +189,7 @@ LL | no_safety_comment!(()); = note: this error originates in the macro `no_safety_comment` (in Nightly builds, run with -Z macro-backtrace for more info) error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:411:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:416:5 | LL | unsafe impl T for (i32) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -197,7 +197,7 @@ LL | unsafe impl T for (i32) {} = help: consider adding a safety comment on the preceding line error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:403:13 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:408:13 | LL | unsafe impl T for $t {} | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -209,7 +209,7 @@ LL | no_safety_comment!(u32); = note: this error originates in the macro `no_safety_comment` (in Nightly builds, run with -Z macro-backtrace for more info) error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:417:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:422:5 | LL | unsafe impl T for (bool) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -217,7 +217,7 @@ LL | unsafe impl T for (bool) {} = help: consider adding a safety comment on the preceding line error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:463:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:468:5 | LL | unsafe impl NoComment for () {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -225,7 +225,7 @@ LL | unsafe impl NoComment for () {} = help: consider adding a safety comment on the preceding line error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:467:19 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:472:19 | LL | /* SAFETY: */ unsafe impl InlineComment for () {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -233,7 +233,7 @@ LL | /* SAFETY: */ unsafe impl InlineComment for () {} = help: consider adding a safety comment on the preceding line error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:471:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:476:5 | LL | unsafe impl TrailingComment for () {} // SAFETY: | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -241,13 +241,13 @@ LL | unsafe impl TrailingComment for () {} // SAFETY: = help: consider adding a safety comment on the preceding line error: constant item has unnecessary safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:475:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:480:5 | LL | const BIG_NUMBER: i32 = 1000000; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: consider removing the safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:474:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:479:5 | LL | // SAFETY: | ^^^^^^^^^^ @@ -255,7 +255,7 @@ LL | // SAFETY: = help: to override `-D warnings` add `#[allow(clippy::unnecessary_safety_comment)]` error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:476:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:481:5 | LL | unsafe impl Interference for () {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -263,7 +263,7 @@ LL | unsafe impl Interference for () {} = help: consider adding a safety comment on the preceding line error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:483:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:488:5 | LL | unsafe impl ImplInFn for () {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -271,7 +271,7 @@ LL | unsafe impl ImplInFn for () {} = help: consider adding a safety comment on the preceding line error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:492:1 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:497:1 | LL | unsafe impl CrateRoot for () {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -279,7 +279,7 @@ LL | unsafe impl CrateRoot for () {} = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:502:9 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:507:9 | LL | unsafe {}; | ^^^^^^^^^ @@ -287,7 +287,7 @@ LL | unsafe {}; = help: consider adding a safety comment on the preceding line error: statement has unnecessary safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:505:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:510:5 | LL | / let _ = { LL | | if unsafe { true } { @@ -299,13 +299,13 @@ LL | | }; | |______^ | help: consider removing the safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:504:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:509:5 | LL | // SAFETY: this is more than one level away, so it should warn | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:506:12 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:511:12 | LL | if unsafe { true } { | ^^^^^^^^^^^^^^^ @@ -313,7 +313,7 @@ LL | if unsafe { true } { = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:509:23 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:514:23 | LL | let bar = unsafe {}; | ^^^^^^^^^ @@ -321,7 +321,7 @@ LL | let bar = unsafe {}; = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:527:9 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:532:9 | LL | unsafe { a_function_with_a_very_long_name_to_break_the_line() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -329,7 +329,7 @@ LL | unsafe { a_function_with_a_very_long_name_to_break_the_line() }; = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:531:9 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:536:9 | LL | unsafe { a_const_function_with_a_very_long_name_to_break_the_line() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -337,7 +337,7 @@ LL | unsafe { a_const_function_with_a_very_long_name_to_break_the_line() = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:535:9 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:540:9 | LL | unsafe { a_const_function_with_a_very_long_name_to_break_the_line() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -345,7 +345,7 @@ LL | unsafe { a_const_function_with_a_very_long_name_to_break_the_line() = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:541:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:546:5 | LL | unsafe {} | ^^^^^^^^^ @@ -353,7 +353,7 @@ LL | unsafe {} = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:545:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:550:5 | LL | unsafe { | ^^^^^^^^ @@ -361,7 +361,7 @@ LL | unsafe { = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:552:9 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:557:9 | LL | unsafe { a_function_with_a_very_long_name_to_break_the_line() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -369,7 +369,7 @@ LL | unsafe { a_function_with_a_very_long_name_to_break_the_line() }; = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:557:9 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:562:9 | LL | unsafe { a_const_function_with_a_very_long_name_to_break_the_line() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -377,7 +377,7 @@ LL | unsafe { a_const_function_with_a_very_long_name_to_break_the_line() = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:563:9 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:568:9 | LL | unsafe { a_const_function_with_a_very_long_name_to_break_the_line() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -385,7 +385,7 @@ LL | unsafe { a_const_function_with_a_very_long_name_to_break_the_line() = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:568:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:573:5 | LL | unsafe {} | ^^^^^^^^^ diff --git a/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs b/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs index 8997073c8a5..e5ef9d35fb6 100644 --- a/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs +++ b/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs @@ -4,7 +4,12 @@ //@[disabled] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/undocumented_unsafe_blocks/disabled #![warn(clippy::undocumented_unsafe_blocks, clippy::unnecessary_safety_comment)] -#![allow(deref_nullptr, non_local_definitions, clippy::let_unit_value, clippy::missing_safety_doc)] +#![allow( + deref_nullptr, + non_local_definitions, + clippy::let_unit_value, + clippy::missing_safety_doc +)] #![feature(lint_reasons)] extern crate proc_macro_unsafe; diff --git a/tests/ui/assigning_clones.fixed b/tests/ui/assigning_clones.fixed new file mode 100644 index 00000000000..c66e0c1f602 --- /dev/null +++ b/tests/ui/assigning_clones.fixed @@ -0,0 +1,222 @@ +#![allow(unused)] +#![allow(clippy::redundant_clone)] +#![allow(clippy::ptr_arg)] // https://github.com/rust-lang/rust-clippy/issues/10612 +#![allow(clippy::needless_late_init)] +#![allow(clippy::box_collection)] +#![warn(clippy::assigning_clones)] + +use std::borrow::ToOwned; +use std::ops::{Add, Deref, DerefMut}; + +// Clone +pub struct HasCloneFrom; + +impl Clone for HasCloneFrom { + fn clone(&self) -> Self { + Self + } + fn clone_from(&mut self, source: &Self) { + *self = HasCloneFrom; + } +} + +fn clone_method_rhs_val(mut_thing: &mut HasCloneFrom, value_thing: HasCloneFrom) { + mut_thing.clone_from(&value_thing); +} + +fn clone_method_rhs_ref(mut_thing: &mut HasCloneFrom, ref_thing: &HasCloneFrom) { + mut_thing.clone_from(ref_thing); +} + +fn clone_method_lhs_val(mut mut_thing: HasCloneFrom, ref_thing: &HasCloneFrom) { + mut_thing.clone_from(ref_thing); +} + +fn clone_function_lhs_mut_ref(mut_thing: &mut HasCloneFrom, ref_thing: &HasCloneFrom) { + Clone::clone_from(mut_thing, ref_thing); +} + +fn clone_function_lhs_val(mut mut_thing: HasCloneFrom, ref_thing: &HasCloneFrom) { + Clone::clone_from(&mut mut_thing, ref_thing); +} + +fn clone_function_through_trait(mut_thing: &mut HasCloneFrom, ref_thing: &HasCloneFrom) { + Clone::clone_from(mut_thing, ref_thing); +} + +fn clone_function_through_type(mut_thing: &mut HasCloneFrom, ref_thing: &HasCloneFrom) { + Clone::clone_from(mut_thing, ref_thing); +} + +fn clone_function_fully_qualified(mut_thing: &mut HasCloneFrom, ref_thing: &HasCloneFrom) { + Clone::clone_from(mut_thing, ref_thing); +} + +fn clone_method_lhs_complex(mut_thing: &mut HasCloneFrom, ref_thing: &HasCloneFrom) { + // These parens should be kept as necessary for a receiver + (mut_thing + &mut HasCloneFrom).clone_from(ref_thing); +} + +fn clone_method_rhs_complex(mut_thing: &mut HasCloneFrom, ref_thing: &HasCloneFrom) { + // These parens should be removed since they are not needed in a function argument + mut_thing.clone_from(ref_thing + ref_thing); +} + +fn assign_to_init_mut_var(b: HasCloneFrom) -> HasCloneFrom { + let mut a = HasCloneFrom; + for _ in 1..10 { + a.clone_from(&b); + } + a +} + +fn assign_to_late_init_mut_var(b: HasCloneFrom) { + let mut a; + a = HasCloneFrom; + a = b.clone(); +} + +fn assign_to_uninit_var(b: HasCloneFrom) { + let a; + a = b.clone(); +} + +fn assign_to_uninit_mut_var(b: HasCloneFrom) { + let mut a; + a = b.clone(); +} + +#[derive(Clone)] +pub struct HasDeriveClone; + +fn ignore_derive_clone(a: &mut HasDeriveClone, b: &HasDeriveClone) { + // Should not be linted, since the Clone impl is derived + *a = b.clone(); +} + +pub struct HasCloneImpl; + +impl Clone for HasCloneImpl { + fn clone(&self) -> Self { + Self + } +} + +fn ignore_missing_clone_from(a: &mut HasCloneImpl, b: &HasCloneImpl) { + // Should not be linted, since the Clone impl doesn't override clone_from + *a = b.clone(); +} + +struct FakeClone; + +impl FakeClone { + /// This looks just like `Clone::clone` + fn clone(&self) -> Self { + FakeClone + } +} + +fn ignore_fake_clone() { + let mut a = FakeClone; + let b = FakeClone; + // Should not be linted, since the Clone impl doesn't come from std + a = b.clone(); +} + +fn ignore_generic_clone(a: &mut T, b: &T) { + // Should not be linted, since we don't know the actual clone impl + *a = b.clone(); +} + +macro_rules! clone_inside { + ($a:expr, $b: expr) => { + $a = $b.clone(); + }; +} + +fn clone_inside_macro() { + let mut a = String::new(); + let b = String::new(); + clone_inside!(a, b); +} + +// ToOwned +fn owned_method_mut_ref(mut_string: &mut String, ref_str: &str) { + ref_str.clone_into(mut_string); +} + +fn owned_method_val(mut mut_string: String, ref_str: &str) { + ref_str.clone_into(&mut mut_string); +} + +struct HasDeref { + a: String, +} + +impl Deref for HasDeref { + type Target = String; + fn deref(&self) -> &Self::Target { + &self.a + } +} + +impl DerefMut for HasDeref { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.a + } +} + +fn owned_method_box(mut_box_string: &mut Box, ref_str: &str) { + ref_str.clone_into(&mut (*mut_box_string)); +} + +fn owned_method_deref(mut_box_string: &mut HasDeref, ref_str: &str) { + ref_str.clone_into(&mut (*mut_box_string)); +} + +fn owned_function_mut_ref(mut_thing: &mut String, ref_str: &str) { + ToOwned::clone_into(ref_str, mut_thing); +} + +fn owned_function_val(mut mut_thing: String, ref_str: &str) { + ToOwned::clone_into(ref_str, &mut mut_thing); +} + +struct FakeToOwned; +impl FakeToOwned { + /// This looks just like `ToOwned::to_owned` + fn to_owned(&self) -> Self { + FakeToOwned + } +} + +fn fake_to_owned() { + let mut a = FakeToOwned; + let b = FakeToOwned; + // Should not be linted, since the ToOwned impl doesn't come from std + a = b.to_owned(); +} + +fn main() {} + +/// Trait implementation to allow producing a `Thing` with a low-precedence expression. +impl Add for HasCloneFrom { + type Output = Self; + fn add(self, _: HasCloneFrom) -> Self { + self + } +} +/// Trait implementation to allow producing a `&Thing` with a low-precedence expression. +impl<'a> Add for &'a HasCloneFrom { + type Output = Self; + fn add(self, _: &'a HasCloneFrom) -> Self { + self + } +} +/// Trait implementation to allow producing a `&mut Thing` with a low-precedence expression. +impl<'a> Add for &'a mut HasCloneFrom { + type Output = Self; + fn add(self, _: &'a mut HasCloneFrom) -> Self { + self + } +} diff --git a/tests/ui/assigning_clones.rs b/tests/ui/assigning_clones.rs new file mode 100644 index 00000000000..b9f994d3e03 --- /dev/null +++ b/tests/ui/assigning_clones.rs @@ -0,0 +1,222 @@ +#![allow(unused)] +#![allow(clippy::redundant_clone)] +#![allow(clippy::ptr_arg)] // https://github.com/rust-lang/rust-clippy/issues/10612 +#![allow(clippy::needless_late_init)] +#![allow(clippy::box_collection)] +#![warn(clippy::assigning_clones)] + +use std::borrow::ToOwned; +use std::ops::{Add, Deref, DerefMut}; + +// Clone +pub struct HasCloneFrom; + +impl Clone for HasCloneFrom { + fn clone(&self) -> Self { + Self + } + fn clone_from(&mut self, source: &Self) { + *self = HasCloneFrom; + } +} + +fn clone_method_rhs_val(mut_thing: &mut HasCloneFrom, value_thing: HasCloneFrom) { + *mut_thing = value_thing.clone(); +} + +fn clone_method_rhs_ref(mut_thing: &mut HasCloneFrom, ref_thing: &HasCloneFrom) { + *mut_thing = ref_thing.clone(); +} + +fn clone_method_lhs_val(mut mut_thing: HasCloneFrom, ref_thing: &HasCloneFrom) { + mut_thing = ref_thing.clone(); +} + +fn clone_function_lhs_mut_ref(mut_thing: &mut HasCloneFrom, ref_thing: &HasCloneFrom) { + *mut_thing = Clone::clone(ref_thing); +} + +fn clone_function_lhs_val(mut mut_thing: HasCloneFrom, ref_thing: &HasCloneFrom) { + mut_thing = Clone::clone(ref_thing); +} + +fn clone_function_through_trait(mut_thing: &mut HasCloneFrom, ref_thing: &HasCloneFrom) { + *mut_thing = Clone::clone(ref_thing); +} + +fn clone_function_through_type(mut_thing: &mut HasCloneFrom, ref_thing: &HasCloneFrom) { + *mut_thing = HasCloneFrom::clone(ref_thing); +} + +fn clone_function_fully_qualified(mut_thing: &mut HasCloneFrom, ref_thing: &HasCloneFrom) { + *mut_thing = ::clone(ref_thing); +} + +fn clone_method_lhs_complex(mut_thing: &mut HasCloneFrom, ref_thing: &HasCloneFrom) { + // These parens should be kept as necessary for a receiver + *(mut_thing + &mut HasCloneFrom) = ref_thing.clone(); +} + +fn clone_method_rhs_complex(mut_thing: &mut HasCloneFrom, ref_thing: &HasCloneFrom) { + // These parens should be removed since they are not needed in a function argument + *mut_thing = (ref_thing + ref_thing).clone(); +} + +fn assign_to_init_mut_var(b: HasCloneFrom) -> HasCloneFrom { + let mut a = HasCloneFrom; + for _ in 1..10 { + a = b.clone(); + } + a +} + +fn assign_to_late_init_mut_var(b: HasCloneFrom) { + let mut a; + a = HasCloneFrom; + a = b.clone(); +} + +fn assign_to_uninit_var(b: HasCloneFrom) { + let a; + a = b.clone(); +} + +fn assign_to_uninit_mut_var(b: HasCloneFrom) { + let mut a; + a = b.clone(); +} + +#[derive(Clone)] +pub struct HasDeriveClone; + +fn ignore_derive_clone(a: &mut HasDeriveClone, b: &HasDeriveClone) { + // Should not be linted, since the Clone impl is derived + *a = b.clone(); +} + +pub struct HasCloneImpl; + +impl Clone for HasCloneImpl { + fn clone(&self) -> Self { + Self + } +} + +fn ignore_missing_clone_from(a: &mut HasCloneImpl, b: &HasCloneImpl) { + // Should not be linted, since the Clone impl doesn't override clone_from + *a = b.clone(); +} + +struct FakeClone; + +impl FakeClone { + /// This looks just like `Clone::clone` + fn clone(&self) -> Self { + FakeClone + } +} + +fn ignore_fake_clone() { + let mut a = FakeClone; + let b = FakeClone; + // Should not be linted, since the Clone impl doesn't come from std + a = b.clone(); +} + +fn ignore_generic_clone(a: &mut T, b: &T) { + // Should not be linted, since we don't know the actual clone impl + *a = b.clone(); +} + +macro_rules! clone_inside { + ($a:expr, $b: expr) => { + $a = $b.clone(); + }; +} + +fn clone_inside_macro() { + let mut a = String::new(); + let b = String::new(); + clone_inside!(a, b); +} + +// ToOwned +fn owned_method_mut_ref(mut_string: &mut String, ref_str: &str) { + *mut_string = ref_str.to_owned(); +} + +fn owned_method_val(mut mut_string: String, ref_str: &str) { + mut_string = ref_str.to_owned(); +} + +struct HasDeref { + a: String, +} + +impl Deref for HasDeref { + type Target = String; + fn deref(&self) -> &Self::Target { + &self.a + } +} + +impl DerefMut for HasDeref { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.a + } +} + +fn owned_method_box(mut_box_string: &mut Box, ref_str: &str) { + **mut_box_string = ref_str.to_owned(); +} + +fn owned_method_deref(mut_box_string: &mut HasDeref, ref_str: &str) { + **mut_box_string = ref_str.to_owned(); +} + +fn owned_function_mut_ref(mut_thing: &mut String, ref_str: &str) { + *mut_thing = ToOwned::to_owned(ref_str); +} + +fn owned_function_val(mut mut_thing: String, ref_str: &str) { + mut_thing = ToOwned::to_owned(ref_str); +} + +struct FakeToOwned; +impl FakeToOwned { + /// This looks just like `ToOwned::to_owned` + fn to_owned(&self) -> Self { + FakeToOwned + } +} + +fn fake_to_owned() { + let mut a = FakeToOwned; + let b = FakeToOwned; + // Should not be linted, since the ToOwned impl doesn't come from std + a = b.to_owned(); +} + +fn main() {} + +/// Trait implementation to allow producing a `Thing` with a low-precedence expression. +impl Add for HasCloneFrom { + type Output = Self; + fn add(self, _: HasCloneFrom) -> Self { + self + } +} +/// Trait implementation to allow producing a `&Thing` with a low-precedence expression. +impl<'a> Add for &'a HasCloneFrom { + type Output = Self; + fn add(self, _: &'a HasCloneFrom) -> Self { + self + } +} +/// Trait implementation to allow producing a `&mut Thing` with a low-precedence expression. +impl<'a> Add for &'a mut HasCloneFrom { + type Output = Self; + fn add(self, _: &'a mut HasCloneFrom) -> Self { + self + } +} diff --git a/tests/ui/assigning_clones.stderr b/tests/ui/assigning_clones.stderr new file mode 100644 index 00000000000..b76323f3606 --- /dev/null +++ b/tests/ui/assigning_clones.stderr @@ -0,0 +1,107 @@ +error: assigning the result of `Clone::clone()` may be inefficient + --> tests/ui/assigning_clones.rs:24:5 + | +LL | *mut_thing = value_thing.clone(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_from()`: `mut_thing.clone_from(&value_thing)` + | + = note: `-D clippy::assigning-clones` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::assigning_clones)]` + +error: assigning the result of `Clone::clone()` may be inefficient + --> tests/ui/assigning_clones.rs:28:5 + | +LL | *mut_thing = ref_thing.clone(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_from()`: `mut_thing.clone_from(ref_thing)` + +error: assigning the result of `Clone::clone()` may be inefficient + --> tests/ui/assigning_clones.rs:32:5 + | +LL | mut_thing = ref_thing.clone(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_from()`: `mut_thing.clone_from(ref_thing)` + +error: assigning the result of `Clone::clone()` may be inefficient + --> tests/ui/assigning_clones.rs:36:5 + | +LL | *mut_thing = Clone::clone(ref_thing); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_from()`: `Clone::clone_from(mut_thing, ref_thing)` + +error: assigning the result of `Clone::clone()` may be inefficient + --> tests/ui/assigning_clones.rs:40:5 + | +LL | mut_thing = Clone::clone(ref_thing); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_from()`: `Clone::clone_from(&mut mut_thing, ref_thing)` + +error: assigning the result of `Clone::clone()` may be inefficient + --> tests/ui/assigning_clones.rs:44:5 + | +LL | *mut_thing = Clone::clone(ref_thing); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_from()`: `Clone::clone_from(mut_thing, ref_thing)` + +error: assigning the result of `Clone::clone()` may be inefficient + --> tests/ui/assigning_clones.rs:48:5 + | +LL | *mut_thing = HasCloneFrom::clone(ref_thing); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_from()`: `Clone::clone_from(mut_thing, ref_thing)` + +error: assigning the result of `Clone::clone()` may be inefficient + --> tests/ui/assigning_clones.rs:52:5 + | +LL | *mut_thing = ::clone(ref_thing); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_from()`: `Clone::clone_from(mut_thing, ref_thing)` + +error: assigning the result of `Clone::clone()` may be inefficient + --> tests/ui/assigning_clones.rs:57:5 + | +LL | *(mut_thing + &mut HasCloneFrom) = ref_thing.clone(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_from()`: `(mut_thing + &mut HasCloneFrom).clone_from(ref_thing)` + +error: assigning the result of `Clone::clone()` may be inefficient + --> tests/ui/assigning_clones.rs:62:5 + | +LL | *mut_thing = (ref_thing + ref_thing).clone(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_from()`: `mut_thing.clone_from(ref_thing + ref_thing)` + +error: assigning the result of `Clone::clone()` may be inefficient + --> tests/ui/assigning_clones.rs:68:9 + | +LL | a = b.clone(); + | ^^^^^^^^^^^^^ help: use `clone_from()`: `a.clone_from(&b)` + +error: assigning the result of `ToOwned::to_owned()` may be inefficient + --> tests/ui/assigning_clones.rs:145:5 + | +LL | *mut_string = ref_str.to_owned(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_into()`: `ref_str.clone_into(mut_string)` + +error: assigning the result of `ToOwned::to_owned()` may be inefficient + --> tests/ui/assigning_clones.rs:149:5 + | +LL | mut_string = ref_str.to_owned(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_into()`: `ref_str.clone_into(&mut mut_string)` + +error: assigning the result of `ToOwned::to_owned()` may be inefficient + --> tests/ui/assigning_clones.rs:170:5 + | +LL | **mut_box_string = ref_str.to_owned(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_into()`: `ref_str.clone_into(&mut (*mut_box_string))` + +error: assigning the result of `ToOwned::to_owned()` may be inefficient + --> tests/ui/assigning_clones.rs:174:5 + | +LL | **mut_box_string = ref_str.to_owned(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_into()`: `ref_str.clone_into(&mut (*mut_box_string))` + +error: assigning the result of `ToOwned::to_owned()` may be inefficient + --> tests/ui/assigning_clones.rs:178:5 + | +LL | *mut_thing = ToOwned::to_owned(ref_str); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_into()`: `ToOwned::clone_into(ref_str, mut_thing)` + +error: assigning the result of `ToOwned::to_owned()` may be inefficient + --> tests/ui/assigning_clones.rs:182:5 + | +LL | mut_thing = ToOwned::to_owned(ref_str); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_into()`: `ToOwned::clone_into(ref_str, &mut mut_thing)` + +error: aborting due to 17 previous errors + diff --git a/tests/ui/crashes/unreachable-array-or-slice.rs b/tests/ui/crashes/unreachable-array-or-slice.rs index b56abccbd41..e920e58d6ec 100644 --- a/tests/ui/crashes/unreachable-array-or-slice.rs +++ b/tests/ui/crashes/unreachable-array-or-slice.rs @@ -3,6 +3,6 @@ pub fn main() { let Self::anything_here_kills_it(a, b, ..) = Foo(5, 5, 5, 5); match [5, 5, 5, 5] { - [..] => { } + [..] => {}, } } diff --git a/tests/ui/derive_partial_eq_without_eq.fixed b/tests/ui/derive_partial_eq_without_eq.fixed index aa7a95405e0..6f42487bbf4 100644 --- a/tests/ui/derive_partial_eq_without_eq.fixed +++ b/tests/ui/derive_partial_eq_without_eq.fixed @@ -153,4 +153,30 @@ pub enum MissingEqNonExhaustive3 { Bar, } +mod struct_gen { + // issue 9413 + pub trait Group { + type Element: Eq + PartialEq; + } + + pub trait Suite { + type Group: Group; + } + + #[derive(PartialEq, Eq)] + //~^ ERROR: you are deriving `PartialEq` and can implement `Eq` + pub struct Foo(::Element); + + #[derive(PartialEq, Eq)] + pub struct Bar(i32, ::Element); + + // issue 9319 + #[derive(PartialEq, Eq)] + //~^ ERROR: you are deriving `PartialEq` and can implement `Eq` + pub struct Oof(T); + + #[derive(PartialEq, Eq)] + pub struct Rab(T); +} + fn main() {} diff --git a/tests/ui/derive_partial_eq_without_eq.rs b/tests/ui/derive_partial_eq_without_eq.rs index 90ac7a7989e..24f687c6c9d 100644 --- a/tests/ui/derive_partial_eq_without_eq.rs +++ b/tests/ui/derive_partial_eq_without_eq.rs @@ -153,4 +153,30 @@ pub enum MissingEqNonExhaustive3 { Bar, } +mod struct_gen { + // issue 9413 + pub trait Group { + type Element: Eq + PartialEq; + } + + pub trait Suite { + type Group: Group; + } + + #[derive(PartialEq)] + //~^ ERROR: you are deriving `PartialEq` and can implement `Eq` + pub struct Foo(::Element); + + #[derive(PartialEq, Eq)] + pub struct Bar(i32, ::Element); + + // issue 9319 + #[derive(PartialEq)] + //~^ ERROR: you are deriving `PartialEq` and can implement `Eq` + pub struct Oof(T); + + #[derive(PartialEq, Eq)] + pub struct Rab(T); +} + fn main() {} diff --git a/tests/ui/derive_partial_eq_without_eq.stderr b/tests/ui/derive_partial_eq_without_eq.stderr index 42b9895121f..3d92112dc36 100644 --- a/tests/ui/derive_partial_eq_without_eq.stderr +++ b/tests/ui/derive_partial_eq_without_eq.stderr @@ -67,5 +67,17 @@ error: you are deriving `PartialEq` and can implement `Eq` LL | #[derive(PartialEq)] | ^^^^^^^^^ help: consider deriving `Eq` as well: `PartialEq, Eq` -error: aborting due to 11 previous errors +error: you are deriving `PartialEq` and can implement `Eq` + --> tests/ui/derive_partial_eq_without_eq.rs:166:14 + | +LL | #[derive(PartialEq)] + | ^^^^^^^^^ help: consider deriving `Eq` as well: `PartialEq, Eq` + +error: you are deriving `PartialEq` and can implement `Eq` + --> tests/ui/derive_partial_eq_without_eq.rs:174:14 + | +LL | #[derive(PartialEq)] + | ^^^^^^^^^ help: consider deriving `Eq` as well: `PartialEq, Eq` + +error: aborting due to 13 previous errors diff --git a/tests/ui/doc/doc-fixable.fixed b/tests/ui/doc/doc-fixable.fixed index 16f7bafd44b..178d4a1aa2b 100644 --- a/tests/ui/doc/doc-fixable.fixed +++ b/tests/ui/doc/doc-fixable.fixed @@ -230,3 +230,8 @@ fn issue_11568() {} /// There is no try (`do()` or `do_not()`). fn parenthesized_word() {} + +/// `ABes` +/// OSes +/// UXes +fn plural_acronym_test() {} diff --git a/tests/ui/doc/doc-fixable.rs b/tests/ui/doc/doc-fixable.rs index 4058b2bad74..01edb44c64c 100644 --- a/tests/ui/doc/doc-fixable.rs +++ b/tests/ui/doc/doc-fixable.rs @@ -230,3 +230,8 @@ fn issue_11568() {} /// There is no try (do() or do_not()). fn parenthesized_word() {} + +/// ABes +/// OSes +/// UXes +fn plural_acronym_test() {} diff --git a/tests/ui/doc/doc-fixable.stderr b/tests/ui/doc/doc-fixable.stderr index 7db9ff2b83b..ac876306b39 100644 --- a/tests/ui/doc/doc-fixable.stderr +++ b/tests/ui/doc/doc-fixable.stderr @@ -341,5 +341,16 @@ help: try LL | /// There is no try (do() or `do_not()`). | ~~~~~~~~~~ -error: aborting due to 31 previous errors +error: item in documentation is missing backticks + --> tests/ui/doc/doc-fixable.rs:234:5 + | +LL | /// ABes + | ^^^^ + | +help: try + | +LL | /// `ABes` + | ~~~~~~ + +error: aborting due to 32 previous errors diff --git a/tests/ui/doc/issue_9473.fixed b/tests/ui/doc/issue_9473.fixed new file mode 100644 index 00000000000..276ce7620ca --- /dev/null +++ b/tests/ui/doc/issue_9473.fixed @@ -0,0 +1,9 @@ +#![warn(clippy::doc_markdown)] + +// Should not warn! +/// Blah blah blah [FooBar]<[FooBar]>. +pub struct Foo(u32); + +// Should warn. +/// Blah blah blah [FooBar]<[FooBar]>[`FooBar`]. +pub struct FooBar(u32); diff --git a/tests/ui/doc/issue_9473.rs b/tests/ui/doc/issue_9473.rs new file mode 100644 index 00000000000..52527f7106d --- /dev/null +++ b/tests/ui/doc/issue_9473.rs @@ -0,0 +1,9 @@ +#![warn(clippy::doc_markdown)] + +// Should not warn! +/// Blah blah blah [FooBar]<[FooBar]>. +pub struct Foo(u32); + +// Should warn. +/// Blah blah blah [FooBar]<[FooBar]>[FooBar]. +pub struct FooBar(u32); diff --git a/tests/ui/doc/issue_9473.stderr b/tests/ui/doc/issue_9473.stderr new file mode 100644 index 00000000000..35aa2884cc1 --- /dev/null +++ b/tests/ui/doc/issue_9473.stderr @@ -0,0 +1,15 @@ +error: item in documentation is missing backticks + --> tests/ui/doc/issue_9473.rs:8:58 + | +LL | /// Blah blah blah [FooBar]<[FooBar]>[FooBar]. + | ^^^^^^ + | + = note: `-D clippy::doc-markdown` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::doc_markdown)]` +help: try + | +LL | /// Blah blah blah [FooBar]<[FooBar]>[`FooBar`]. + | ~~~~~~~~ + +error: aborting due to 1 previous error + diff --git a/tests/ui/else_if_without_else.rs b/tests/ui/else_if_without_else.rs index eb5e2266540..e7786f7dd27 100644 --- a/tests/ui/else_if_without_else.rs +++ b/tests/ui/else_if_without_else.rs @@ -1,3 +1,5 @@ +//@compile-flags: -Zdeduplicate-diagnostics=yes + #![warn(clippy::all)] #![warn(clippy::else_if_without_else)] diff --git a/tests/ui/else_if_without_else.stderr b/tests/ui/else_if_without_else.stderr index 80355cb2dba..3bb840f39e7 100644 --- a/tests/ui/else_if_without_else.stderr +++ b/tests/ui/else_if_without_else.stderr @@ -1,5 +1,5 @@ error: `if` expression with an `else if`, but without a final `else` - --> tests/ui/else_if_without_else.rs:45:12 + --> tests/ui/else_if_without_else.rs:47:12 | LL | } else if bla2() { | ____________^ @@ -13,7 +13,7 @@ LL | | } = help: to override `-D warnings` add `#[allow(clippy::else_if_without_else)]` error: `if` expression with an `else if`, but without a final `else` - --> tests/ui/else_if_without_else.rs:54:12 + --> tests/ui/else_if_without_else.rs:56:12 | LL | } else if bla3() { | ____________^ diff --git a/tests/ui/empty_docs.rs b/tests/ui/empty_docs.rs index c47a603e71b..272fab7d5ca 100644 --- a/tests/ui/empty_docs.rs +++ b/tests/ui/empty_docs.rs @@ -1,5 +1,7 @@ #![allow(unused)] #![warn(clippy::empty_docs)] +#![allow(clippy::mixed_attributes_style)] + mod outer { //! diff --git a/tests/ui/empty_docs.stderr b/tests/ui/empty_docs.stderr index 3f1d071fb13..f12aead6aa7 100644 --- a/tests/ui/empty_docs.stderr +++ b/tests/ui/empty_docs.stderr @@ -1,5 +1,5 @@ error: empty doc comment - --> tests/ui/empty_docs.rs:4:5 + --> tests/ui/empty_docs.rs:6:5 | LL | //! | ^^^ @@ -9,7 +9,7 @@ LL | //! = help: to override `-D warnings` add `#[allow(clippy::empty_docs)]` error: empty doc comment - --> tests/ui/empty_docs.rs:12:5 + --> tests/ui/empty_docs.rs:14:5 | LL | /// | ^^^ @@ -17,7 +17,7 @@ LL | /// = help: consider removing or filling it error: empty doc comment - --> tests/ui/empty_docs.rs:14:9 + --> tests/ui/empty_docs.rs:16:9 | LL | /// | ^^^ @@ -25,7 +25,7 @@ LL | /// = help: consider removing or filling it error: empty doc comment - --> tests/ui/empty_docs.rs:25:5 + --> tests/ui/empty_docs.rs:27:5 | LL | #[doc = ""] | ^^^^^^^^^^^ @@ -33,7 +33,7 @@ LL | #[doc = ""] = help: consider removing or filling it error: empty doc comment - --> tests/ui/empty_docs.rs:28:5 + --> tests/ui/empty_docs.rs:30:5 | LL | / #[doc = ""] LL | | #[doc = ""] @@ -42,7 +42,7 @@ LL | | #[doc = ""] = help: consider removing or filling it error: empty doc comment - --> tests/ui/empty_docs.rs:35:5 + --> tests/ui/empty_docs.rs:37:5 | LL | /// | ^^^ @@ -50,7 +50,7 @@ LL | /// = help: consider removing or filling it error: empty doc comment - --> tests/ui/empty_docs.rs:48:13 + --> tests/ui/empty_docs.rs:50:13 | LL | /*! */ | ^^^^^^ @@ -58,7 +58,7 @@ LL | /*! */ = help: consider removing or filling it error: empty doc comment - --> tests/ui/empty_docs.rs:56:13 + --> tests/ui/empty_docs.rs:58:13 | LL | /// | ^^^ @@ -66,7 +66,7 @@ LL | /// = help: consider removing or filling it error: empty doc comment - --> tests/ui/empty_docs.rs:64:9 + --> tests/ui/empty_docs.rs:66:9 | LL | /// | ^^^ diff --git a/tests/ui/entry.fixed b/tests/ui/entry.fixed index 4099fe7e139..71ec13f4610 100644 --- a/tests/ui/entry.fixed +++ b/tests/ui/entry.fixed @@ -165,4 +165,15 @@ pub fn issue_10331() { } } +/// Issue 11935 +/// Do not suggest using entries if the map is used inside the `insert` expression. +pub fn issue_11935() { + let mut counts: HashMap = HashMap::new(); + if !counts.contains_key(&1) { + counts.insert(1, 1); + } else { + counts.insert(1, counts.get(&1).unwrap() + 1); + } +} + fn main() {} diff --git a/tests/ui/entry.rs b/tests/ui/entry.rs index 409be0aa060..86092b7c055 100644 --- a/tests/ui/entry.rs +++ b/tests/ui/entry.rs @@ -169,4 +169,15 @@ pub fn issue_10331() { } } +/// Issue 11935 +/// Do not suggest using entries if the map is used inside the `insert` expression. +pub fn issue_11935() { + let mut counts: HashMap = HashMap::new(); + if !counts.contains_key(&1) { + counts.insert(1, 1); + } else { + counts.insert(1, counts.get(&1).unwrap() + 1); + } +} + fn main() {} diff --git a/tests/ui/explicit_iter_loop.fixed b/tests/ui/explicit_iter_loop.fixed index 06229a52a18..f38b34c5a7c 100644 --- a/tests/ui/explicit_iter_loop.fixed +++ b/tests/ui/explicit_iter_loop.fixed @@ -6,7 +6,7 @@ clippy::deref_addrof, clippy::unnecessary_mut_passed, dead_code, - non_local_definitions, + non_local_definitions )] use core::slice; diff --git a/tests/ui/explicit_iter_loop.rs b/tests/ui/explicit_iter_loop.rs index c2bf45ab2e9..2e701ada5ac 100644 --- a/tests/ui/explicit_iter_loop.rs +++ b/tests/ui/explicit_iter_loop.rs @@ -6,7 +6,7 @@ clippy::deref_addrof, clippy::unnecessary_mut_passed, dead_code, - non_local_definitions, + non_local_definitions )] use core::slice; diff --git a/tests/ui/field_reassign_with_default.rs b/tests/ui/field_reassign_with_default.rs index 2045b1eebcd..620cffb4f04 100644 --- a/tests/ui/field_reassign_with_default.rs +++ b/tests/ui/field_reassign_with_default.rs @@ -2,6 +2,7 @@ //@aux-build:proc_macros.rs #![warn(clippy::field_reassign_with_default)] +#![allow(clippy::assigning_clones)] #[macro_use] extern crate proc_macro_derive; diff --git a/tests/ui/field_reassign_with_default.stderr b/tests/ui/field_reassign_with_default.stderr index bc032834920..ae909475c6f 100644 --- a/tests/ui/field_reassign_with_default.stderr +++ b/tests/ui/field_reassign_with_default.stderr @@ -1,11 +1,11 @@ error: field assignment outside of initializer for an instance created with Default::default() - --> tests/ui/field_reassign_with_default.rs:56:5 + --> tests/ui/field_reassign_with_default.rs:57:5 | LL | a.i = 42; | ^^^^^^^^^ | note: consider initializing the variable with `main::A { i: 42, ..Default::default() }` and removing relevant reassignments - --> tests/ui/field_reassign_with_default.rs:55:5 + --> tests/ui/field_reassign_with_default.rs:56:5 | LL | let mut a: A = Default::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -13,121 +13,121 @@ LL | let mut a: A = Default::default(); = help: to override `-D warnings` add `#[allow(clippy::field_reassign_with_default)]` error: field assignment outside of initializer for an instance created with Default::default() - --> tests/ui/field_reassign_with_default.rs:96:5 + --> tests/ui/field_reassign_with_default.rs:97:5 | LL | a.j = 43; | ^^^^^^^^^ | note: consider initializing the variable with `main::A { j: 43, i: 42 }` and removing relevant reassignments - --> tests/ui/field_reassign_with_default.rs:95:5 + --> tests/ui/field_reassign_with_default.rs:96:5 | LL | let mut a: A = Default::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: field assignment outside of initializer for an instance created with Default::default() - --> tests/ui/field_reassign_with_default.rs:101:5 + --> tests/ui/field_reassign_with_default.rs:102:5 | LL | a.i = 42; | ^^^^^^^^^ | note: consider initializing the variable with `main::A { i: 42, j: 44 }` and removing relevant reassignments - --> tests/ui/field_reassign_with_default.rs:100:5 + --> tests/ui/field_reassign_with_default.rs:101:5 | LL | let mut a: A = Default::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: field assignment outside of initializer for an instance created with Default::default() - --> tests/ui/field_reassign_with_default.rs:107:5 + --> tests/ui/field_reassign_with_default.rs:108:5 | LL | a.i = 42; | ^^^^^^^^^ | note: consider initializing the variable with `main::A { i: 42, ..Default::default() }` and removing relevant reassignments - --> tests/ui/field_reassign_with_default.rs:106:5 + --> tests/ui/field_reassign_with_default.rs:107:5 | LL | let mut a = A::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: field assignment outside of initializer for an instance created with Default::default() - --> tests/ui/field_reassign_with_default.rs:117:5 + --> tests/ui/field_reassign_with_default.rs:118:5 | LL | a.i = Default::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ | note: consider initializing the variable with `main::A { i: Default::default(), ..Default::default() }` and removing relevant reassignments - --> tests/ui/field_reassign_with_default.rs:116:5 + --> tests/ui/field_reassign_with_default.rs:117:5 | LL | let mut a: A = Default::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: field assignment outside of initializer for an instance created with Default::default() - --> tests/ui/field_reassign_with_default.rs:121:5 + --> tests/ui/field_reassign_with_default.rs:122:5 | LL | a.i = Default::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ | note: consider initializing the variable with `main::A { i: Default::default(), j: 45 }` and removing relevant reassignments - --> tests/ui/field_reassign_with_default.rs:120:5 + --> tests/ui/field_reassign_with_default.rs:121:5 | LL | let mut a: A = Default::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: field assignment outside of initializer for an instance created with Default::default() - --> tests/ui/field_reassign_with_default.rs:143:5 + --> tests/ui/field_reassign_with_default.rs:144:5 | LL | a.i = vec![1]; | ^^^^^^^^^^^^^^ | note: consider initializing the variable with `C { i: vec![1], ..Default::default() }` and removing relevant reassignments - --> tests/ui/field_reassign_with_default.rs:142:5 + --> tests/ui/field_reassign_with_default.rs:143:5 | LL | let mut a: C = C::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: field assignment outside of initializer for an instance created with Default::default() - --> tests/ui/field_reassign_with_default.rs:161:5 + --> tests/ui/field_reassign_with_default.rs:162:5 | LL | a.i = true; | ^^^^^^^^^^^ | note: consider initializing the variable with `Wrapper:: { i: true }` and removing relevant reassignments - --> tests/ui/field_reassign_with_default.rs:160:5 + --> tests/ui/field_reassign_with_default.rs:161:5 | LL | let mut a: Wrapper = Default::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: field assignment outside of initializer for an instance created with Default::default() - --> tests/ui/field_reassign_with_default.rs:164:5 + --> tests/ui/field_reassign_with_default.rs:165:5 | LL | a.i = 42; | ^^^^^^^^^ | note: consider initializing the variable with `WrapperMulti:: { i: 42, ..Default::default() }` and removing relevant reassignments - --> tests/ui/field_reassign_with_default.rs:163:5 + --> tests/ui/field_reassign_with_default.rs:164:5 | LL | let mut a: WrapperMulti = Default::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: field assignment outside of initializer for an instance created with Default::default() - --> tests/ui/field_reassign_with_default.rs:235:13 + --> tests/ui/field_reassign_with_default.rs:236:13 | LL | f.name = name.len(); | ^^^^^^^^^^^^^^^^^^^^ | note: consider initializing the variable with `issue6312::ImplDropAllCopy { name: name.len(), ..Default::default() }` and removing relevant reassignments - --> tests/ui/field_reassign_with_default.rs:234:13 + --> tests/ui/field_reassign_with_default.rs:235:13 | LL | let mut f = ImplDropAllCopy::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: field assignment outside of initializer for an instance created with Default::default() - --> tests/ui/field_reassign_with_default.rs:251:13 + --> tests/ui/field_reassign_with_default.rs:252:13 | LL | f.name = name.len(); | ^^^^^^^^^^^^^^^^^^^^ | note: consider initializing the variable with `issue6312::NoDropAllCopy { name: name.len(), ..Default::default() }` and removing relevant reassignments - --> tests/ui/field_reassign_with_default.rs:250:13 + --> tests/ui/field_reassign_with_default.rs:251:13 | LL | let mut f = NoDropAllCopy::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/identity_op.fixed b/tests/ui/identity_op.fixed index 660e9a21b18..b18d8560f6f 100644 --- a/tests/ui/identity_op.fixed +++ b/tests/ui/identity_op.fixed @@ -134,7 +134,7 @@ fn main() { //~^ ERROR: this operation has no effect f(if b { 1 } else { 2 } + 3); //~^ ERROR: this operation has no effect - + const _: i32 = { 2 * 4 } + 3; //~^ ERROR: this operation has no effect const _: i32 = { 1 + 2 * 3 } + 3; diff --git a/tests/ui/identity_op.rs b/tests/ui/identity_op.rs index bbef531e9dc..f1f01b42447 100644 --- a/tests/ui/identity_op.rs +++ b/tests/ui/identity_op.rs @@ -134,7 +134,7 @@ fn f(_: i32) { //~^ ERROR: this operation has no effect f(0 + if b { 1 } else { 2 } + 3); //~^ ERROR: this operation has no effect - + const _: i32 = { 2 * 4 } + 0 + 3; //~^ ERROR: this operation has no effect const _: i32 = 0 + { 1 + 2 * 3 } + 3; diff --git a/tests/ui/indexing_slicing_index.rs b/tests/ui/indexing_slicing_index.rs index 2ababad7fc7..27ee2f91594 100644 --- a/tests/ui/indexing_slicing_index.rs +++ b/tests/ui/indexing_slicing_index.rs @@ -1,3 +1,5 @@ +//@compile-flags: -Zdeduplicate-diagnostics=yes + #![feature(inline_const)] #![warn(clippy::indexing_slicing)] // We also check the out_of_bounds_indexing lint here, because it lints similar things and diff --git a/tests/ui/indexing_slicing_index.stderr b/tests/ui/indexing_slicing_index.stderr index 06a4defcb93..5f62ec9b556 100644 --- a/tests/ui/indexing_slicing_index.stderr +++ b/tests/ui/indexing_slicing_index.stderr @@ -1,5 +1,5 @@ error: indexing may panic - --> tests/ui/indexing_slicing_index.rs:14:20 + --> tests/ui/indexing_slicing_index.rs:16:20 | LL | const REF: &i32 = &ARR[idx()]; // This should be linted, since `suppress-restriction-lint-in-const` default is false. | ^^^^^^^^^^ @@ -10,19 +10,19 @@ LL | const REF: &i32 = &ARR[idx()]; // This should be linted, since `suppress-re = help: to override `-D warnings` add `#[allow(clippy::indexing_slicing)]` error[E0080]: evaluation of `main::{constant#3}` failed - --> tests/ui/indexing_slicing_index.rs:46:14 + --> tests/ui/indexing_slicing_index.rs:48:14 | LL | const { &ARR[idx4()] }; | ^^^^^^^^^^^ index out of bounds: the length is 2 but the index is 4 note: erroneous constant encountered - --> tests/ui/indexing_slicing_index.rs:46:5 + --> tests/ui/indexing_slicing_index.rs:48:5 | LL | const { &ARR[idx4()] }; | ^^^^^^^^^^^^^^^^^^^^^^ error: indexing may panic - --> tests/ui/indexing_slicing_index.rs:27:5 + --> tests/ui/indexing_slicing_index.rs:29:5 | LL | x[index]; | ^^^^^^^^ @@ -30,7 +30,7 @@ LL | x[index]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: index is out of bounds - --> tests/ui/indexing_slicing_index.rs:30:5 + --> tests/ui/indexing_slicing_index.rs:32:5 | LL | x[4]; | ^^^^ @@ -39,13 +39,13 @@ LL | x[4]; = help: to override `-D warnings` add `#[allow(clippy::out_of_bounds_indexing)]` error: index is out of bounds - --> tests/ui/indexing_slicing_index.rs:32:5 + --> tests/ui/indexing_slicing_index.rs:34:5 | LL | x[1 << 3]; | ^^^^^^^^^ error: indexing may panic - --> tests/ui/indexing_slicing_index.rs:43:14 + --> tests/ui/indexing_slicing_index.rs:45:14 | LL | const { &ARR[idx()] }; | ^^^^^^^^^^ @@ -54,7 +54,7 @@ LL | const { &ARR[idx()] }; = note: the suggestion might not be applicable in constant blocks error: indexing may panic - --> tests/ui/indexing_slicing_index.rs:46:14 + --> tests/ui/indexing_slicing_index.rs:48:14 | LL | const { &ARR[idx4()] }; | ^^^^^^^^^^^ @@ -63,13 +63,13 @@ LL | const { &ARR[idx4()] }; = note: the suggestion might not be applicable in constant blocks error: index is out of bounds - --> tests/ui/indexing_slicing_index.rs:53:5 + --> tests/ui/indexing_slicing_index.rs:55:5 | LL | y[4]; | ^^^^ error: indexing may panic - --> tests/ui/indexing_slicing_index.rs:56:5 + --> tests/ui/indexing_slicing_index.rs:58:5 | LL | v[0]; | ^^^^ @@ -77,7 +77,7 @@ LL | v[0]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: indexing may panic - --> tests/ui/indexing_slicing_index.rs:58:5 + --> tests/ui/indexing_slicing_index.rs:60:5 | LL | v[10]; | ^^^^^ @@ -85,7 +85,7 @@ LL | v[10]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: indexing may panic - --> tests/ui/indexing_slicing_index.rs:60:5 + --> tests/ui/indexing_slicing_index.rs:62:5 | LL | v[1 << 3]; | ^^^^^^^^^ @@ -93,13 +93,13 @@ LL | v[1 << 3]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: index is out of bounds - --> tests/ui/indexing_slicing_index.rs:68:5 + --> tests/ui/indexing_slicing_index.rs:70:5 | LL | x[N]; | ^^^^ error: indexing may panic - --> tests/ui/indexing_slicing_index.rs:71:5 + --> tests/ui/indexing_slicing_index.rs:73:5 | LL | v[N]; | ^^^^ @@ -107,7 +107,7 @@ LL | v[N]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: indexing may panic - --> tests/ui/indexing_slicing_index.rs:73:5 + --> tests/ui/indexing_slicing_index.rs:75:5 | LL | v[M]; | ^^^^ @@ -115,7 +115,7 @@ LL | v[M]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: index is out of bounds - --> tests/ui/indexing_slicing_index.rs:77:13 + --> tests/ui/indexing_slicing_index.rs:79:13 | LL | let _ = x[4]; | ^^^^ diff --git a/tests/ui/let_underscore_untyped.rs b/tests/ui/let_underscore_untyped.rs index bd94a3ada18..6275b6f970a 100644 --- a/tests/ui/let_underscore_untyped.rs +++ b/tests/ui/let_underscore_untyped.rs @@ -73,3 +73,5 @@ fn main() { #[allow(clippy::let_underscore_untyped)] let _ = a(); } + +async fn dont_lint_async_prototype(_: u8) {} diff --git a/tests/ui/manual_let_else.rs b/tests/ui/manual_let_else.rs index 5d94660ec89..1fb252e3f97 100644 --- a/tests/ui/manual_let_else.rs +++ b/tests/ui/manual_let_else.rs @@ -1,3 +1,4 @@ +#![feature(try_blocks)] #![allow(unused_braces, unused_variables, dead_code)] #![allow( clippy::collapsible_else_if, @@ -446,3 +447,12 @@ struct U { w: T, x: T, } + +fn issue12337() { + // We want to generally silence question_mark lints within try blocks, since `?` has different + // behavior to `return`, and question_mark calls into manual_let_else logic, so make sure that + // we still emit a lint for manual_let_else + let _: Option<()> = try { + let v = if let Some(v_some) = g() { v_some } else { return }; + }; +} diff --git a/tests/ui/manual_let_else.stderr b/tests/ui/manual_let_else.stderr index b6433fc460c..7012c6b8891 100644 --- a/tests/ui/manual_let_else.stderr +++ b/tests/ui/manual_let_else.stderr @@ -1,5 +1,5 @@ error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:27:5 + --> tests/ui/manual_let_else.rs:28:5 | LL | let v = if let Some(v_some) = g() { v_some } else { return }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v) = g() else { return };` @@ -8,7 +8,7 @@ LL | let v = if let Some(v_some) = g() { v_some } else { return }; = help: to override `-D warnings` add `#[allow(clippy::manual_let_else)]` error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:30:5 + --> tests/ui/manual_let_else.rs:31:5 | LL | / let v = if let Some(v_some) = g() { LL | | @@ -26,7 +26,7 @@ LL + }; | error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:37:5 + --> tests/ui/manual_let_else.rs:38:5 | LL | / let v = if let Some(v) = g() { LL | | @@ -47,25 +47,25 @@ LL + }; | error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:49:9 + --> tests/ui/manual_let_else.rs:50:9 | LL | let v = if let Some(v_some) = g() { v_some } else { continue }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v) = g() else { continue };` error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:51:9 + --> tests/ui/manual_let_else.rs:52:9 | LL | let v = if let Some(v_some) = g() { v_some } else { break }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v) = g() else { break };` error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:56:5 + --> tests/ui/manual_let_else.rs:57:5 | LL | let v = if let Some(v_some) = g() { v_some } else { panic!() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v) = g() else { panic!() };` error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:60:5 + --> tests/ui/manual_let_else.rs:61:5 | LL | / let v = if let Some(v_some) = g() { LL | | @@ -83,7 +83,7 @@ LL + }; | error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:68:5 + --> tests/ui/manual_let_else.rs:69:5 | LL | / let v = if let Some(v_some) = g() { LL | | @@ -101,7 +101,7 @@ LL + }; | error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:76:5 + --> tests/ui/manual_let_else.rs:77:5 | LL | / let v = if let Some(v_some) = g() { LL | | @@ -121,7 +121,7 @@ LL + }; | error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:85:5 + --> tests/ui/manual_let_else.rs:86:5 | LL | / let v = if let Some(v_some) = g() { LL | | @@ -141,7 +141,7 @@ LL + }; | error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:94:5 + --> tests/ui/manual_let_else.rs:95:5 | LL | / let v = if let Some(v_some) = g() { LL | | @@ -168,7 +168,7 @@ LL + }; | error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:110:5 + --> tests/ui/manual_let_else.rs:111:5 | LL | / let v = if let Some(v_some) = g() { LL | | @@ -190,7 +190,7 @@ LL + }; | error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:121:5 + --> tests/ui/manual_let_else.rs:122:5 | LL | / let v = if let Some(v_some) = g() { LL | | @@ -217,7 +217,7 @@ LL + }; | error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:137:5 + --> tests/ui/manual_let_else.rs:138:5 | LL | / let v = if let Some(v_some) = g() { LL | | @@ -239,7 +239,7 @@ LL + }; | error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:148:5 + --> tests/ui/manual_let_else.rs:149:5 | LL | / let v = if let Some(v_some) = g() { LL | | @@ -257,7 +257,7 @@ LL + }; | error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:156:5 + --> tests/ui/manual_let_else.rs:157:5 | LL | / let v = if let Some(v_some) = g() { LL | | @@ -278,7 +278,7 @@ LL + }; | error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:166:5 + --> tests/ui/manual_let_else.rs:167:5 | LL | / let v = if let Some(v_some) = g() { LL | | @@ -299,7 +299,7 @@ LL + } }; | error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:176:5 + --> tests/ui/manual_let_else.rs:177:5 | LL | / let v = if let Some(v_some) = g() { LL | | @@ -328,7 +328,7 @@ LL + }; | error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:194:5 + --> tests/ui/manual_let_else.rs:195:5 | LL | / let (v, w) = if let Some(v_some) = g().map(|v| (v, 42)) { LL | | @@ -346,7 +346,7 @@ LL + }; | error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:202:5 + --> tests/ui/manual_let_else.rs:203:5 | LL | / let (w, S { v }) = if let (Some(v_some), w_some) = (g().map(|_| S { v: 0 }), 0) { LL | | @@ -364,7 +364,7 @@ LL + }; | error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:212:13 + --> tests/ui/manual_let_else.rs:213:13 | LL | let $n = if let Some(v) = $e { v } else { return }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some($n) = g() else { return };` @@ -375,19 +375,19 @@ LL | create_binding_if_some!(w, g()); = note: this error originates in the macro `create_binding_if_some` (in Nightly builds, run with -Z macro-backtrace for more info) error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:221:5 + --> tests/ui/manual_let_else.rs:222:5 | LL | let v = if let Variant::A(a, 0) = e() { a } else { return }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Variant::A(v, 0) = e() else { return };` error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:225:5 + --> tests/ui/manual_let_else.rs:226:5 | LL | let mut v = if let Variant::B(b) = e() { b } else { return }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Variant::B(mut v) = e() else { return };` error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:230:5 + --> tests/ui/manual_let_else.rs:231:5 | LL | / let v = if let Ok(Some(Variant::B(b))) | Err(Some(Variant::A(b, _))) = nested { LL | | @@ -405,19 +405,19 @@ LL + }; | error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:237:5 + --> tests/ui/manual_let_else.rs:238:5 | LL | let v = if let Variant::A(.., a) = e() { a } else { return }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Variant::A(.., v) = e() else { return };` error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:241:5 + --> tests/ui/manual_let_else.rs:242:5 | LL | let w = if let (Some(v), ()) = (g(), ()) { v } else { return }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let (Some(w), ()) = (g(), ()) else { return };` error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:245:5 + --> tests/ui/manual_let_else.rs:246:5 | LL | / let w = if let Some(S { v: x }) = Some(S { v: 0 }) { LL | | @@ -435,7 +435,7 @@ LL + }; | error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:253:5 + --> tests/ui/manual_let_else.rs:254:5 | LL | / let v = if let Some(S { v: x }) = Some(S { v: 0 }) { LL | | @@ -453,7 +453,7 @@ LL + }; | error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:261:5 + --> tests/ui/manual_let_else.rs:262:5 | LL | / let (x, S { v }, w) = if let Some(U { v, w, x }) = None::>> { LL | | @@ -471,7 +471,7 @@ LL + }; | error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:378:5 + --> tests/ui/manual_let_else.rs:379:5 | LL | / let _ = match ff { LL | | @@ -480,5 +480,11 @@ LL | | _ => macro_call!(), LL | | }; | |______^ help: consider writing: `let Some(_) = ff else { macro_call!() };` -error: aborting due to 30 previous errors +error: this could be rewritten as `let...else` + --> tests/ui/manual_let_else.rs:456:9 + | +LL | let v = if let Some(v_some) = g() { v_some } else { return }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v) = g() else { return };` + +error: aborting due to 31 previous errors diff --git a/tests/ui/manual_memcpy/without_loop_counters.rs b/tests/ui/manual_memcpy/without_loop_counters.rs index 8146091a2bb..c917fa7f2d0 100644 --- a/tests/ui/manual_memcpy/without_loop_counters.rs +++ b/tests/ui/manual_memcpy/without_loop_counters.rs @@ -1,5 +1,6 @@ -#![warn(clippy::needless_range_loop, clippy::manual_memcpy)] -#![allow(clippy::useless_vec)] +#![warn(clippy::manual_memcpy)] +#![allow(clippy::assigning_clones, clippy::useless_vec, clippy::needless_range_loop)] + //@no-rustfix const LOOP_OFFSET: usize = 5000; @@ -158,6 +159,59 @@ fn index(&self, _: usize) -> &i32 { //~^ ERROR: it looks like you're manually copying between slices dst[i] = src[i]; } + + // Don't trigger lint for following multi-dimensional arrays + let src = [[0; 5]; 5]; + for i in 0..4 { + dst[i] = src[i + 1][i]; + } + for i in 0..5 { + dst[i] = src[i][i]; + } + for i in 0..5 { + dst[i] = src[i][3]; + } + + let src = [0; 5]; + let mut dst = [[0; 5]; 5]; + for i in 0..5 { + dst[i][i] = src[i]; + } + + let src = [[[0; 5]; 5]; 5]; + let mut dst = [0; 5]; + for i in 0..5 { + dst[i] = src[i][i][i]; + } + for i in 0..5 { + dst[i] = src[i][i][0]; + } + for i in 0..5 { + dst[i] = src[i][0][i]; + } + for i in 0..5 { + dst[i] = src[0][i][i]; + } + for i in 0..5 { + dst[i] = src[0][i][1]; + } + for i in 0..5 { + dst[i] = src[i][0][1]; + } + + // Trigger lint + let src = [[0; 5]; 5]; + let mut dst = [0; 5]; + for i in 0..5 { + //~^ ERROR: it looks like you're manually copying between slices + dst[i] = src[0][i]; + } + + let src = [[[0; 5]; 5]; 5]; + for i in 0..5 { + //~^ ERROR: it looks like you're manually copying between slices + dst[i] = src[0][1][i]; + } } #[warn(clippy::needless_range_loop, clippy::manual_memcpy)] diff --git a/tests/ui/manual_memcpy/without_loop_counters.stderr b/tests/ui/manual_memcpy/without_loop_counters.stderr index 55cca1fb584..803053b2db2 100644 --- a/tests/ui/manual_memcpy/without_loop_counters.stderr +++ b/tests/ui/manual_memcpy/without_loop_counters.stderr @@ -1,5 +1,5 @@ error: it looks like you're manually copying between slices - --> tests/ui/manual_memcpy/without_loop_counters.rs:8:5 + --> tests/ui/manual_memcpy/without_loop_counters.rs:9:5 | LL | / for i in 0..src.len() { LL | | @@ -12,7 +12,7 @@ LL | | } = help: to override `-D warnings` add `#[allow(clippy::manual_memcpy)]` error: it looks like you're manually copying between slices - --> tests/ui/manual_memcpy/without_loop_counters.rs:15:5 + --> tests/ui/manual_memcpy/without_loop_counters.rs:16:5 | LL | / for i in 0..src.len() { LL | | @@ -21,7 +21,7 @@ LL | | } | |_____^ help: try replacing the loop by: `dst[10..(src.len() + 10)].copy_from_slice(&src[..]);` error: it looks like you're manually copying between slices - --> tests/ui/manual_memcpy/without_loop_counters.rs:21:5 + --> tests/ui/manual_memcpy/without_loop_counters.rs:22:5 | LL | / for i in 0..src.len() { LL | | @@ -30,7 +30,7 @@ LL | | } | |_____^ help: try replacing the loop by: `dst[..src.len()].copy_from_slice(&src[10..(src.len() + 10)]);` error: it looks like you're manually copying between slices - --> tests/ui/manual_memcpy/without_loop_counters.rs:27:5 + --> tests/ui/manual_memcpy/without_loop_counters.rs:28:5 | LL | / for i in 11..src.len() { LL | | @@ -39,7 +39,7 @@ LL | | } | |_____^ help: try replacing the loop by: `dst[11..src.len()].copy_from_slice(&src[(11 - 10)..(src.len() - 10)]);` error: it looks like you're manually copying between slices - --> tests/ui/manual_memcpy/without_loop_counters.rs:33:5 + --> tests/ui/manual_memcpy/without_loop_counters.rs:34:5 | LL | / for i in 0..dst.len() { LL | | @@ -48,7 +48,7 @@ LL | | } | |_____^ help: try replacing the loop by: `dst.copy_from_slice(&src[..dst.len()]);` error: it looks like you're manually copying between slices - --> tests/ui/manual_memcpy/without_loop_counters.rs:47:5 + --> tests/ui/manual_memcpy/without_loop_counters.rs:48:5 | LL | / for i in 10..256 { LL | | @@ -64,7 +64,7 @@ LL + dst2[(10 + 500)..(256 + 500)].copy_from_slice(&src[10..256]); | error: it looks like you're manually copying between slices - --> tests/ui/manual_memcpy/without_loop_counters.rs:60:5 + --> tests/ui/manual_memcpy/without_loop_counters.rs:61:5 | LL | / for i in 10..LOOP_OFFSET { LL | | @@ -73,7 +73,7 @@ LL | | } | |_____^ help: try replacing the loop by: `dst[(10 + LOOP_OFFSET)..(LOOP_OFFSET + LOOP_OFFSET)].copy_from_slice(&src[(10 - some_var)..(LOOP_OFFSET - some_var)]);` error: it looks like you're manually copying between slices - --> tests/ui/manual_memcpy/without_loop_counters.rs:74:5 + --> tests/ui/manual_memcpy/without_loop_counters.rs:75:5 | LL | / for i in 0..src_vec.len() { LL | | @@ -82,7 +82,7 @@ LL | | } | |_____^ help: try replacing the loop by: `dst_vec[..src_vec.len()].copy_from_slice(&src_vec[..]);` error: it looks like you're manually copying between slices - --> tests/ui/manual_memcpy/without_loop_counters.rs:104:5 + --> tests/ui/manual_memcpy/without_loop_counters.rs:105:5 | LL | / for i in from..from + src.len() { LL | | @@ -91,7 +91,7 @@ LL | | } | |_____^ help: try replacing the loop by: `dst[from..(from + src.len())].copy_from_slice(&src[..(from + src.len() - from)]);` error: it looks like you're manually copying between slices - --> tests/ui/manual_memcpy/without_loop_counters.rs:109:5 + --> tests/ui/manual_memcpy/without_loop_counters.rs:110:5 | LL | / for i in from..from + 3 { LL | | @@ -100,7 +100,7 @@ LL | | } | |_____^ help: try replacing the loop by: `dst[from..(from + 3)].copy_from_slice(&src[..(from + 3 - from)]);` error: it looks like you're manually copying between slices - --> tests/ui/manual_memcpy/without_loop_counters.rs:115:5 + --> tests/ui/manual_memcpy/without_loop_counters.rs:116:5 | LL | / for i in 0..5 { LL | | @@ -109,7 +109,7 @@ LL | | } | |_____^ help: try replacing the loop by: `dst[..5].copy_from_slice(&src);` error: it looks like you're manually copying between slices - --> tests/ui/manual_memcpy/without_loop_counters.rs:121:5 + --> tests/ui/manual_memcpy/without_loop_counters.rs:122:5 | LL | / for i in 0..0 { LL | | @@ -118,7 +118,7 @@ LL | | } | |_____^ help: try replacing the loop by: `dst[..0].copy_from_slice(&src[..0]);` error: it looks like you're manually copying between slices - --> tests/ui/manual_memcpy/without_loop_counters.rs:145:5 + --> tests/ui/manual_memcpy/without_loop_counters.rs:146:5 | LL | / for i in 0..4 { LL | | @@ -127,7 +127,7 @@ LL | | } | |_____^ help: try replacing the loop by: `dst.copy_from_slice(&src[..4]);` error: it looks like you're manually copying between slices - --> tests/ui/manual_memcpy/without_loop_counters.rs:151:5 + --> tests/ui/manual_memcpy/without_loop_counters.rs:152:5 | LL | / for i in 0..5 { LL | | @@ -136,7 +136,7 @@ LL | | } | |_____^ help: try replacing the loop by: `dst[..5].copy_from_slice(&src);` error: it looks like you're manually copying between slices - --> tests/ui/manual_memcpy/without_loop_counters.rs:157:5 + --> tests/ui/manual_memcpy/without_loop_counters.rs:158:5 | LL | / for i in 0..5 { LL | | @@ -145,7 +145,25 @@ LL | | } | |_____^ help: try replacing the loop by: `dst.copy_from_slice(&src);` error: it looks like you're manually copying between slices - --> tests/ui/manual_memcpy/without_loop_counters.rs:165:5 + --> tests/ui/manual_memcpy/without_loop_counters.rs:205:5 + | +LL | / for i in 0..5 { +LL | | +LL | | dst[i] = src[0][i]; +LL | | } + | |_____^ help: try replacing the loop by: `dst.copy_from_slice(&src[0]);` + +error: it looks like you're manually copying between slices + --> tests/ui/manual_memcpy/without_loop_counters.rs:211:5 + | +LL | / for i in 0..5 { +LL | | +LL | | dst[i] = src[0][1][i]; +LL | | } + | |_____^ help: try replacing the loop by: `dst.copy_from_slice(&src[0][1]);` + +error: it looks like you're manually copying between slices + --> tests/ui/manual_memcpy/without_loop_counters.rs:219:5 | LL | / for i in 0..src.len() { LL | | @@ -153,5 +171,5 @@ LL | | dst[i] = src[i].clone(); LL | | } | |_____^ help: try replacing the loop by: `dst[..src.len()].clone_from_slice(&src[..]);` -error: aborting due to 16 previous errors +error: aborting due to 18 previous errors diff --git a/tests/ui/manual_retain.fixed b/tests/ui/manual_retain.fixed index 5540029bf6b..e359dfbb98c 100644 --- a/tests/ui/manual_retain.fixed +++ b/tests/ui/manual_retain.fixed @@ -1,3 +1,5 @@ +//@compile-flags: -Zdeduplicate-diagnostics=yes + #![warn(clippy::manual_retain)] #![allow(unused, clippy::redundant_clone)] use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, VecDeque}; diff --git a/tests/ui/manual_retain.rs b/tests/ui/manual_retain.rs index cee641d9d65..931814f08b7 100644 --- a/tests/ui/manual_retain.rs +++ b/tests/ui/manual_retain.rs @@ -1,3 +1,5 @@ +//@compile-flags: -Zdeduplicate-diagnostics=yes + #![warn(clippy::manual_retain)] #![allow(unused, clippy::redundant_clone)] use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, VecDeque}; diff --git a/tests/ui/manual_retain.stderr b/tests/ui/manual_retain.stderr index c25c804df75..fdbbc53e4df 100644 --- a/tests/ui/manual_retain.stderr +++ b/tests/ui/manual_retain.stderr @@ -1,5 +1,5 @@ error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:25:5 + --> tests/ui/manual_retain.rs:27:5 | LL | binary_heap = binary_heap.into_iter().filter(|x| x % 2 == 0).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `binary_heap.retain(|x| x % 2 == 0)` @@ -8,43 +8,43 @@ LL | binary_heap = binary_heap.into_iter().filter(|x| x % 2 == 0).collect(); = help: to override `-D warnings` add `#[allow(clippy::manual_retain)]` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:26:5 + --> tests/ui/manual_retain.rs:28:5 | LL | binary_heap = binary_heap.iter().filter(|&x| x % 2 == 0).copied().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `binary_heap.retain(|x| x % 2 == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:27:5 + --> tests/ui/manual_retain.rs:29:5 | LL | binary_heap = binary_heap.iter().filter(|&x| x % 2 == 0).cloned().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `binary_heap.retain(|x| x % 2 == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:31:5 + --> tests/ui/manual_retain.rs:33:5 | LL | tuples = tuples.iter().filter(|(ref x, ref y)| *x == 0).copied().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `tuples.retain(|(ref x, ref y)| *x == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:32:5 + --> tests/ui/manual_retain.rs:34:5 | LL | tuples = tuples.iter().filter(|(x, y)| *x == 0).copied().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `tuples.retain(|(x, y)| *x == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:62:5 + --> tests/ui/manual_retain.rs:64:5 | LL | btree_map = btree_map.into_iter().filter(|(k, _)| k % 2 == 0).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `btree_map.retain(|k, _| k % 2 == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:63:5 + --> tests/ui/manual_retain.rs:65:5 | LL | btree_map = btree_map.into_iter().filter(|(_, v)| v % 2 == 0).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `btree_map.retain(|_, &mut v| v % 2 == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:64:5 + --> tests/ui/manual_retain.rs:66:5 | LL | / btree_map = btree_map LL | | .into_iter() @@ -53,49 +53,49 @@ LL | | .collect(); | |__________________^ help: consider calling `.retain()` instead: `btree_map.retain(|k, &mut v| (k % 2 == 0) && (v % 2 == 0))` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:89:5 + --> tests/ui/manual_retain.rs:91:5 | LL | btree_set = btree_set.iter().filter(|&x| x % 2 == 0).copied().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `btree_set.retain(|x| x % 2 == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:90:5 + --> tests/ui/manual_retain.rs:92:5 | LL | btree_set = btree_set.iter().filter(|&x| x % 2 == 0).cloned().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `btree_set.retain(|x| x % 2 == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:91:5 + --> tests/ui/manual_retain.rs:93:5 | LL | btree_set = btree_set.into_iter().filter(|x| x % 2 == 0).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `btree_set.retain(|x| x % 2 == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:95:5 + --> tests/ui/manual_retain.rs:97:5 | LL | tuples = tuples.iter().filter(|(ref x, ref y)| *x == 0).copied().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `tuples.retain(|(ref x, ref y)| *x == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:96:5 + --> tests/ui/manual_retain.rs:98:5 | LL | tuples = tuples.iter().filter(|(x, y)| *x == 0).copied().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `tuples.retain(|(x, y)| *x == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:126:5 + --> tests/ui/manual_retain.rs:128:5 | LL | hash_map = hash_map.into_iter().filter(|(k, _)| k % 2 == 0).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `hash_map.retain(|k, _| k % 2 == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:127:5 + --> tests/ui/manual_retain.rs:129:5 | LL | hash_map = hash_map.into_iter().filter(|(_, v)| v % 2 == 0).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `hash_map.retain(|_, &mut v| v % 2 == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:128:5 + --> tests/ui/manual_retain.rs:130:5 | LL | / hash_map = hash_map LL | | .into_iter() @@ -104,133 +104,133 @@ LL | | .collect(); | |__________________^ help: consider calling `.retain()` instead: `hash_map.retain(|k, &mut v| (k % 2 == 0) && (v % 2 == 0))` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:152:5 + --> tests/ui/manual_retain.rs:154:5 | LL | hash_set = hash_set.into_iter().filter(|x| x % 2 == 0).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `hash_set.retain(|x| x % 2 == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:153:5 + --> tests/ui/manual_retain.rs:155:5 | LL | hash_set = hash_set.iter().filter(|&x| x % 2 == 0).copied().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `hash_set.retain(|x| x % 2 == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:154:5 + --> tests/ui/manual_retain.rs:156:5 | LL | hash_set = hash_set.iter().filter(|&x| x % 2 == 0).cloned().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `hash_set.retain(|x| x % 2 == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:158:5 + --> tests/ui/manual_retain.rs:160:5 | LL | tuples = tuples.iter().filter(|(ref x, ref y)| *x == 0).copied().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `tuples.retain(|(ref x, ref y)| *x == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:159:5 + --> tests/ui/manual_retain.rs:161:5 | LL | tuples = tuples.iter().filter(|(x, y)| *x == 0).copied().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `tuples.retain(|(x, y)| *x == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:188:5 + --> tests/ui/manual_retain.rs:190:5 | LL | s = s.chars().filter(|&c| c != 'o').to_owned().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `s.retain(|c| c != 'o')` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:200:5 + --> tests/ui/manual_retain.rs:202:5 | LL | vec = vec.iter().filter(|&x| x % 2 == 0).copied().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec.retain(|x| x % 2 == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:201:5 + --> tests/ui/manual_retain.rs:203:5 | LL | vec = vec.iter().filter(|&x| x % 2 == 0).cloned().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec.retain(|x| x % 2 == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:202:5 + --> tests/ui/manual_retain.rs:204:5 | LL | vec = vec.into_iter().filter(|x| x % 2 == 0).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec.retain(|x| x % 2 == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:206:5 + --> tests/ui/manual_retain.rs:208:5 | LL | tuples = tuples.iter().filter(|(ref x, ref y)| *x == 0).copied().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `tuples.retain(|(ref x, ref y)| *x == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:207:5 + --> tests/ui/manual_retain.rs:209:5 | LL | tuples = tuples.iter().filter(|(x, y)| *x == 0).copied().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `tuples.retain(|(x, y)| *x == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:229:5 + --> tests/ui/manual_retain.rs:231:5 | LL | vec_deque = vec_deque.iter().filter(|&x| x % 2 == 0).copied().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec_deque.retain(|x| x % 2 == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:230:5 + --> tests/ui/manual_retain.rs:232:5 | LL | vec_deque = vec_deque.iter().filter(|&x| x % 2 == 0).cloned().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec_deque.retain(|x| x % 2 == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:231:5 + --> tests/ui/manual_retain.rs:233:5 | LL | vec_deque = vec_deque.into_iter().filter(|x| x % 2 == 0).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec_deque.retain(|x| x % 2 == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:288:5 + --> tests/ui/manual_retain.rs:290:5 | LL | vec = vec.into_iter().filter(|(x, y)| *x == 0).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec.retain(|(x, y)| *x == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:292:5 + --> tests/ui/manual_retain.rs:294:5 | LL | tuples = tuples.into_iter().filter(|(_, n)| *n > 0).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `tuples.retain(|(_, n)| *n > 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:309:5 + --> tests/ui/manual_retain.rs:311:5 | LL | vec = vec.iter().filter(|&&x| x == 0).copied().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec.retain(|&x| x == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:310:5 + --> tests/ui/manual_retain.rs:312:5 | LL | vec = vec.iter().filter(|&&x| x == 0).cloned().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec.retain(|&x| x == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:311:5 + --> tests/ui/manual_retain.rs:313:5 | LL | vec = vec.into_iter().filter(|&x| x == 0).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec.retain(|&x| x == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:314:5 + --> tests/ui/manual_retain.rs:316:5 | LL | vec = vec.iter().filter(|&x| *x == 0).copied().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec.retain(|x| *x == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:315:5 + --> tests/ui/manual_retain.rs:317:5 | LL | vec = vec.iter().filter(|&x| *x == 0).cloned().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec.retain(|x| *x == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:316:5 + --> tests/ui/manual_retain.rs:318:5 | LL | vec = vec.into_iter().filter(|x| *x == 0).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec.retain(|x| *x == 0)` diff --git a/tests/ui/many_single_char_names.rs b/tests/ui/many_single_char_names.rs index 68578340d90..2af45eaab8a 100644 --- a/tests/ui/many_single_char_names.rs +++ b/tests/ui/many_single_char_names.rs @@ -1,3 +1,5 @@ +//@compile-flags: -Zdeduplicate-diagnostics=yes + #![allow(clippy::too_many_arguments, clippy::diverging_sub_expression)] #![warn(clippy::many_single_char_names)] diff --git a/tests/ui/many_single_char_names.stderr b/tests/ui/many_single_char_names.stderr index 131836ef7c8..3b2460b5c07 100644 --- a/tests/ui/many_single_char_names.stderr +++ b/tests/ui/many_single_char_names.stderr @@ -1,5 +1,5 @@ error: 5 bindings with single-character names in scope - --> tests/ui/many_single_char_names.rs:5:9 + --> tests/ui/many_single_char_names.rs:7:9 | LL | let a: i32; | ^ @@ -14,7 +14,7 @@ LL | let e: i32; = help: to override `-D warnings` add `#[allow(clippy::many_single_char_names)]` error: 6 bindings with single-character names in scope - --> tests/ui/many_single_char_names.rs:5:9 + --> tests/ui/many_single_char_names.rs:7:9 | LL | let a: i32; | ^ @@ -28,7 +28,7 @@ LL | let f: i32; | ^ error: 5 bindings with single-character names in scope - --> tests/ui/many_single_char_names.rs:5:9 + --> tests/ui/many_single_char_names.rs:7:9 | LL | let a: i32; | ^ @@ -40,13 +40,13 @@ LL | e => panic!(), | ^ error: 8 bindings with single-character names in scope - --> tests/ui/many_single_char_names.rs:34:13 + --> tests/ui/many_single_char_names.rs:36:13 | LL | fn bindings(a: i32, b: i32, c: i32, d: i32, e: i32, f: i32, g: i32, h: i32) {} | ^ ^ ^ ^ ^ ^ ^ ^ error: 8 bindings with single-character names in scope - --> tests/ui/many_single_char_names.rs:38:10 + --> tests/ui/many_single_char_names.rs:40:10 | LL | let (a, b, c, d, e, f, g, h): (bool, bool, bool, bool, bool, bool, bool, bool) = unimplemented!(); | ^ ^ ^ ^ ^ ^ ^ ^ diff --git a/tests/ui/min_rust_version_invalid_attr.rs b/tests/ui/min_rust_version_invalid_attr.rs index 3917bb9e03d..2dccadd9fce 100644 --- a/tests/ui/min_rust_version_invalid_attr.rs +++ b/tests/ui/min_rust_version_invalid_attr.rs @@ -1,3 +1,5 @@ +//@compile-flags: -Zdeduplicate-diagnostics=yes + #![feature(custom_inner_attributes)] #![clippy::msrv = "invalid.version"] //~^ ERROR: `invalid.version` is not a valid Rust version diff --git a/tests/ui/min_rust_version_invalid_attr.stderr b/tests/ui/min_rust_version_invalid_attr.stderr index cf0d08a5d21..b4cb1b5713f 100644 --- a/tests/ui/min_rust_version_invalid_attr.stderr +++ b/tests/ui/min_rust_version_invalid_attr.stderr @@ -1,35 +1,35 @@ error: `invalid.version` is not a valid Rust version - --> tests/ui/min_rust_version_invalid_attr.rs:2:1 + --> tests/ui/min_rust_version_invalid_attr.rs:4:1 | LL | #![clippy::msrv = "invalid.version"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `invalid.version` is not a valid Rust version - --> tests/ui/min_rust_version_invalid_attr.rs:7:1 + --> tests/ui/min_rust_version_invalid_attr.rs:9:1 | LL | #[clippy::msrv = "invalid.version"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `clippy::msrv` is defined multiple times - --> tests/ui/min_rust_version_invalid_attr.rs:14:5 + --> tests/ui/min_rust_version_invalid_attr.rs:16:5 | LL | #![clippy::msrv = "1.10.1"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: first definition found here - --> tests/ui/min_rust_version_invalid_attr.rs:12:5 + --> tests/ui/min_rust_version_invalid_attr.rs:14:5 | LL | #![clippy::msrv = "1.40"] | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: `clippy::msrv` is defined multiple times - --> tests/ui/min_rust_version_invalid_attr.rs:19:9 + --> tests/ui/min_rust_version_invalid_attr.rs:21:9 | LL | #![clippy::msrv = "1.0.0"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: first definition found here - --> tests/ui/min_rust_version_invalid_attr.rs:18:9 + --> tests/ui/min_rust_version_invalid_attr.rs:20:9 | LL | #![clippy::msrv = "1"] | ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/mixed_attributes_style.rs b/tests/ui/mixed_attributes_style.rs new file mode 100644 index 00000000000..ad93e3019fa --- /dev/null +++ b/tests/ui/mixed_attributes_style.rs @@ -0,0 +1,39 @@ +#![warn(clippy::mixed_attributes_style)] + +#[allow(unused)] //~ ERROR: item has both inner and outer attributes +fn foo1() { + #![allow(unused)] +} + +#[allow(unused)] +#[allow(unused)] +fn foo2() {} + +fn foo3() { + #![allow(unused)] + #![allow(unused)] +} + +/// linux +//~^ ERROR: item has both inner and outer attributes +fn foo4() { + //! windows +} + +/// linux +/// windows +fn foo5() {} + +fn foo6() { + //! linux + //! windows +} + +#[allow(unused)] //~ ERROR: item has both inner and outer attributes +mod bar { + #![allow(unused)] +} + +fn main() { + // test code goes here +} diff --git a/tests/ui/mixed_attributes_style.stderr b/tests/ui/mixed_attributes_style.stderr new file mode 100644 index 00000000000..d1d5cd3f47f --- /dev/null +++ b/tests/ui/mixed_attributes_style.stderr @@ -0,0 +1,30 @@ +error: item has both inner and outer attributes + --> tests/ui/mixed_attributes_style.rs:3:1 + | +LL | / #[allow(unused)] +LL | | fn foo1() { +LL | | #![allow(unused)] + | |_____________________^ + | + = note: `-D clippy::mixed-attributes-style` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::mixed_attributes_style)]` + +error: item has both inner and outer attributes + --> tests/ui/mixed_attributes_style.rs:17:1 + | +LL | / /// linux +LL | | +LL | | fn foo4() { +LL | | //! windows + | |_______________^ + +error: item has both inner and outer attributes + --> tests/ui/mixed_attributes_style.rs:32:1 + | +LL | / #[allow(unused)] +LL | | mod bar { +LL | | #![allow(unused)] + | |_____________________^ + +error: aborting due to 3 previous errors + diff --git a/tests/ui/mut_mut.rs b/tests/ui/mut_mut.rs index 72a171119f3..288b003405d 100644 --- a/tests/ui/mut_mut.rs +++ b/tests/ui/mut_mut.rs @@ -1,4 +1,6 @@ //@aux-build:proc_macros.rs +//@compile-flags: -Zdeduplicate-diagnostics=yes + #![warn(clippy::mut_mut)] #![allow(unused)] #![allow( diff --git a/tests/ui/mut_mut.stderr b/tests/ui/mut_mut.stderr index 810c0c96743..73f2410a252 100644 --- a/tests/ui/mut_mut.stderr +++ b/tests/ui/mut_mut.stderr @@ -1,5 +1,5 @@ error: generally you want to avoid `&mut &mut _` if possible - --> tests/ui/mut_mut.rs:14:11 + --> tests/ui/mut_mut.rs:16:11 | LL | fn fun(x: &mut &mut u32) -> bool { | ^^^^^^^^^^^^^ @@ -8,13 +8,13 @@ LL | fn fun(x: &mut &mut u32) -> bool { = help: to override `-D warnings` add `#[allow(clippy::mut_mut)]` error: generally you want to avoid `&mut &mut _` if possible - --> tests/ui/mut_mut.rs:31:17 + --> tests/ui/mut_mut.rs:33:17 | LL | let mut x = &mut &mut 1u32; | ^^^^^^^^^^^^^^ error: generally you want to avoid `&mut &mut _` if possible - --> tests/ui/mut_mut.rs:46:25 + --> tests/ui/mut_mut.rs:48:25 | LL | let mut z = inline!(&mut $(&mut 3u32)); | ^ @@ -22,37 +22,37 @@ LL | let mut z = inline!(&mut $(&mut 3u32)); = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info) error: this expression mutably borrows a mutable reference. Consider reborrowing - --> tests/ui/mut_mut.rs:33:21 + --> tests/ui/mut_mut.rs:35:21 | LL | let mut y = &mut x; | ^^^^^^ error: generally you want to avoid `&mut &mut _` if possible - --> tests/ui/mut_mut.rs:37:32 + --> tests/ui/mut_mut.rs:39:32 | LL | let y: &mut &mut u32 = &mut &mut 2; | ^^^^^^^^^^^ error: generally you want to avoid `&mut &mut _` if possible - --> tests/ui/mut_mut.rs:37:16 + --> tests/ui/mut_mut.rs:39:16 | LL | let y: &mut &mut u32 = &mut &mut 2; | ^^^^^^^^^^^^^ error: generally you want to avoid `&mut &mut _` if possible - --> tests/ui/mut_mut.rs:42:37 + --> tests/ui/mut_mut.rs:44:37 | LL | let y: &mut &mut &mut u32 = &mut &mut &mut 2; | ^^^^^^^^^^^^^^^^ error: generally you want to avoid `&mut &mut _` if possible - --> tests/ui/mut_mut.rs:42:16 + --> tests/ui/mut_mut.rs:44:16 | LL | let y: &mut &mut &mut u32 = &mut &mut &mut 2; | ^^^^^^^^^^^^^^^^^^ error: generally you want to avoid `&mut &mut _` if possible - --> tests/ui/mut_mut.rs:42:21 + --> tests/ui/mut_mut.rs:44:21 | LL | let y: &mut &mut &mut u32 = &mut &mut &mut 2; | ^^^^^^^^^^^^^ diff --git a/tests/ui/no_effect_replace.rs b/tests/ui/no_effect_replace.rs index e4fd5caae2a..2a940d87fb9 100644 --- a/tests/ui/no_effect_replace.rs +++ b/tests/ui/no_effect_replace.rs @@ -1,3 +1,5 @@ +//@compile-flags: -Zdeduplicate-diagnostics=yes + #![warn(clippy::no_effect_replace)] fn main() { diff --git a/tests/ui/no_effect_replace.stderr b/tests/ui/no_effect_replace.stderr index ded86c5c5b8..ad2dcd2cc9b 100644 --- a/tests/ui/no_effect_replace.stderr +++ b/tests/ui/no_effect_replace.stderr @@ -1,5 +1,5 @@ error: replacing text with itself - --> tests/ui/no_effect_replace.rs:4:13 + --> tests/ui/no_effect_replace.rs:6:13 | LL | let _ = "12345".replace('1', "1"); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -8,43 +8,43 @@ LL | let _ = "12345".replace('1', "1"); = help: to override `-D warnings` add `#[allow(clippy::no_effect_replace)]` error: replacing text with itself - --> tests/ui/no_effect_replace.rs:7:13 + --> tests/ui/no_effect_replace.rs:9:13 | LL | let _ = "12345".replace("12", "12"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: replacing text with itself - --> tests/ui/no_effect_replace.rs:9:13 + --> tests/ui/no_effect_replace.rs:11:13 | LL | let _ = String::new().replace("12", "12"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: replacing text with itself - --> tests/ui/no_effect_replace.rs:12:13 + --> tests/ui/no_effect_replace.rs:14:13 | LL | let _ = "12345".replacen('1', "1", 1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: replacing text with itself - --> tests/ui/no_effect_replace.rs:14:13 + --> tests/ui/no_effect_replace.rs:16:13 | LL | let _ = "12345".replacen("12", "12", 1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: replacing text with itself - --> tests/ui/no_effect_replace.rs:16:13 + --> tests/ui/no_effect_replace.rs:18:13 | LL | let _ = String::new().replacen("12", "12", 1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: replacing text with itself - --> tests/ui/no_effect_replace.rs:23:13 + --> tests/ui/no_effect_replace.rs:25:13 | LL | let _ = "hello".replace(&x.f(), &x.f()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: replacing text with itself - --> tests/ui/no_effect_replace.rs:27:13 + --> tests/ui/no_effect_replace.rs:29:13 | LL | let _ = "hello".replace(&y(), &y()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/non_canonical_clone_impl.fixed b/tests/ui/non_canonical_clone_impl.fixed index 165702b3041..7d1be412e54 100644 --- a/tests/ui/non_canonical_clone_impl.fixed +++ b/tests/ui/non_canonical_clone_impl.fixed @@ -1,4 +1,5 @@ #![allow(clippy::clone_on_copy, unused)] +#![allow(clippy::assigning_clones)] #![no_main] // lint diff --git a/tests/ui/non_canonical_clone_impl.rs b/tests/ui/non_canonical_clone_impl.rs index 3b07dd5ce62..beae05efb2f 100644 --- a/tests/ui/non_canonical_clone_impl.rs +++ b/tests/ui/non_canonical_clone_impl.rs @@ -1,4 +1,5 @@ #![allow(clippy::clone_on_copy, unused)] +#![allow(clippy::assigning_clones)] #![no_main] // lint diff --git a/tests/ui/non_canonical_clone_impl.stderr b/tests/ui/non_canonical_clone_impl.stderr index 8eff322fa2d..6bfc99d988b 100644 --- a/tests/ui/non_canonical_clone_impl.stderr +++ b/tests/ui/non_canonical_clone_impl.stderr @@ -1,5 +1,5 @@ error: non-canonical implementation of `clone` on a `Copy` type - --> tests/ui/non_canonical_clone_impl.rs:9:29 + --> tests/ui/non_canonical_clone_impl.rs:10:29 | LL | fn clone(&self) -> Self { | _____________________________^ @@ -11,7 +11,7 @@ LL | | } = help: to override `-D warnings` add `#[allow(clippy::non_canonical_clone_impl)]` error: unnecessary implementation of `clone_from` on a `Copy` type - --> tests/ui/non_canonical_clone_impl.rs:13:5 + --> tests/ui/non_canonical_clone_impl.rs:14:5 | LL | / fn clone_from(&mut self, source: &Self) { LL | | source.clone(); @@ -20,7 +20,7 @@ LL | | } | |_____^ help: remove it error: non-canonical implementation of `clone` on a `Copy` type - --> tests/ui/non_canonical_clone_impl.rs:80:29 + --> tests/ui/non_canonical_clone_impl.rs:81:29 | LL | fn clone(&self) -> Self { | _____________________________^ @@ -29,7 +29,7 @@ LL | | } | |_____^ help: change this to: `{ *self }` error: unnecessary implementation of `clone_from` on a `Copy` type - --> tests/ui/non_canonical_clone_impl.rs:84:5 + --> tests/ui/non_canonical_clone_impl.rs:85:5 | LL | / fn clone_from(&mut self, source: &Self) { LL | | source.clone(); diff --git a/tests/ui/nonminimal_bool.rs b/tests/ui/nonminimal_bool.rs index 908ef6cb2a0..38157116e91 100644 --- a/tests/ui/nonminimal_bool.rs +++ b/tests/ui/nonminimal_bool.rs @@ -1,4 +1,5 @@ //@no-rustfix: overlapping suggestions + #![feature(lint_reasons)] #![allow( unused, @@ -173,3 +174,8 @@ fn issue_5794() { if !b == !c {} //~ ERROR: this boolean expression can be simplified if !b != !c {} //~ ERROR: this boolean expression can be simplified } + +fn issue_12371(x: usize) -> bool { + // Should not warn! + !x != 0 +} diff --git a/tests/ui/nonminimal_bool.stderr b/tests/ui/nonminimal_bool.stderr index 954e2345266..b6af06d845a 100644 --- a/tests/ui/nonminimal_bool.stderr +++ b/tests/ui/nonminimal_bool.stderr @@ -1,5 +1,5 @@ error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool.rs:18:13 + --> tests/ui/nonminimal_bool.rs:19:13 | LL | let _ = !true; | ^^^^^ help: try: `false` @@ -8,43 +8,43 @@ LL | let _ = !true; = help: to override `-D warnings` add `#[allow(clippy::nonminimal_bool)]` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool.rs:21:13 + --> tests/ui/nonminimal_bool.rs:22:13 | LL | let _ = !false; | ^^^^^^ help: try: `true` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool.rs:23:13 + --> tests/ui/nonminimal_bool.rs:24:13 | LL | let _ = !!a; | ^^^ help: try: `a` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool.rs:25:13 + --> tests/ui/nonminimal_bool.rs:26:13 | LL | let _ = false || a; | ^^^^^^^^^^ help: try: `a` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool.rs:30:13 + --> tests/ui/nonminimal_bool.rs:31:13 | LL | let _ = !(!a && b); | ^^^^^^^^^^ help: try: `a || !b` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool.rs:32:13 + --> tests/ui/nonminimal_bool.rs:33:13 | LL | let _ = !(!a || b); | ^^^^^^^^^^ help: try: `a && !b` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool.rs:34:13 + --> tests/ui/nonminimal_bool.rs:35:13 | LL | let _ = !a && !(b && c); | ^^^^^^^^^^^^^^^ help: try: `!(a || b && c)` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool.rs:43:13 + --> tests/ui/nonminimal_bool.rs:44:13 | LL | let _ = a == b && c == 5 && a == b; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -57,7 +57,7 @@ LL | let _ = a == b && c == 5; | ~~~~~~~~~~~~~~~~ error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool.rs:45:13 + --> tests/ui/nonminimal_bool.rs:46:13 | LL | let _ = a == b || c == 5 || a == b; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -70,7 +70,7 @@ LL | let _ = a == b || c == 5; | ~~~~~~~~~~~~~~~~ error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool.rs:47:13 + --> tests/ui/nonminimal_bool.rs:48:13 | LL | let _ = a == b && c == 5 && b == a; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -83,7 +83,7 @@ LL | let _ = a == b && c == 5; | ~~~~~~~~~~~~~~~~ error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool.rs:49:13 + --> tests/ui/nonminimal_bool.rs:50:13 | LL | let _ = a != b || !(a != b || c == d); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -96,7 +96,7 @@ LL | let _ = a != b || c != d; | ~~~~~~~~~~~~~~~~ error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool.rs:51:13 + --> tests/ui/nonminimal_bool.rs:52:13 | LL | let _ = a != b && !(a != b && c == d); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -109,43 +109,43 @@ LL | let _ = a != b && c != d; | ~~~~~~~~~~~~~~~~ error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool.rs:82:8 + --> tests/ui/nonminimal_bool.rs:83:8 | LL | if matches!(true, true) && true { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(true, true)` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool.rs:162:8 + --> tests/ui/nonminimal_bool.rs:163:8 | LL | if !(12 == a) {} | ^^^^^^^^^^ help: try: `12 != a` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool.rs:163:8 + --> tests/ui/nonminimal_bool.rs:164:8 | LL | if !(a == 12) {} | ^^^^^^^^^^ help: try: `a != 12` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool.rs:164:8 + --> tests/ui/nonminimal_bool.rs:165:8 | LL | if !(12 != a) {} | ^^^^^^^^^^ help: try: `12 == a` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool.rs:165:8 + --> tests/ui/nonminimal_bool.rs:166:8 | LL | if !(a != 12) {} | ^^^^^^^^^^ help: try: `a == 12` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool.rs:169:8 + --> tests/ui/nonminimal_bool.rs:170:8 | LL | if !b == true {} | ^^^^^^^^^^ help: try: `b != true` error: this comparison might be written more concisely - --> tests/ui/nonminimal_bool.rs:169:8 + --> tests/ui/nonminimal_bool.rs:170:8 | LL | if !b == true {} | ^^^^^^^^^^ help: try simplifying it as shown: `b != true` @@ -154,61 +154,61 @@ LL | if !b == true {} = help: to override `-D warnings` add `#[allow(clippy::bool_comparison)]` error: equality checks against true are unnecessary - --> tests/ui/nonminimal_bool.rs:169:8 + --> tests/ui/nonminimal_bool.rs:170:8 | LL | if !b == true {} | ^^^^^^^^^^ help: try simplifying it as shown: `!b` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool.rs:170:8 + --> tests/ui/nonminimal_bool.rs:171:8 | LL | if !b != true {} | ^^^^^^^^^^ help: try: `b == true` error: inequality checks against true can be replaced by a negation - --> tests/ui/nonminimal_bool.rs:170:8 + --> tests/ui/nonminimal_bool.rs:171:8 | LL | if !b != true {} | ^^^^^^^^^^ help: try simplifying it as shown: `!(!b)` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool.rs:171:8 + --> tests/ui/nonminimal_bool.rs:172:8 | LL | if true == !b {} | ^^^^^^^^^^ help: try: `true != b` error: this comparison might be written more concisely - --> tests/ui/nonminimal_bool.rs:171:8 + --> tests/ui/nonminimal_bool.rs:172:8 | LL | if true == !b {} | ^^^^^^^^^^ help: try simplifying it as shown: `true != b` error: equality checks against true are unnecessary - --> tests/ui/nonminimal_bool.rs:171:8 + --> tests/ui/nonminimal_bool.rs:172:8 | LL | if true == !b {} | ^^^^^^^^^^ help: try simplifying it as shown: `!b` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool.rs:172:8 + --> tests/ui/nonminimal_bool.rs:173:8 | LL | if true != !b {} | ^^^^^^^^^^ help: try: `true == b` error: inequality checks against true can be replaced by a negation - --> tests/ui/nonminimal_bool.rs:172:8 + --> tests/ui/nonminimal_bool.rs:173:8 | LL | if true != !b {} | ^^^^^^^^^^ help: try simplifying it as shown: `!(!b)` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool.rs:173:8 + --> tests/ui/nonminimal_bool.rs:174:8 | LL | if !b == !c {} | ^^^^^^^^ help: try: `b == c` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool.rs:174:8 + --> tests/ui/nonminimal_bool.rs:175:8 | LL | if !b != !c {} | ^^^^^^^^ help: try: `b != c` diff --git a/tests/ui/nonminimal_bool_methods.fixed b/tests/ui/nonminimal_bool_methods.fixed index e27c0350d49..bd4be3e5a44 100644 --- a/tests/ui/nonminimal_bool_methods.fixed +++ b/tests/ui/nonminimal_bool_methods.fixed @@ -1,3 +1,5 @@ +//@compile-flags: -Zdeduplicate-diagnostics=yes + #![allow(unused, clippy::diverging_sub_expression, clippy::needless_if)] #![warn(clippy::nonminimal_bool)] diff --git a/tests/ui/nonminimal_bool_methods.rs b/tests/ui/nonminimal_bool_methods.rs index 040a6e920a1..4523c7385df 100644 --- a/tests/ui/nonminimal_bool_methods.rs +++ b/tests/ui/nonminimal_bool_methods.rs @@ -1,3 +1,5 @@ +//@compile-flags: -Zdeduplicate-diagnostics=yes + #![allow(unused, clippy::diverging_sub_expression, clippy::needless_if)] #![warn(clippy::nonminimal_bool)] diff --git a/tests/ui/nonminimal_bool_methods.stderr b/tests/ui/nonminimal_bool_methods.stderr index ede88ba529c..e32c8dacd2f 100644 --- a/tests/ui/nonminimal_bool_methods.stderr +++ b/tests/ui/nonminimal_bool_methods.stderr @@ -1,5 +1,5 @@ error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool_methods.rs:8:13 + --> tests/ui/nonminimal_bool_methods.rs:10:13 | LL | let _ = !a.is_some(); | ^^^^^^^^^^^^ help: try: `a.is_none()` @@ -8,73 +8,73 @@ LL | let _ = !a.is_some(); = help: to override `-D warnings` add `#[allow(clippy::nonminimal_bool)]` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool_methods.rs:10:13 + --> tests/ui/nonminimal_bool_methods.rs:12:13 | LL | let _ = !a.is_none(); | ^^^^^^^^^^^^ help: try: `a.is_some()` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool_methods.rs:12:13 + --> tests/ui/nonminimal_bool_methods.rs:14:13 | LL | let _ = !b.is_err(); | ^^^^^^^^^^^ help: try: `b.is_ok()` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool_methods.rs:14:13 + --> tests/ui/nonminimal_bool_methods.rs:16:13 | LL | let _ = !b.is_ok(); | ^^^^^^^^^^ help: try: `b.is_err()` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool_methods.rs:16:13 + --> tests/ui/nonminimal_bool_methods.rs:18:13 | LL | let _ = !(a.is_some() && !c); | ^^^^^^^^^^^^^^^^^^^^ help: try: `a.is_none() || c` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool_methods.rs:17:13 + --> tests/ui/nonminimal_bool_methods.rs:19:13 | LL | let _ = !(a.is_some() || !c); | ^^^^^^^^^^^^^^^^^^^^ help: try: `a.is_none() && c` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool_methods.rs:18:26 + --> tests/ui/nonminimal_bool_methods.rs:20:26 | LL | let _ = !(!c ^ c) || !a.is_some(); | ^^^^^^^^^^^^ help: try: `a.is_none()` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool_methods.rs:19:25 + --> tests/ui/nonminimal_bool_methods.rs:21:25 | LL | let _ = (!c ^ c) || !a.is_some(); | ^^^^^^^^^^^^ help: try: `a.is_none()` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool_methods.rs:20:23 + --> tests/ui/nonminimal_bool_methods.rs:22:23 | LL | let _ = !c ^ c || !a.is_some(); | ^^^^^^^^^^^^ help: try: `a.is_none()` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool_methods.rs:92:8 + --> tests/ui/nonminimal_bool_methods.rs:94:8 | LL | if !res.is_ok() {} | ^^^^^^^^^^^^ help: try: `res.is_err()` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool_methods.rs:93:8 + --> tests/ui/nonminimal_bool_methods.rs:95:8 | LL | if !res.is_err() {} | ^^^^^^^^^^^^^ help: try: `res.is_ok()` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool_methods.rs:96:8 + --> tests/ui/nonminimal_bool_methods.rs:98:8 | LL | if !res.is_some() {} | ^^^^^^^^^^^^^^ help: try: `res.is_none()` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool_methods.rs:97:8 + --> tests/ui/nonminimal_bool_methods.rs:99:8 | LL | if !res.is_none() {} | ^^^^^^^^^^^^^^ help: try: `res.is_some()` diff --git a/tests/ui/option_option.rs b/tests/ui/option_option.rs index 9bbdd3aaacc..2f6e4d76145 100644 --- a/tests/ui/option_option.rs +++ b/tests/ui/option_option.rs @@ -1,3 +1,5 @@ +//@compile-flags: -Zdeduplicate-diagnostics=yes + #![deny(clippy::option_option)] #![allow(clippy::unnecessary_wraps)] diff --git a/tests/ui/option_option.stderr b/tests/ui/option_option.stderr index 0cd048e400e..76cb9ae944c 100644 --- a/tests/ui/option_option.stderr +++ b/tests/ui/option_option.stderr @@ -1,77 +1,77 @@ error: consider using `Option` instead of `Option>` or a custom enum if you need to distinguish all 3 cases - --> tests/ui/option_option.rs:4:10 + --> tests/ui/option_option.rs:6:10 | LL | const C: Option> = None; | ^^^^^^^^^^^^^^^^^^^ | note: the lint level is defined here - --> tests/ui/option_option.rs:1:9 + --> tests/ui/option_option.rs:3:9 | LL | #![deny(clippy::option_option)] | ^^^^^^^^^^^^^^^^^^^^^ error: consider using `Option` instead of `Option>` or a custom enum if you need to distinguish all 3 cases - --> tests/ui/option_option.rs:6:11 + --> tests/ui/option_option.rs:8:11 | LL | static S: Option> = None; | ^^^^^^^^^^^^^^^^^^^ error: consider using `Option` instead of `Option>` or a custom enum if you need to distinguish all 3 cases - --> tests/ui/option_option.rs:9:13 + --> tests/ui/option_option.rs:11:13 | LL | fn input(_: Option>) {} | ^^^^^^^^^^^^^^^^^^ error: consider using `Option` instead of `Option>` or a custom enum if you need to distinguish all 3 cases - --> tests/ui/option_option.rs:12:16 + --> tests/ui/option_option.rs:14:16 | LL | fn output() -> Option> { | ^^^^^^^^^^^^^^^^^^ error: consider using `Option` instead of `Option>` or a custom enum if you need to distinguish all 3 cases - --> tests/ui/option_option.rs:17:27 + --> tests/ui/option_option.rs:19:27 | LL | fn output_nested() -> Vec>> { | ^^^^^^^^^^^^^^^^^^ error: consider using `Option` instead of `Option>` or a custom enum if you need to distinguish all 3 cases - --> tests/ui/option_option.rs:23:30 + --> tests/ui/option_option.rs:25:30 | LL | fn output_nested_nested() -> Option>> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: consider using `Option` instead of `Option>` or a custom enum if you need to distinguish all 3 cases - --> tests/ui/option_option.rs:29:8 + --> tests/ui/option_option.rs:31:8 | LL | x: Option>, | ^^^^^^^^^^^^^^^^^^ error: consider using `Option` instead of `Option>` or a custom enum if you need to distinguish all 3 cases - --> tests/ui/option_option.rs:34:23 + --> tests/ui/option_option.rs:36:23 | LL | fn struct_fn() -> Option> { | ^^^^^^^^^^^^^^^^^^ error: consider using `Option` instead of `Option>` or a custom enum if you need to distinguish all 3 cases - --> tests/ui/option_option.rs:41:22 + --> tests/ui/option_option.rs:43:22 | LL | fn trait_fn() -> Option>; | ^^^^^^^^^^^^^^^^^^ error: consider using `Option` instead of `Option>` or a custom enum if you need to distinguish all 3 cases - --> tests/ui/option_option.rs:46:11 + --> tests/ui/option_option.rs:48:11 | LL | Tuple(Option>), | ^^^^^^^^^^^^^^^^^^ error: consider using `Option` instead of `Option>` or a custom enum if you need to distinguish all 3 cases - --> tests/ui/option_option.rs:48:17 + --> tests/ui/option_option.rs:50:17 | LL | Struct { x: Option> }, | ^^^^^^^^^^^^^^^^^^ error: consider using `Option` instead of `Option>` or a custom enum if you need to distinguish all 3 cases - --> tests/ui/option_option.rs:90:14 + --> tests/ui/option_option.rs:92:14 | LL | foo: Option>>, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/ptr_as_ptr.fixed b/tests/ui/ptr_as_ptr.fixed index fa15c323540..61d37b8ba3a 100644 --- a/tests/ui/ptr_as_ptr.fixed +++ b/tests/ui/ptr_as_ptr.fixed @@ -1,4 +1,5 @@ //@aux-build:proc_macros.rs +//@compile-flags: -Zdeduplicate-diagnostics=yes #![warn(clippy::ptr_as_ptr)] diff --git a/tests/ui/ptr_as_ptr.rs b/tests/ui/ptr_as_ptr.rs index 7ab52e63da5..8f2068cd268 100644 --- a/tests/ui/ptr_as_ptr.rs +++ b/tests/ui/ptr_as_ptr.rs @@ -1,4 +1,5 @@ //@aux-build:proc_macros.rs +//@compile-flags: -Zdeduplicate-diagnostics=yes #![warn(clippy::ptr_as_ptr)] diff --git a/tests/ui/ptr_as_ptr.stderr b/tests/ui/ptr_as_ptr.stderr index e162f35baf5..e6cd697c7ba 100644 --- a/tests/ui/ptr_as_ptr.stderr +++ b/tests/ui/ptr_as_ptr.stderr @@ -1,5 +1,5 @@ error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:18:33 + --> tests/ui/ptr_as_ptr.rs:19:33 | LL | *unsafe { Box::from_raw(Box::into_raw(Box::new(o)) as *mut super::issue_11278_a::T) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `Box::into_raw(Box::new(o)).cast::>()` @@ -8,37 +8,37 @@ LL | *unsafe { Box::from_raw(Box::into_raw(Box::new(o)) as *mut super::i = help: to override `-D warnings` add `#[allow(clippy::ptr_as_ptr)]` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:27:13 + --> tests/ui/ptr_as_ptr.rs:28:13 | LL | let _ = ptr as *const i32; | ^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `ptr.cast::()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:28:13 + --> tests/ui/ptr_as_ptr.rs:29:13 | LL | let _ = mut_ptr as *mut i32; | ^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `mut_ptr.cast::()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:33:17 + --> tests/ui/ptr_as_ptr.rs:34:17 | LL | let _ = *ptr_ptr as *const i32; | ^^^^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `(*ptr_ptr).cast::()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:46:25 + --> tests/ui/ptr_as_ptr.rs:47:25 | LL | let _: *const i32 = ptr as *const _; | ^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `ptr.cast()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:47:23 + --> tests/ui/ptr_as_ptr.rs:48:23 | LL | let _: *mut i32 = mut_ptr as _; | ^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `mut_ptr.cast()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:50:21 + --> tests/ui/ptr_as_ptr.rs:51:21 | LL | let _ = inline!($ptr as *const i32); | ^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `$ptr.cast::()` @@ -46,157 +46,157 @@ LL | let _ = inline!($ptr as *const i32); = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info) error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:71:13 + --> tests/ui/ptr_as_ptr.rs:72:13 | LL | let _ = ptr as *const i32; | ^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `ptr.cast::()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:72:13 + --> tests/ui/ptr_as_ptr.rs:73:13 | LL | let _ = mut_ptr as *mut i32; | ^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `mut_ptr.cast::()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:79:9 + --> tests/ui/ptr_as_ptr.rs:80:9 | LL | ptr::null_mut() as *mut u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut::()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:83:9 + --> tests/ui/ptr_as_ptr.rs:84:9 | LL | std::ptr::null_mut() as *mut u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null_mut::()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:88:9 + --> tests/ui/ptr_as_ptr.rs:89:9 | LL | ptr::null_mut() as *mut u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut::()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:92:9 + --> tests/ui/ptr_as_ptr.rs:93:9 | LL | core::ptr::null_mut() as *mut u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null_mut::()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:97:9 + --> tests/ui/ptr_as_ptr.rs:98:9 | LL | ptr::null() as *const u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null::()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:101:9 + --> tests/ui/ptr_as_ptr.rs:102:9 | LL | std::ptr::null() as *const u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null::()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:106:9 + --> tests/ui/ptr_as_ptr.rs:107:9 | LL | ptr::null() as *const u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null::()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:110:9 + --> tests/ui/ptr_as_ptr.rs:111:9 | LL | core::ptr::null() as *const u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null::()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:117:9 + --> tests/ui/ptr_as_ptr.rs:118:9 | LL | ptr::null_mut() as *mut _ | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:121:9 + --> tests/ui/ptr_as_ptr.rs:122:9 | LL | std::ptr::null_mut() as *mut _ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null_mut()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:126:9 + --> tests/ui/ptr_as_ptr.rs:127:9 | LL | ptr::null_mut() as *mut _ | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:130:9 + --> tests/ui/ptr_as_ptr.rs:131:9 | LL | core::ptr::null_mut() as *mut _ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null_mut()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:135:9 + --> tests/ui/ptr_as_ptr.rs:136:9 | LL | ptr::null() as *const _ | ^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:139:9 + --> tests/ui/ptr_as_ptr.rs:140:9 | LL | std::ptr::null() as *const _ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:144:9 + --> tests/ui/ptr_as_ptr.rs:145:9 | LL | ptr::null() as *const _ | ^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:148:9 + --> tests/ui/ptr_as_ptr.rs:149:9 | LL | core::ptr::null() as *const _ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:155:9 + --> tests/ui/ptr_as_ptr.rs:156:9 | LL | ptr::null_mut() as _ | ^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:159:9 + --> tests/ui/ptr_as_ptr.rs:160:9 | LL | std::ptr::null_mut() as _ | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null_mut()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:164:9 + --> tests/ui/ptr_as_ptr.rs:165:9 | LL | ptr::null_mut() as _ | ^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:168:9 + --> tests/ui/ptr_as_ptr.rs:169:9 | LL | core::ptr::null_mut() as _ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null_mut()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:173:9 + --> tests/ui/ptr_as_ptr.rs:174:9 | LL | ptr::null() as _ | ^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:177:9 + --> tests/ui/ptr_as_ptr.rs:178:9 | LL | std::ptr::null() as _ | ^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:182:9 + --> tests/ui/ptr_as_ptr.rs:183:9 | LL | ptr::null() as _ | ^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null()` error: `as` casting between raw pointers without changing its mutability - --> tests/ui/ptr_as_ptr.rs:186:9 + --> tests/ui/ptr_as_ptr.rs:187:9 | LL | core::ptr::null() as _ | ^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null()` diff --git a/tests/ui/question_mark.fixed b/tests/ui/question_mark.fixed index 2ef006c1419..567472a8af2 100644 --- a/tests/ui/question_mark.fixed +++ b/tests/ui/question_mark.fixed @@ -273,3 +273,13 @@ const fn issue9175(option: Option<()>) -> Option<()> { //stuff Some(()) } + +fn issue12337() -> Option { + let _: Option = try { + let Some(_) = Some(42) else { + return None; + }; + 123 + }; + Some(42) +} diff --git a/tests/ui/question_mark.rs b/tests/ui/question_mark.rs index c170669823f..abf8c270de8 100644 --- a/tests/ui/question_mark.rs +++ b/tests/ui/question_mark.rs @@ -313,3 +313,13 @@ const fn issue9175(option: Option<()>) -> Option<()> { //stuff Some(()) } + +fn issue12337() -> Option { + let _: Option = try { + let Some(_) = Some(42) else { + return None; + }; + 123 + }; + Some(42) +} diff --git a/tests/ui/redundant_closure_call_fixable.fixed b/tests/ui/redundant_closure_call_fixable.fixed index ce5c7f2600b..191f7719904 100644 --- a/tests/ui/redundant_closure_call_fixable.fixed +++ b/tests/ui/redundant_closure_call_fixable.fixed @@ -111,3 +111,20 @@ fn fp_11274() { } m!(|x| println!("{x}")); } + +// Issue #12358: When a macro expands into a closure, immediately calling the expanded closure +// triggers the lint. +fn issue_12358() { + macro_rules! make_closure { + () => { + (|| || {}) + }; + (x) => { + make_closure!()() + }; + } + + // The lint would suggest to alter the line below to `make_closure!(x)`, which is semantically + // different. + make_closure!(x)(); +} diff --git a/tests/ui/redundant_closure_call_fixable.rs b/tests/ui/redundant_closure_call_fixable.rs index ac09390e6ea..33a3b90f9cf 100644 --- a/tests/ui/redundant_closure_call_fixable.rs +++ b/tests/ui/redundant_closure_call_fixable.rs @@ -111,3 +111,20 @@ macro_rules! m { } m!(|x| println!("{x}")); } + +// Issue #12358: When a macro expands into a closure, immediately calling the expanded closure +// triggers the lint. +fn issue_12358() { + macro_rules! make_closure { + () => { + (|| || {}) + }; + (x) => { + make_closure!()() + }; + } + + // The lint would suggest to alter the line below to `make_closure!(x)`, which is semantically + // different. + make_closure!(x)(); +} diff --git a/tests/ui/redundant_field_names.fixed b/tests/ui/redundant_field_names.fixed index c578e786426..72fc4cb7333 100644 --- a/tests/ui/redundant_field_names.fixed +++ b/tests/ui/redundant_field_names.fixed @@ -20,7 +20,7 @@ struct Person { } pub struct S { - v: String, + v: usize, } fn main() { @@ -59,11 +59,22 @@ fn main() { let _ = RangeToInclusive { end }; external! { - let v = String::new(); + let v = 1; let _ = S { v: v }; } + + let v = 2; + macro_rules! internal { + ($i:ident) => { + let _ = S { v }; + let _ = S { $i: v }; + let _ = S { v: $i }; + let _ = S { $i: $i }; + }; + } + internal!(v); } fn issue_3476() { diff --git a/tests/ui/redundant_field_names.rs b/tests/ui/redundant_field_names.rs index d8c2286d5ad..2617d7e7283 100644 --- a/tests/ui/redundant_field_names.rs +++ b/tests/ui/redundant_field_names.rs @@ -20,7 +20,7 @@ struct Person { } pub struct S { - v: String, + v: usize, } fn main() { @@ -59,11 +59,22 @@ fn main() { let _ = RangeToInclusive { end: end }; external! { - let v = String::new(); + let v = 1; let _ = S { v: v }; } + + let v = 2; + macro_rules! internal { + ($i:ident) => { + let _ = S { v: v }; + let _ = S { $i: v }; + let _ = S { v: $i }; + let _ = S { $i: $i }; + }; + } + internal!(v); } fn issue_3476() { diff --git a/tests/ui/redundant_field_names.stderr b/tests/ui/redundant_field_names.stderr index 53234736207..38c021fdba3 100644 --- a/tests/ui/redundant_field_names.stderr +++ b/tests/ui/redundant_field_names.stderr @@ -44,10 +44,21 @@ LL | let _ = RangeToInclusive { end: end }; | ^^^^^^^^ help: replace it with: `end` error: redundant field names in struct initialization - --> tests/ui/redundant_field_names.rs:88:25 + --> tests/ui/redundant_field_names.rs:71:25 + | +LL | let _ = S { v: v }; + | ^^^^ help: replace it with: `v` +... +LL | internal!(v); + | ------------ in this macro invocation + | + = note: this error originates in the macro `internal` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: redundant field names in struct initialization + --> tests/ui/redundant_field_names.rs:99:25 | LL | let _ = RangeFrom { start: start }; | ^^^^^^^^^^^^ help: replace it with: `start` -error: aborting due to 8 previous errors +error: aborting due to 9 previous errors diff --git a/tests/ui/renamed_builtin_attr.fixed b/tests/ui/renamed_builtin_attr.fixed index bc055215708..aebf8712dd9 100644 --- a/tests/ui/renamed_builtin_attr.fixed +++ b/tests/ui/renamed_builtin_attr.fixed @@ -1,2 +1,4 @@ +//@compile-flags: -Zdeduplicate-diagnostics=yes + #[clippy::cognitive_complexity = "1"] fn main() {} diff --git a/tests/ui/renamed_builtin_attr.rs b/tests/ui/renamed_builtin_attr.rs index fdb425363e8..6c18151195f 100644 --- a/tests/ui/renamed_builtin_attr.rs +++ b/tests/ui/renamed_builtin_attr.rs @@ -1,2 +1,4 @@ +//@compile-flags: -Zdeduplicate-diagnostics=yes + #[clippy::cyclomatic_complexity = "1"] fn main() {} diff --git a/tests/ui/renamed_builtin_attr.stderr b/tests/ui/renamed_builtin_attr.stderr index f9108d169c7..fb51313dab6 100644 --- a/tests/ui/renamed_builtin_attr.stderr +++ b/tests/ui/renamed_builtin_attr.stderr @@ -1,5 +1,5 @@ error: usage of deprecated attribute - --> tests/ui/renamed_builtin_attr.rs:1:11 + --> tests/ui/renamed_builtin_attr.rs:3:11 | LL | #[clippy::cyclomatic_complexity = "1"] | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `cognitive_complexity` diff --git a/tests/ui/single_match.fixed b/tests/ui/single_match.fixed index 0a49be2dc4f..6df64eb4053 100644 --- a/tests/ui/single_match.fixed +++ b/tests/ui/single_match.fixed @@ -1,3 +1,5 @@ +//@compile-flags: -Zdeduplicate-diagnostics=yes + #![warn(clippy::single_match)] #![allow( unused, diff --git a/tests/ui/single_match.rs b/tests/ui/single_match.rs index 4e35d265acb..4f005f4e04f 100644 --- a/tests/ui/single_match.rs +++ b/tests/ui/single_match.rs @@ -1,3 +1,5 @@ +//@compile-flags: -Zdeduplicate-diagnostics=yes + #![warn(clippy::single_match)] #![allow( unused, diff --git a/tests/ui/single_match.stderr b/tests/ui/single_match.stderr index 40af38879ae..651d0b4911d 100644 --- a/tests/ui/single_match.stderr +++ b/tests/ui/single_match.stderr @@ -1,5 +1,5 @@ error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> tests/ui/single_match.rs:14:5 + --> tests/ui/single_match.rs:16:5 | LL | / match x { LL | | Some(y) => { @@ -19,7 +19,7 @@ LL ~ }; | error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> tests/ui/single_match.rs:22:5 + --> tests/ui/single_match.rs:24:5 | LL | / match x { LL | | // Note the missing block braces. @@ -31,7 +31,7 @@ LL | | } | |_____^ help: try: `if let Some(y) = x { println!("{:?}", y) }` error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> tests/ui/single_match.rs:31:5 + --> tests/ui/single_match.rs:33:5 | LL | / match z { LL | | (2..=3, 7..=9) => dummy(), @@ -40,7 +40,7 @@ LL | | }; | |_____^ help: try: `if let (2..=3, 7..=9) = z { dummy() }` error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> tests/ui/single_match.rs:60:5 + --> tests/ui/single_match.rs:62:5 | LL | / match x { LL | | Some(y) => dummy(), @@ -49,7 +49,7 @@ LL | | }; | |_____^ help: try: `if let Some(y) = x { dummy() }` error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> tests/ui/single_match.rs:65:5 + --> tests/ui/single_match.rs:67:5 | LL | / match y { LL | | Ok(y) => dummy(), @@ -58,7 +58,7 @@ LL | | }; | |_____^ help: try: `if let Ok(y) = y { dummy() }` error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> tests/ui/single_match.rs:72:5 + --> tests/ui/single_match.rs:74:5 | LL | / match c { LL | | Cow::Borrowed(..) => dummy(), @@ -67,7 +67,7 @@ LL | | }; | |_____^ help: try: `if let Cow::Borrowed(..) = c { dummy() }` error: you seem to be trying to use `match` for an equality check. Consider using `if` - --> tests/ui/single_match.rs:93:5 + --> tests/ui/single_match.rs:95:5 | LL | / match x { LL | | "test" => println!(), @@ -76,7 +76,7 @@ LL | | } | |_____^ help: try: `if x == "test" { println!() }` error: you seem to be trying to use `match` for an equality check. Consider using `if` - --> tests/ui/single_match.rs:106:5 + --> tests/ui/single_match.rs:108:5 | LL | / match x { LL | | Foo::A => println!(), @@ -85,7 +85,7 @@ LL | | } | |_____^ help: try: `if x == Foo::A { println!() }` error: you seem to be trying to use `match` for an equality check. Consider using `if` - --> tests/ui/single_match.rs:112:5 + --> tests/ui/single_match.rs:114:5 | LL | / match x { LL | | FOO_C => println!(), @@ -94,7 +94,7 @@ LL | | } | |_____^ help: try: `if x == FOO_C { println!() }` error: you seem to be trying to use `match` for an equality check. Consider using `if` - --> tests/ui/single_match.rs:117:5 + --> tests/ui/single_match.rs:119:5 | LL | / match &&x { LL | | Foo::A => println!(), @@ -103,7 +103,7 @@ LL | | } | |_____^ help: try: `if x == Foo::A { println!() }` error: you seem to be trying to use `match` for an equality check. Consider using `if` - --> tests/ui/single_match.rs:123:5 + --> tests/ui/single_match.rs:125:5 | LL | / match &x { LL | | Foo::A => println!(), @@ -112,7 +112,7 @@ LL | | } | |_____^ help: try: `if x == &Foo::A { println!() }` error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> tests/ui/single_match.rs:140:5 + --> tests/ui/single_match.rs:142:5 | LL | / match x { LL | | Bar::A => println!(), @@ -121,7 +121,7 @@ LL | | } | |_____^ help: try: `if let Bar::A = x { println!() }` error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> tests/ui/single_match.rs:148:5 + --> tests/ui/single_match.rs:150:5 | LL | / match x { LL | | None => println!(), @@ -130,7 +130,7 @@ LL | | }; | |_____^ help: try: `if let None = x { println!() }` error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> tests/ui/single_match.rs:170:5 + --> tests/ui/single_match.rs:172:5 | LL | / match x { LL | | (Some(_), _) => {}, @@ -139,7 +139,7 @@ LL | | } | |_____^ help: try: `if let (Some(_), _) = x {}` error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> tests/ui/single_match.rs:176:5 + --> tests/ui/single_match.rs:178:5 | LL | / match x { LL | | (Some(E::V), _) => todo!(), @@ -148,7 +148,7 @@ LL | | } | |_____^ help: try: `if let (Some(E::V), _) = x { todo!() }` error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> tests/ui/single_match.rs:182:5 + --> tests/ui/single_match.rs:184:5 | LL | / match (Some(42), Some(E::V), Some(42)) { LL | | (.., Some(E::V), _) => {}, @@ -157,7 +157,7 @@ LL | | } | |_____^ help: try: `if let (.., Some(E::V), _) = (Some(42), Some(E::V), Some(42)) {}` error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> tests/ui/single_match.rs:254:5 + --> tests/ui/single_match.rs:256:5 | LL | / match bar { LL | | Some(v) => unsafe { @@ -177,7 +177,7 @@ LL + } } | error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> tests/ui/single_match.rs:262:5 + --> tests/ui/single_match.rs:264:5 | LL | / match bar { LL | | #[rustfmt::skip] diff --git a/tests/ui/single_match_else.fixed b/tests/ui/single_match_else.fixed index f3b1de3b44f..2970f5485fa 100644 --- a/tests/ui/single_match_else.fixed +++ b/tests/ui/single_match_else.fixed @@ -1,4 +1,6 @@ //@aux-build: proc_macros.rs +//@compile-flags: -Zdeduplicate-diagnostics=yes + #![warn(clippy::single_match_else)] #![allow(unused, clippy::needless_return, clippy::no_effect, clippy::uninlined_format_args)] extern crate proc_macros; diff --git a/tests/ui/single_match_else.rs b/tests/ui/single_match_else.rs index ddee2e42ec2..26974b2a48a 100644 --- a/tests/ui/single_match_else.rs +++ b/tests/ui/single_match_else.rs @@ -1,4 +1,6 @@ //@aux-build: proc_macros.rs +//@compile-flags: -Zdeduplicate-diagnostics=yes + #![warn(clippy::single_match_else)] #![allow(unused, clippy::needless_return, clippy::no_effect, clippy::uninlined_format_args)] extern crate proc_macros; diff --git a/tests/ui/single_match_else.stderr b/tests/ui/single_match_else.stderr index 63c733e9a7a..48c74c0caea 100644 --- a/tests/ui/single_match_else.stderr +++ b/tests/ui/single_match_else.stderr @@ -1,5 +1,5 @@ error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> tests/ui/single_match_else.rs:16:13 + --> tests/ui/single_match_else.rs:18:13 | LL | let _ = match ExprNode::Butterflies { | _____________^ @@ -22,7 +22,7 @@ LL ~ }; | error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> tests/ui/single_match_else.rs:81:5 + --> tests/ui/single_match_else.rs:83:5 | LL | / match Some(1) { LL | | Some(a) => println!("${:?}", a), @@ -42,7 +42,7 @@ LL + } | error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> tests/ui/single_match_else.rs:90:5 + --> tests/ui/single_match_else.rs:92:5 | LL | / match Some(1) { LL | | Some(a) => println!("${:?}", a), @@ -62,7 +62,7 @@ LL + } | error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> tests/ui/single_match_else.rs:100:5 + --> tests/ui/single_match_else.rs:102:5 | LL | / match Result::::Ok(1) { LL | | Ok(a) => println!("${:?}", a), @@ -82,7 +82,7 @@ LL + } | error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> tests/ui/single_match_else.rs:109:5 + --> tests/ui/single_match_else.rs:111:5 | LL | / match Cow::from("moo") { LL | | Cow::Owned(a) => println!("${:?}", a), @@ -102,7 +102,7 @@ LL + } | error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> tests/ui/single_match_else.rs:119:5 + --> tests/ui/single_match_else.rs:121:5 | LL | / match bar { LL | | Some(v) => unsafe { @@ -125,7 +125,7 @@ LL + } | error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> tests/ui/single_match_else.rs:130:5 + --> tests/ui/single_match_else.rs:132:5 | LL | / match bar { LL | | Some(v) => { @@ -149,7 +149,7 @@ LL + } } | error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> tests/ui/single_match_else.rs:142:5 + --> tests/ui/single_match_else.rs:144:5 | LL | / match bar { LL | | Some(v) => unsafe { @@ -173,7 +173,7 @@ LL + } } | error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> tests/ui/single_match_else.rs:154:5 + --> tests/ui/single_match_else.rs:156:5 | LL | / match bar { LL | | #[rustfmt::skip] diff --git a/tests/ui/std_instead_of_core.fixed b/tests/ui/std_instead_of_core.fixed index a7555704fbe..0a734a65d29 100644 --- a/tests/ui/std_instead_of_core.fixed +++ b/tests/ui/std_instead_of_core.fixed @@ -1,4 +1,5 @@ //@aux-build:proc_macro_derive.rs + #![warn(clippy::std_instead_of_core)] #![allow(unused_imports)] @@ -16,12 +17,20 @@ fn std_instead_of_core() { use ::core::hash::Hash; //~^ ERROR: used import from `std` instead of `core` // Don't lint on `env` macro - use std::env; + use core::env; // Multiple imports use core::fmt::{Debug, Result}; //~^ ERROR: used import from `std` instead of `core` + // Multiple imports multiline + #[rustfmt::skip] + use core::{ + //~^ ERROR: used import from `std` instead of `core` + fmt::Write as _, + ptr::read_unaligned, + }; + // Function calls let ptr = core::ptr::null::(); //~^ ERROR: used import from `std` instead of `core` diff --git a/tests/ui/std_instead_of_core.rs b/tests/ui/std_instead_of_core.rs index af7f3399f49..c12c459c7eb 100644 --- a/tests/ui/std_instead_of_core.rs +++ b/tests/ui/std_instead_of_core.rs @@ -1,4 +1,5 @@ //@aux-build:proc_macro_derive.rs + #![warn(clippy::std_instead_of_core)] #![allow(unused_imports)] @@ -22,6 +23,14 @@ fn std_instead_of_core() { use std::fmt::{Debug, Result}; //~^ ERROR: used import from `std` instead of `core` + // Multiple imports multiline + #[rustfmt::skip] + use std::{ + //~^ ERROR: used import from `std` instead of `core` + fmt::Write as _, + ptr::read_unaligned, + }; + // Function calls let ptr = std::ptr::null::(); //~^ ERROR: used import from `std` instead of `core` diff --git a/tests/ui/std_instead_of_core.stderr b/tests/ui/std_instead_of_core.stderr index 30dd49dc268..ee42b474a32 100644 --- a/tests/ui/std_instead_of_core.stderr +++ b/tests/ui/std_instead_of_core.stderr @@ -1,5 +1,5 @@ error: used import from `std` instead of `core` - --> tests/ui/std_instead_of_core.rs:13:9 + --> tests/ui/std_instead_of_core.rs:14:9 | LL | use std::hash::Hasher; | ^^^ help: consider importing the item from `core`: `core` @@ -8,49 +8,61 @@ LL | use std::hash::Hasher; = help: to override `-D warnings` add `#[allow(clippy::std_instead_of_core)]` error: used import from `std` instead of `core` - --> tests/ui/std_instead_of_core.rs:16:11 + --> tests/ui/std_instead_of_core.rs:17:11 | LL | use ::std::hash::Hash; | ^^^ help: consider importing the item from `core`: `core` error: used import from `std` instead of `core` - --> tests/ui/std_instead_of_core.rs:22:9 + --> tests/ui/std_instead_of_core.rs:20:9 + | +LL | use std::env; + | ^^^ help: consider importing the item from `core`: `core` + +error: used import from `std` instead of `core` + --> tests/ui/std_instead_of_core.rs:23:9 | LL | use std::fmt::{Debug, Result}; | ^^^ help: consider importing the item from `core`: `core` error: used import from `std` instead of `core` - --> tests/ui/std_instead_of_core.rs:26:15 + --> tests/ui/std_instead_of_core.rs:28:9 + | +LL | use std::{ + | ^^^ help: consider importing the item from `core`: `core` + +error: used import from `std` instead of `core` + --> tests/ui/std_instead_of_core.rs:35:15 | LL | let ptr = std::ptr::null::(); | ^^^ help: consider importing the item from `core`: `core` error: used import from `std` instead of `core` - --> tests/ui/std_instead_of_core.rs:28:21 + --> tests/ui/std_instead_of_core.rs:37:21 | LL | let ptr_mut = ::std::ptr::null_mut::(); | ^^^ help: consider importing the item from `core`: `core` error: used import from `std` instead of `core` - --> tests/ui/std_instead_of_core.rs:32:16 + --> tests/ui/std_instead_of_core.rs:41:16 | LL | let cell = std::cell::Cell::new(8u32); | ^^^ help: consider importing the item from `core`: `core` error: used import from `std` instead of `core` - --> tests/ui/std_instead_of_core.rs:34:27 + --> tests/ui/std_instead_of_core.rs:43:27 | LL | let cell_absolute = ::std::cell::Cell::new(8u32); | ^^^ help: consider importing the item from `core`: `core` error: used import from `std` instead of `core` - --> tests/ui/std_instead_of_core.rs:43:9 + --> tests/ui/std_instead_of_core.rs:52:9 | LL | use std::iter::Iterator; | ^^^ help: consider importing the item from `core`: `core` error: used import from `std` instead of `alloc` - --> tests/ui/std_instead_of_core.rs:50:9 + --> tests/ui/std_instead_of_core.rs:59:9 | LL | use std::vec; | ^^^ help: consider importing the item from `alloc`: `alloc` @@ -59,13 +71,13 @@ LL | use std::vec; = help: to override `-D warnings` add `#[allow(clippy::std_instead_of_alloc)]` error: used import from `std` instead of `alloc` - --> tests/ui/std_instead_of_core.rs:52:9 + --> tests/ui/std_instead_of_core.rs:61:9 | LL | use std::vec::Vec; | ^^^ help: consider importing the item from `alloc`: `alloc` error: used import from `alloc` instead of `core` - --> tests/ui/std_instead_of_core.rs:58:9 + --> tests/ui/std_instead_of_core.rs:67:9 | LL | use alloc::slice::from_ref; | ^^^^^ help: consider importing the item from `core`: `core` @@ -73,5 +85,5 @@ LL | use alloc::slice::from_ref; = note: `-D clippy::alloc-instead-of-core` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::alloc_instead_of_core)]` -error: aborting due to 11 previous errors +error: aborting due to 13 previous errors diff --git a/tests/ui/suspicious_operation_groupings.fixed b/tests/ui/suspicious_operation_groupings.fixed index 9d9732307c8..60fde6e22cb 100644 --- a/tests/ui/suspicious_operation_groupings.fixed +++ b/tests/ui/suspicious_operation_groupings.fixed @@ -1,3 +1,5 @@ +//@compile-flags: -Zdeduplicate-diagnostics=yes + #![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 201b8e657f4..ce37148a853 100644 --- a/tests/ui/suspicious_operation_groupings.rs +++ b/tests/ui/suspicious_operation_groupings.rs @@ -1,3 +1,5 @@ +//@compile-flags: -Zdeduplicate-diagnostics=yes + #![warn(clippy::suspicious_operation_groupings)] #![allow(dead_code, unused_parens, clippy::eq_op)] diff --git a/tests/ui/suspicious_operation_groupings.stderr b/tests/ui/suspicious_operation_groupings.stderr index 9d1d8a1f34f..7cb066d57e7 100644 --- a/tests/ui/suspicious_operation_groupings.stderr +++ b/tests/ui/suspicious_operation_groupings.stderr @@ -1,5 +1,5 @@ error: this sequence of operators looks suspiciously like a bug - --> tests/ui/suspicious_operation_groupings.rs:15:9 + --> tests/ui/suspicious_operation_groupings.rs:17:9 | LL | self.x == other.y && self.y == other.y && self.z == other.z | ^^^^^^^^^^^^^^^^^ help: did you mean: `self.x == other.x` @@ -8,151 +8,151 @@ LL | self.x == other.y && self.y == other.y && self.z == other.z = help: to override `-D warnings` add `#[allow(clippy::suspicious_operation_groupings)]` error: this sequence of operators looks suspiciously like a bug - --> tests/ui/suspicious_operation_groupings.rs:28:20 + --> tests/ui/suspicious_operation_groupings.rs:30:20 | LL | s1.a < s2.a && s1.a < s2.b | ^^^^^^^^^^^ help: did you mean: `s1.b < s2.b` error: this sequence of operators looks suspiciously like a bug - --> tests/ui/suspicious_operation_groupings.rs:76:33 + --> tests/ui/suspicious_operation_groupings.rs:78:33 | LL | s1.a * s2.a + s1.b * s2.b + s1.c * s2.b + s1.d * s2.d | ^^^^^^^^^^^ help: did you mean: `s1.c * s2.c` error: this sequence of operators looks suspiciously like a bug - --> tests/ui/suspicious_operation_groupings.rs:81:19 + --> tests/ui/suspicious_operation_groupings.rs:83:19 | LL | s1.a * s2.a + s1.b * s2.c + s1.c * s2.c | ^^^^^^^^^^^ help: did you mean: `s1.b * s2.b` error: this sequence of operators looks suspiciously like a bug - --> tests/ui/suspicious_operation_groupings.rs:81:19 + --> tests/ui/suspicious_operation_groupings.rs:83:19 | LL | s1.a * s2.a + s1.b * s2.c + s1.c * s2.c | ^^^^^^^^^^^ help: did you mean: `s1.b * s2.b` error: this sequence of operators looks suspiciously like a bug - --> tests/ui/suspicious_operation_groupings.rs:86:19 + --> tests/ui/suspicious_operation_groupings.rs:88:19 | LL | s1.a * s2.a + s2.b * s2.b + s1.c * s2.c | ^^^^^^^^^^^ help: did you mean: `s1.b * s2.b` error: this sequence of operators looks suspiciously like a bug - --> tests/ui/suspicious_operation_groupings.rs:91:19 + --> tests/ui/suspicious_operation_groupings.rs:93:19 | LL | s1.a * s2.a + s1.b * s1.b + s1.c * s2.c | ^^^^^^^^^^^ help: did you mean: `s1.b * s2.b` error: this sequence of operators looks suspiciously like a bug - --> tests/ui/suspicious_operation_groupings.rs:96:5 + --> tests/ui/suspicious_operation_groupings.rs:98:5 | LL | s1.a * s1.a + s1.b * s2.b + s1.c * s2.c | ^^^^^^^^^^^ help: did you mean: `s1.a * s2.a` error: this sequence of operators looks suspiciously like a bug - --> tests/ui/suspicious_operation_groupings.rs:101:33 + --> tests/ui/suspicious_operation_groupings.rs:103:33 | LL | s1.a * s2.a + s1.b * s2.b + s1.c * s1.c | ^^^^^^^^^^^ help: did you mean: `s1.c * s2.c` error: this sequence of operators looks suspiciously like a bug - --> tests/ui/suspicious_operation_groupings.rs:114:20 + --> tests/ui/suspicious_operation_groupings.rs:116:20 | LL | (s1.a * s2.a + s1.b * s1.b) | ^^^^^^^^^^^ help: did you mean: `s1.b * s2.b` error: this sequence of operators looks suspiciously like a bug - --> tests/ui/suspicious_operation_groupings.rs:119:34 + --> tests/ui/suspicious_operation_groupings.rs:121:34 | LL | (s1.a * s2.a + s1.b * s2.b + s1.c * s2.b + s1.d * s2.d) | ^^^^^^^^^^^ help: did you mean: `s1.c * s2.c` error: this sequence of operators looks suspiciously like a bug - --> tests/ui/suspicious_operation_groupings.rs:124:38 + --> tests/ui/suspicious_operation_groupings.rs:126:38 | LL | (s1.a * s2.a) + (s1.b * s2.b) + (s1.c * s2.b) + (s1.d * s2.d) | ^^^^^^^^^^^ help: did you mean: `s1.c * s2.c` error: this sequence of operators looks suspiciously like a bug - --> tests/ui/suspicious_operation_groupings.rs:129:39 + --> tests/ui/suspicious_operation_groupings.rs:131:39 | LL | ((s1.a * s2.a) + (s1.b * s2.b) + (s1.c * s2.b) + (s1.d * s2.d)) | ^^^^^^^^^^^ help: did you mean: `s1.c * s2.c` error: this sequence of operators looks suspiciously like a bug - --> tests/ui/suspicious_operation_groupings.rs:134:42 + --> tests/ui/suspicious_operation_groupings.rs:136:42 | LL | (((s1.a * s2.a) + (s1.b * s2.b)) + ((s1.c * s2.b) + (s1.d * s2.d))) | ^^^^^^^^^^^ help: did you mean: `s1.c * s2.c` error: this sequence of operators looks suspiciously like a bug - --> tests/ui/suspicious_operation_groupings.rs:134:42 + --> tests/ui/suspicious_operation_groupings.rs:136:42 | LL | (((s1.a * s2.a) + (s1.b * s2.b)) + ((s1.c * s2.b) + (s1.d * s2.d))) | ^^^^^^^^^^^ help: did you mean: `s1.c * s2.c` error: this sequence of operators looks suspiciously like a bug - --> tests/ui/suspicious_operation_groupings.rs:139:40 + --> tests/ui/suspicious_operation_groupings.rs:141:40 | LL | (((s1.a * s2.a) + (s1.b * s2.b) + (s1.c * s2.b)) + (s1.d * s2.d)) | ^^^^^^^^^^^ help: did you mean: `s1.c * s2.c` error: this sequence of operators looks suspiciously like a bug - --> tests/ui/suspicious_operation_groupings.rs:144:40 + --> tests/ui/suspicious_operation_groupings.rs:146:40 | LL | ((s1.a * s2.a) + ((s1.b * s2.b) + (s1.c * s2.b) + (s1.d * s2.d))) | ^^^^^^^^^^^ help: did you mean: `s1.c * s2.c` error: this sequence of operators looks suspiciously like a bug - --> tests/ui/suspicious_operation_groupings.rs:149:20 + --> tests/ui/suspicious_operation_groupings.rs:151:20 | LL | (s1.a * s2.a + s2.b * s2.b) / 2 | ^^^^^^^^^^^ help: did you mean: `s1.b * s2.b` error: this sequence of operators looks suspiciously like a bug - --> tests/ui/suspicious_operation_groupings.rs:154:35 + --> tests/ui/suspicious_operation_groupings.rs:156:35 | LL | i32::swap_bytes(s1.a * s2.a + s2.b * s2.b) | ^^^^^^^^^^^ help: did you mean: `s1.b * s2.b` error: this sequence of operators looks suspiciously like a bug - --> tests/ui/suspicious_operation_groupings.rs:159:29 + --> tests/ui/suspicious_operation_groupings.rs:161:29 | LL | s1.a > 0 && s1.b > 0 && s1.d == s2.c && s1.d == s2.d | ^^^^^^^^^^^^ help: did you mean: `s1.c == s2.c` error: this sequence of operators looks suspiciously like a bug - --> tests/ui/suspicious_operation_groupings.rs:164:17 + --> tests/ui/suspicious_operation_groupings.rs:166:17 | LL | s1.a > 0 && s1.d == s2.c && s1.b > 0 && s1.d == s2.d | ^^^^^^^^^^^^ help: did you mean: `s1.c == s2.c` error: this sequence of operators looks suspiciously like a bug - --> tests/ui/suspicious_operation_groupings.rs:173:77 + --> tests/ui/suspicious_operation_groupings.rs:175:77 | LL | (n1.inner.0).0 == (n2.inner.0).0 && (n1.inner.1).0 == (n2.inner.1).0 && (n1.inner.2).0 == (n2.inner.1).0 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: did you mean: `(n1.inner.2).0 == (n2.inner.2).0` error: this sequence of operators looks suspiciously like a bug - --> tests/ui/suspicious_operation_groupings.rs:187:25 + --> tests/ui/suspicious_operation_groupings.rs:189:25 | LL | s1.a <= s2.a && s1.a <= s2.b | ^^^^^^^^^^^^ help: did you mean: `s1.b <= s2.b` error: this sequence of operators looks suspiciously like a bug - --> tests/ui/suspicious_operation_groupings.rs:193:23 + --> tests/ui/suspicious_operation_groupings.rs:195:23 | LL | if s1.a < s2.a && s1.a < s2.b { | ^^^^^^^^^^^ help: did you mean: `s1.b < s2.b` error: this sequence of operators looks suspiciously like a bug - --> tests/ui/suspicious_operation_groupings.rs:200:48 + --> tests/ui/suspicious_operation_groupings.rs:202:48 | LL | -(-(-s1.a * -s2.a) + (-(-s1.b * -s2.b) + -(-s1.c * -s2.b) + -(-s1.d * -s2.d))) | ^^^^^^^^^^^^^ help: did you mean: `-s1.c * -s2.c` error: this sequence of operators looks suspiciously like a bug - --> tests/ui/suspicious_operation_groupings.rs:205:27 + --> tests/ui/suspicious_operation_groupings.rs:207:27 | LL | -(if -s1.a < -s2.a && -s1.a < -s2.b { s1.c } else { s2.a }) | ^^^^^^^^^^^^^ help: did you mean: `-s1.b < -s2.b` diff --git a/tests/ui/thread_local_initializer_can_be_made_const.fixed b/tests/ui/thread_local_initializer_can_be_made_const.fixed index bbde25b0a88..a6ed59d49c5 100644 --- a/tests/ui/thread_local_initializer_can_be_made_const.fixed +++ b/tests/ui/thread_local_initializer_can_be_made_const.fixed @@ -27,4 +27,18 @@ fn main() { } //~^^^^ ERROR: initializer for `thread_local` value can be made `const` //~^^^ ERROR: initializer for `thread_local` value can be made `const` + + thread_local! { + static PEEL_ME: i32 = const { 1 }; + //~^ ERROR: initializer for `thread_local` value can be made `const` + static PEEL_ME_MANY: i32 = const { { let x = 1; x * x } }; + //~^ ERROR: initializer for `thread_local` value can be made `const` + } +} + +#[clippy::msrv = "1.58"] +fn f() { + thread_local! { + static TLS: i32 = 1; + } } diff --git a/tests/ui/thread_local_initializer_can_be_made_const.rs b/tests/ui/thread_local_initializer_can_be_made_const.rs index 3d7aacf2f09..3f0159c5806 100644 --- a/tests/ui/thread_local_initializer_can_be_made_const.rs +++ b/tests/ui/thread_local_initializer_can_be_made_const.rs @@ -27,4 +27,18 @@ fn main() { } //~^^^^ ERROR: initializer for `thread_local` value can be made `const` //~^^^ ERROR: initializer for `thread_local` value can be made `const` + + thread_local! { + static PEEL_ME: i32 = { 1 }; + //~^ ERROR: initializer for `thread_local` value can be made `const` + static PEEL_ME_MANY: i32 = { let x = 1; x * x }; + //~^ ERROR: initializer for `thread_local` value can be made `const` + } +} + +#[clippy::msrv = "1.58"] +fn f() { + thread_local! { + static TLS: i32 = 1; + } } diff --git a/tests/ui/thread_local_initializer_can_be_made_const.stderr b/tests/ui/thread_local_initializer_can_be_made_const.stderr index 9ee52fbbb31..b4f8bd822b0 100644 --- a/tests/ui/thread_local_initializer_can_be_made_const.stderr +++ b/tests/ui/thread_local_initializer_can_be_made_const.stderr @@ -25,5 +25,17 @@ error: initializer for `thread_local` value can be made `const` LL | static BUF_4_CAN_BE_MADE_CONST: RefCell = RefCell::new(String::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `const { RefCell::new(String::new()) }` -error: aborting due to 4 previous errors +error: initializer for `thread_local` value can be made `const` + --> tests/ui/thread_local_initializer_can_be_made_const.rs:32:31 + | +LL | static PEEL_ME: i32 = { 1 }; + | ^^^^^ help: replace with: `const { 1 }` + +error: initializer for `thread_local` value can be made `const` + --> tests/ui/thread_local_initializer_can_be_made_const.rs:34:36 + | +LL | static PEEL_ME_MANY: i32 = { let x = 1; x * x }; + | ^^^^^^^^^^^^^^^^^^^^ help: replace with: `const { { let x = 1; x * x } }` + +error: aborting due to 6 previous errors diff --git a/tests/ui/transmutes_expressible_as_ptr_casts.fixed b/tests/ui/transmutes_expressible_as_ptr_casts.fixed index 08b8e786611..2365695d691 100644 --- a/tests/ui/transmutes_expressible_as_ptr_casts.fixed +++ b/tests/ui/transmutes_expressible_as_ptr_casts.fixed @@ -82,3 +82,10 @@ fn issue_10449() { let _x: u8 = unsafe { *(f as *const u8) }; } + +// Pointers cannot be cast to integers in const contexts +const fn issue_12402

(ptr: *const P) { + unsafe { transmute::<*const i32, usize>(&42i32) }; + unsafe { transmute::(issue_12402) }; + let _ = unsafe { transmute::<_, usize>(ptr) }; +} diff --git a/tests/ui/transmutes_expressible_as_ptr_casts.rs b/tests/ui/transmutes_expressible_as_ptr_casts.rs index 92eb765e5f9..cd1607b4c19 100644 --- a/tests/ui/transmutes_expressible_as_ptr_casts.rs +++ b/tests/ui/transmutes_expressible_as_ptr_casts.rs @@ -82,3 +82,10 @@ fn f() {} let _x: u8 = unsafe { *std::mem::transmute::(f) }; } + +// Pointers cannot be cast to integers in const contexts +const fn issue_12402

(ptr: *const P) { + unsafe { transmute::<*const i32, usize>(&42i32) }; + unsafe { transmute::(issue_12402) }; + let _ = unsafe { transmute::<_, usize>(ptr) }; +} diff --git a/tests/ui/type_complexity.rs b/tests/ui/type_complexity.rs index be28ee2da0c..b057dc4e89f 100644 --- a/tests/ui/type_complexity.rs +++ b/tests/ui/type_complexity.rs @@ -1,3 +1,5 @@ +//@compile-flags: -Zdeduplicate-diagnostics=yes + #![warn(clippy::all)] #![allow(unused, clippy::needless_pass_by_value, clippy::vec_box, clippy::useless_vec)] #![feature(associated_type_defaults)] diff --git a/tests/ui/type_complexity.stderr b/tests/ui/type_complexity.stderr index 9e27899e4f9..bfbab8647e8 100644 --- a/tests/ui/type_complexity.stderr +++ b/tests/ui/type_complexity.stderr @@ -1,5 +1,5 @@ error: very complex type used. Consider factoring parts into `type` definitions - --> tests/ui/type_complexity.rs:7:12 + --> tests/ui/type_complexity.rs:9:12 | LL | const CST: (u32, (u32, (u32, (u32, u32)))) = (0, (0, (0, (0, 0)))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -8,85 +8,85 @@ LL | const CST: (u32, (u32, (u32, (u32, u32)))) = (0, (0, (0, (0, 0)))); = help: to override `-D warnings` add `#[allow(clippy::type_complexity)]` error: very complex type used. Consider factoring parts into `type` definitions - --> tests/ui/type_complexity.rs:10:12 + --> tests/ui/type_complexity.rs:12:12 | LL | static ST: (u32, (u32, (u32, (u32, u32)))) = (0, (0, (0, (0, 0)))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: very complex type used. Consider factoring parts into `type` definitions - --> tests/ui/type_complexity.rs:14:8 + --> tests/ui/type_complexity.rs:16:8 | LL | f: Vec>>, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: very complex type used. Consider factoring parts into `type` definitions - --> tests/ui/type_complexity.rs:18:11 + --> tests/ui/type_complexity.rs:20:11 | LL | struct Ts(Vec>>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: very complex type used. Consider factoring parts into `type` definitions - --> tests/ui/type_complexity.rs:22:11 + --> tests/ui/type_complexity.rs:24:11 | LL | Tuple(Vec>>), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: very complex type used. Consider factoring parts into `type` definitions - --> tests/ui/type_complexity.rs:24:17 + --> tests/ui/type_complexity.rs:26:17 | LL | Struct { f: Vec>> }, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: very complex type used. Consider factoring parts into `type` definitions - --> tests/ui/type_complexity.rs:29:14 + --> tests/ui/type_complexity.rs:31:14 | LL | const A: (u32, (u32, (u32, (u32, u32)))) = (0, (0, (0, (0, 0)))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: very complex type used. Consider factoring parts into `type` definitions - --> tests/ui/type_complexity.rs:31:30 + --> tests/ui/type_complexity.rs:33:30 | LL | fn impl_method(&self, p: Vec>>) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: very complex type used. Consider factoring parts into `type` definitions - --> tests/ui/type_complexity.rs:36:14 + --> tests/ui/type_complexity.rs:38:14 | LL | const A: Vec>>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: very complex type used. Consider factoring parts into `type` definitions - --> tests/ui/type_complexity.rs:38:14 + --> tests/ui/type_complexity.rs:40:14 | LL | type B = Vec>>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: very complex type used. Consider factoring parts into `type` definitions - --> tests/ui/type_complexity.rs:40:25 + --> tests/ui/type_complexity.rs:42:25 | LL | fn method(&self, p: Vec>>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: very complex type used. Consider factoring parts into `type` definitions - --> tests/ui/type_complexity.rs:42:29 + --> tests/ui/type_complexity.rs:44:29 | LL | fn def_method(&self, p: Vec>>) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: very complex type used. Consider factoring parts into `type` definitions - --> tests/ui/type_complexity.rs:55:15 + --> tests/ui/type_complexity.rs:57:15 | LL | fn test1() -> Vec>> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: very complex type used. Consider factoring parts into `type` definitions - --> tests/ui/type_complexity.rs:60:14 + --> tests/ui/type_complexity.rs:62:14 | LL | fn test2(_x: Vec>>) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: very complex type used. Consider factoring parts into `type` definitions - --> tests/ui/type_complexity.rs:64:13 + --> tests/ui/type_complexity.rs:66:13 | LL | let _y: Vec>> = vec![]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/unknown_attribute.rs b/tests/ui/unknown_attribute.rs index 932f284d5b7..3241742b5d4 100644 --- a/tests/ui/unknown_attribute.rs +++ b/tests/ui/unknown_attribute.rs @@ -1,3 +1,5 @@ +//@compile-flags: -Zdeduplicate-diagnostics=yes + #[clippy::unknown] //~^ ERROR: usage of unknown attribute #[clippy::cognitive_complexity = "1"] diff --git a/tests/ui/unknown_attribute.stderr b/tests/ui/unknown_attribute.stderr index d1f8eeb51ae..b306abe0a9d 100644 --- a/tests/ui/unknown_attribute.stderr +++ b/tests/ui/unknown_attribute.stderr @@ -1,5 +1,5 @@ error: usage of unknown attribute - --> tests/ui/unknown_attribute.rs:1:11 + --> tests/ui/unknown_attribute.rs:3:11 | LL | #[clippy::unknown] | ^^^^^^^ diff --git a/tests/ui/unnecessary_cast.fixed b/tests/ui/unnecessary_cast.fixed index f52d3250339..288541362cd 100644 --- a/tests/ui/unnecessary_cast.fixed +++ b/tests/ui/unnecessary_cast.fixed @@ -221,4 +221,10 @@ mod fixable { fn issue_9603() { let _: f32 = -0x400 as f32; } + + // Issue #11968: The suggestion for this lint removes the parentheses and leave the code as + // `*x.pow(2)` which tries to dereference the return value rather than `x`. + fn issue_11968(x: &usize) -> usize { + { *x }.pow(2) + } } diff --git a/tests/ui/unnecessary_cast.rs b/tests/ui/unnecessary_cast.rs index dfd8b454e6c..eef3a42e351 100644 --- a/tests/ui/unnecessary_cast.rs +++ b/tests/ui/unnecessary_cast.rs @@ -221,4 +221,10 @@ fn foo() -> f32 { fn issue_9603() { let _: f32 = -0x400 as f32; } + + // Issue #11968: The suggestion for this lint removes the parentheses and leave the code as + // `*x.pow(2)` which tries to dereference the return value rather than `x`. + fn issue_11968(x: &usize) -> usize { + (*x as usize).pow(2) + } } diff --git a/tests/ui/unnecessary_cast.stderr b/tests/ui/unnecessary_cast.stderr index 935bb71da32..80fd5c13d81 100644 --- a/tests/ui/unnecessary_cast.stderr +++ b/tests/ui/unnecessary_cast.stderr @@ -241,5 +241,11 @@ error: casting to the same type is unnecessary (`f32` -> `f32`) LL | let _num = foo() as f32; | ^^^^^^^^^^^^ help: try: `foo()` -error: aborting due to 40 previous errors +error: casting to the same type is unnecessary (`usize` -> `usize`) + --> tests/ui/unnecessary_cast.rs:228:9 + | +LL | (*x as usize).pow(2) + | ^^^^^^^^^^^^^ help: try: `{ *x }` + +error: aborting due to 41 previous errors