Merge from rustc
This commit is contained in:
commit
55b757ee3c
4
.github/driver.sh
vendored
4
.github/driver.sh
vendored
@ -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)
|
||||
|
||||
|
11
.github/workflows/clippy.yml
vendored
11
.github/workflows/clippy.yml
vendored
@ -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
|
||||
|
32
.github/workflows/clippy_bors.yml
vendored
32
.github/workflows/clippy_bors.yml
vendored
@ -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 }}
|
||||
|
||||
|
124
CHANGELOG.md
124
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
|
||||
<!-- end autogenerated links to lint list -->
|
||||
<!-- begin autogenerated links to configuration documentation -->
|
||||
[`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
|
||||
<!-- end autogenerated links to configuration documentation -->
|
||||
|
@ -94,6 +94,53 @@ impl LateLintPass<'_> for CheckTokioAsyncReadExtTrait {
|
||||
}
|
||||
```
|
||||
|
||||
## Creating Types Programmatically
|
||||
|
||||
Traits are often generic over a type parameter, e.g. `Borrow<T>` 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
|
||||
|
@ -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
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -193,7 +193,7 @@ fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error> where V: MapA
|
||||
}
|
||||
|
||||
pub fn get_configuration_metadata() -> Vec<ClippyConfiguration> {
|
||||
vec![
|
||||
let mut sorted = vec![
|
||||
$(
|
||||
{
|
||||
let deprecation_reason = wrap_option!($($dep)?);
|
||||
@ -206,7 +206,9 @@ pub fn get_configuration_metadata() -> Vec<ClippyConfiguration> {
|
||||
)
|
||||
},
|
||||
)+
|
||||
]
|
||||
];
|
||||
sorted.sort_by(|a, b| a.name.cmp(&b.name));
|
||||
sorted
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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 }
|
||||
|
322
clippy_lints/src/assigning_clones.rs
Normal file
322
clippy_lints/src/assigning_clones.rs
Normal file
@ -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<CallCandidate<'tcx>> {
|
||||
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})")
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
37
clippy_lints/src/attrs/allow_attributes_without_reason.rs
Normal file
37
clippy_lints/src/attrs/allow_attributes_without_reason.rs
Normal file
@ -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 = \"..\"`",
|
||||
);
|
||||
}
|
44
clippy_lints/src/attrs/blanket_clippy_restriction_lints.rs
Normal file
44
clippy_lints/src/attrs/blanket_clippy_restriction_lints.rs
Normal file
@ -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");
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
87
clippy_lints/src/attrs/deprecated_cfg_attr.rs
Normal file
87
clippy_lints/src/attrs/deprecated_cfg_attr.rs
Normal file
@ -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,
|
||||
);
|
||||
}
|
||||
}
|
20
clippy_lints/src/attrs/deprecated_semver.rs
Normal file
20
clippy_lints/src/attrs/deprecated_semver.rs
Normal file
@ -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",
|
||||
);
|
||||
}
|
52
clippy_lints/src/attrs/empty_line_after.rs
Normal file
52
clippy_lints/src/attrs/empty_line_after.rs
Normal file
@ -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::<Vec<_>>();
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
29
clippy_lints/src/attrs/inline_always.rs
Normal file
29
clippy_lints/src/attrs/inline_always.rs
Normal file
@ -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"),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
51
clippy_lints/src/attrs/maybe_misused_cfg.rs
Normal file
51
clippy_lints/src/attrs/maybe_misused_cfg.rs
Normal file
@ -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,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
90
clippy_lints/src/attrs/mismatched_target_os.rs
Normal file
90
clippy_lints/src/attrs/mismatched_target_os.rs
Normal file
@ -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;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
30
clippy_lints/src/attrs/mixed_attributes_style.rs
Normal file
30
clippy_lints/src/attrs/mixed_attributes_style.rs
Normal file
@ -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",
|
||||
);
|
||||
}
|
588
clippy_lints/src/attrs/mod.rs
Normal file
588
clippy_lints/src/attrs/mod.rs
Normal file
@ -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);
|
||||
}
|
49
clippy_lints/src/attrs/non_minimal_cfg.rs
Normal file
49
clippy_lints/src/attrs/non_minimal_cfg.rs
Normal file
@ -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",
|
||||
|_| {},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
54
clippy_lints/src/attrs/should_panic_without_expect.rs
Normal file
54
clippy_lints/src/attrs/should_panic_without_expect.rs
Normal file
@ -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,
|
||||
);
|
||||
}
|
||||
}
|
70
clippy_lints/src/attrs/unnecessary_clippy_cfg.rs
Normal file
70
clippy_lints/src/attrs/unnecessary_clippy_cfg.rs
Normal file
@ -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::<Vec<_>>()
|
||||
.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
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
73
clippy_lints/src/attrs/useless_attribute.rs
Normal file
73
clippy_lints/src/attrs/useless_attribute.rs
Normal file
@ -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,
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
87
clippy_lints/src/attrs/utils.rs
Normal file
87
clippy_lints/src/attrs/utils.rs
Normal file
@ -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<Symbol> {
|
||||
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
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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.
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
use crate::doc::DOC_MARKDOWN;
|
||||
|
||||
pub fn check(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, text: &str, span: Span) {
|
||||
pub fn check(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, 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<String>, 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;
|
||||
}
|
||||
|
||||
|
@ -599,10 +599,19 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
|
||||
let mut ignore = false;
|
||||
let mut edition = None;
|
||||
let mut ticks_unbalanced = false;
|
||||
let mut text_to_check: Vec<(CowStr<'_>, Range<usize>)> = Vec::new();
|
||||
let mut text_to_check: Vec<(CowStr<'_>, Range<usize>, 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("<code") {
|
||||
code_level += 1;
|
||||
} else if tag.starts_with("</code") {
|
||||
code_level -= 1;
|
||||
}
|
||||
},
|
||||
Start(CodeBlock(ref kind)) => {
|
||||
in_code = true;
|
||||
if let CodeBlockKind::Fenced(lang) = kind {
|
||||
@ -652,16 +661,15 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
|
||||
"a backtick may be missing a pair",
|
||||
);
|
||||
} else {
|
||||
for (text, range) in text_to_check {
|
||||
for (text, range, assoc_code_level) in text_to_check {
|
||||
if let Some(span) = fragments.span(cx, range) {
|
||||
markdown::check(cx, valid_idents, &text, span);
|
||||
markdown::check(cx, valid_idents, &text, span, assoc_code_level);
|
||||
}
|
||||
}
|
||||
}
|
||||
text_to_check = Vec::new();
|
||||
},
|
||||
Start(_tag) | End(_tag) => (), // 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<Item = (pulldown_cmark::Event<'a>, Range<usize
|
||||
// Don't check the text associated with external URLs
|
||||
continue;
|
||||
}
|
||||
text_to_check.push((text, range));
|
||||
text_to_check.push((text, range, code_level));
|
||||
}
|
||||
},
|
||||
}
|
||||
|
@ -214,12 +214,31 @@ fn entry_path(self) -> &'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<InsertExpr<'tcx>> {
|
||||
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)
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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`
|
||||
}
|
||||
|
||||
|
@ -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((
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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(
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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<bool> {
|
||||
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} }}"),
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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())
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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", "<impl bool>", "then"];
|
||||
pub const ALLOCATOR_GLOBAL: [&str; 3] = ["alloc", "alloc", "Global"];
|
||||
|
@ -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;
|
||||
},
|
||||
_ => (),
|
||||
|
@ -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"]
|
||||
|
@ -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.:
|
||||
|
||||
<yellow,bold>#[allow(clippy::needless_lifetimes)]</>
|
||||
"
|
||||
)
|
||||
|
||||
<green,bold>Manifest Options:</>
|
||||
<cyan,bold>--manifest-path</> <cyan><<PATH>></> Path to Cargo.toml
|
||||
<cyan,bold>--frozen</> Require Cargo.lock and cache are up to date
|
||||
<cyan,bold>--locked</> Require Cargo.lock is up to date
|
||||
<cyan,bold>--offline</> Run without accessing the network
|
||||
")
|
||||
}
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
@ -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()),
|
||||
]
|
||||
|
@ -54,7 +54,7 @@ fn explore_directory(dir: &Path) -> Vec<String> {
|
||||
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());
|
||||
|
@ -5,6 +5,7 @@
|
||||
//@normalize-stderr-test: "'rustc'" -> "'<unnamed>'"
|
||||
//@normalize-stderr-test: "rustc 1\.\d+.* running on .*" -> "rustc <version> running on <target>"
|
||||
//@normalize-stderr-test: "(?ms)query stack during panic:\n.*end of query stack\n" -> ""
|
||||
//@normalize-stderr-test: "this compiler `.*` is outdated" -> "this compiler <version> is outdated"
|
||||
|
||||
#![deny(clippy::internal)]
|
||||
#![allow(clippy::missing_clippy_version_attribute)]
|
||||
|
@ -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 <version> 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 <version> running on <target>
|
||||
|
||||
note: compiler flags: -Z ui-testing
|
||||
note: compiler flags: -Z ui-testing -Z deduplicate-diagnostics=no
|
||||
|
||||
note: Clippy version: foo
|
||||
|
||||
|
@ -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<MultiSpan>,
|
||||
msg: impl Into<DiagMessage>)
|
||||
{
|
||||
pub fn a(cx: impl LintContext, lint: &'static Lint, span: impl Into<MultiSpan>, msg: impl Into<DiagMessage>) {
|
||||
cx.span_lint(lint, span, msg, |_| {});
|
||||
}
|
||||
|
||||
pub fn b(
|
||||
tcx: TyCtxt<'_>,
|
||||
lint: &'static Lint,
|
||||
hir_id: HirId,
|
||||
span: impl Into<MultiSpan>,
|
||||
msg: impl Into<DiagMessage>,
|
||||
) {
|
||||
pub fn b(tcx: TyCtxt<'_>, lint: &'static Lint, hir_id: HirId, span: impl Into<MultiSpan>, msg: impl Into<DiagMessage>) {
|
||||
tcx.node_span_lint(lint, hir_id, span, msg, |_| {});
|
||||
}
|
||||
|
||||
|
@ -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, |_| {});
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
@ -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 {};
|
||||
| ^^^^^^^^^
|
||||
|
@ -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 {}
|
||||
| ^^^^^^^^^
|
||||
|
@ -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;
|
||||
|
222
tests/ui/assigning_clones.fixed
Normal file
222
tests/ui/assigning_clones.fixed
Normal file
@ -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<T: 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<String>, 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
|
||||
}
|
||||
}
|
222
tests/ui/assigning_clones.rs
Normal file
222
tests/ui/assigning_clones.rs
Normal file
@ -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 = <HasCloneFrom as Clone>::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<T: 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<String>, 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
|
||||
}
|
||||
}
|
107
tests/ui/assigning_clones.stderr
Normal file
107
tests/ui/assigning_clones.stderr
Normal file
@ -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 = <HasCloneFrom as 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: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
|
||||
|
@ -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] {
|
||||
[..] => { }
|
||||
[..] => {},
|
||||
}
|
||||
}
|
||||
|
@ -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<C: Suite>(<C::Group as Group>::Element);
|
||||
|
||||
#[derive(PartialEq, Eq)]
|
||||
pub struct Bar<C: Suite>(i32, <C::Group as Group>::Element);
|
||||
|
||||
// issue 9319
|
||||
#[derive(PartialEq, Eq)]
|
||||
//~^ ERROR: you are deriving `PartialEq` and can implement `Eq`
|
||||
pub struct Oof<T: Fn()>(T);
|
||||
|
||||
#[derive(PartialEq, Eq)]
|
||||
pub struct Rab<T: Fn()>(T);
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
@ -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<C: Suite>(<C::Group as Group>::Element);
|
||||
|
||||
#[derive(PartialEq, Eq)]
|
||||
pub struct Bar<C: Suite>(i32, <C::Group as Group>::Element);
|
||||
|
||||
// issue 9319
|
||||
#[derive(PartialEq)]
|
||||
//~^ ERROR: you are deriving `PartialEq` and can implement `Eq`
|
||||
pub struct Oof<T: Fn()>(T);
|
||||
|
||||
#[derive(PartialEq, Eq)]
|
||||
pub struct Rab<T: Fn()>(T);
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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() {}
|
||||
|
@ -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() {}
|
||||
|
@ -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
|
||||
|
||||
|
9
tests/ui/doc/issue_9473.fixed
Normal file
9
tests/ui/doc/issue_9473.fixed
Normal file
@ -0,0 +1,9 @@
|
||||
#![warn(clippy::doc_markdown)]
|
||||
|
||||
// Should not warn!
|
||||
/// Blah blah blah <code>[FooBar]<[FooBar]></code>.
|
||||
pub struct Foo(u32);
|
||||
|
||||
// Should warn.
|
||||
/// Blah blah blah <code>[FooBar]<[FooBar]></code>[`FooBar`].
|
||||
pub struct FooBar(u32);
|
9
tests/ui/doc/issue_9473.rs
Normal file
9
tests/ui/doc/issue_9473.rs
Normal file
@ -0,0 +1,9 @@
|
||||
#![warn(clippy::doc_markdown)]
|
||||
|
||||
// Should not warn!
|
||||
/// Blah blah blah <code>[FooBar]<[FooBar]></code>.
|
||||
pub struct Foo(u32);
|
||||
|
||||
// Should warn.
|
||||
/// Blah blah blah <code>[FooBar]<[FooBar]></code>[FooBar].
|
||||
pub struct FooBar(u32);
|
15
tests/ui/doc/issue_9473.stderr
Normal file
15
tests/ui/doc/issue_9473.stderr
Normal file
@ -0,0 +1,15 @@
|
||||
error: item in documentation is missing backticks
|
||||
--> tests/ui/doc/issue_9473.rs:8:58
|
||||
|
|
||||
LL | /// Blah blah blah <code>[FooBar]<[FooBar]></code>[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 <code>[FooBar]<[FooBar]></code>[`FooBar`].
|
||||
| ~~~~~~~~
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
@ -1,3 +1,5 @@
|
||||
//@compile-flags: -Zdeduplicate-diagnostics=yes
|
||||
|
||||
#![warn(clippy::all)]
|
||||
#![warn(clippy::else_if_without_else)]
|
||||
|
||||
|
@ -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() {
|
||||
| ____________^
|
||||
|
@ -1,5 +1,7 @@
|
||||
#![allow(unused)]
|
||||
#![warn(clippy::empty_docs)]
|
||||
#![allow(clippy::mixed_attributes_style)]
|
||||
|
||||
mod outer {
|
||||
//!
|
||||
|
||||
|
@ -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 | ///
|
||||
| ^^^
|
||||
|
@ -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<u64, u64> = HashMap::new();
|
||||
if !counts.contains_key(&1) {
|
||||
counts.insert(1, 1);
|
||||
} else {
|
||||
counts.insert(1, counts.get(&1).unwrap() + 1);
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
@ -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<u64, u64> = HashMap::new();
|
||||
if !counts.contains_key(&1) {
|
||||
counts.insert(1, 1);
|
||||
} else {
|
||||
counts.insert(1, counts.get(&1).unwrap() + 1);
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
@ -6,7 +6,7 @@
|
||||
clippy::deref_addrof,
|
||||
clippy::unnecessary_mut_passed,
|
||||
dead_code,
|
||||
non_local_definitions,
|
||||
non_local_definitions
|
||||
)]
|
||||
|
||||
use core::slice;
|
||||
|
@ -6,7 +6,7 @@
|
||||
clippy::deref_addrof,
|
||||
clippy::unnecessary_mut_passed,
|
||||
dead_code,
|
||||
non_local_definitions,
|
||||
non_local_definitions
|
||||
)]
|
||||
|
||||
use core::slice;
|
||||
|
@ -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;
|
||||
|
@ -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::<bool> { 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<bool> = 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::<i32, i64> { 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<i32, i64> = 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();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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];
|
||||
| ^^^^
|
||||
|
@ -73,3 +73,5 @@ fn main() {
|
||||
#[allow(clippy::let_underscore_untyped)]
|
||||
let _ = a();
|
||||
}
|
||||
|
||||
async fn dont_lint_async_prototype(_: u8) {}
|
||||
|
@ -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<T> {
|
||||
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 };
|
||||
};
|
||||
}
|
||||
|
@ -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::<U<S<()>>> {
|
||||
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
|
||||
|
||||
|
@ -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)]
|
||||
|
@ -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
|
||||
|
||||
|
@ -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};
|
||||
|
@ -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};
|
||||
|
@ -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)`
|
||||
|
@ -1,3 +1,5 @@
|
||||
//@compile-flags: -Zdeduplicate-diagnostics=yes
|
||||
|
||||
#![allow(clippy::too_many_arguments, clippy::diverging_sub_expression)]
|
||||
#![warn(clippy::many_single_char_names)]
|
||||
|
||||
|
@ -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!();
|
||||
| ^ ^ ^ ^ ^ ^ ^ ^
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user