Auto merge of #107386 - flip1995:clippyup, r=Manishearth

Update Clippy

r? `@Manishearth`
This commit is contained in:
bors 2023-01-27 21:20:39 +00:00
commit 997fe0d57e
57 changed files with 2262 additions and 304 deletions

View file

@ -157,6 +157,11 @@ jobs:
- name: Test metadata collection
run: cargo collect-metadata
- name: Test lint_configuration.md is up-to-date
run: |
echo "run \`cargo collect-metadata\` if this fails"
git update-index --refresh
integration_build:
needs: changelog
runs-on: ubuntu-latest

View file

@ -6,11 +6,204 @@ document.
## Unreleased / Beta / In Rust Nightly
[4f142aa1...master](https://github.com/rust-lang/rust-clippy/compare/4f142aa1...master)
[d822110d...master](https://github.com/rust-lang/rust-clippy/compare/d822110d...master)
## Rust 1.67
Current stable, released 2023-01-26
[4f142aa1...d822110d](https://github.com/rust-lang/rust-clippy/compare/4f142aa1...d822110d)
### New Lints
* [`seek_from_current`]
[#9681](https://github.com/rust-lang/rust-clippy/pull/9681)
* [`from_raw_with_void_ptr`]
[#9690](https://github.com/rust-lang/rust-clippy/pull/9690)
* [`misnamed_getters`]
[#9770](https://github.com/rust-lang/rust-clippy/pull/9770)
* [`seek_to_start_instead_of_rewind`]
[#9667](https://github.com/rust-lang/rust-clippy/pull/9667)
* [`suspicious_xor_used_as_pow`]
[#9506](https://github.com/rust-lang/rust-clippy/pull/9506)
* [`unnecessary_safety_doc`]
[#9822](https://github.com/rust-lang/rust-clippy/pull/9822)
* [`unchecked_duration_subtraction`]
[#9570](https://github.com/rust-lang/rust-clippy/pull/9570)
* [`manual_is_ascii_check`]
[#9765](https://github.com/rust-lang/rust-clippy/pull/9765)
* [`unnecessary_safety_comment`]
[#9851](https://github.com/rust-lang/rust-clippy/pull/9851)
* [`let_underscore_future`]
[#9760](https://github.com/rust-lang/rust-clippy/pull/9760)
* [`manual_let_else`]
[#8437](https://github.com/rust-lang/rust-clippy/pull/8437)
### Moves and Deprecations
* Moved [`uninlined_format_args`] to `style` (Now warn-by-default)
[#9865](https://github.com/rust-lang/rust-clippy/pull/9865)
* Moved [`needless_collect`] to `nursery` (Now allow-by-default)
[#9705](https://github.com/rust-lang/rust-clippy/pull/9705)
* Moved [`or_fun_call`] to `nursery` (Now allow-by-default)
[#9829](https://github.com/rust-lang/rust-clippy/pull/9829)
* Uplifted [`let_underscore_lock`] into rustc
[#9697](https://github.com/rust-lang/rust-clippy/pull/9697)
* Uplifted [`let_underscore_drop`] into rustc
[#9697](https://github.com/rust-lang/rust-clippy/pull/9697)
* Moved [`bool_to_int_with_if`] to `pedantic` (Now allow-by-default)
[#9830](https://github.com/rust-lang/rust-clippy/pull/9830)
* Move `index_refutable_slice` to `pedantic` (Now warn-by-default)
[#9975](https://github.com/rust-lang/rust-clippy/pull/9975)
* Moved [`manual_clamp`] to `nursery` (Now allow-by-default)
[#10101](https://github.com/rust-lang/rust-clippy/pull/10101)
### Enhancements
* The scope of `#![clippy::msrv]` is now tracked correctly
[#9924](https://github.com/rust-lang/rust-clippy/pull/9924)
* `#[clippy::msrv]` can now be used as an outer attribute
[#9860](https://github.com/rust-lang/rust-clippy/pull/9860)
* Clippy will now avoid Cargo's cache, if `Cargo.toml` or `clippy.toml` have changed
[#9707](https://github.com/rust-lang/rust-clippy/pull/9707)
* [`uninlined_format_args`]: Added a new config `allow-mixed-uninlined-format-args` to allow the
lint, if only some arguments can be inlined
[#9865](https://github.com/rust-lang/rust-clippy/pull/9865)
* [`needless_lifetimes`]: Now provides suggests for individual lifetimes
[#9743](https://github.com/rust-lang/rust-clippy/pull/9743)
* [`needless_collect`]: Now detects needless `is_empty` and `contains` calls
[#8744](https://github.com/rust-lang/rust-clippy/pull/8744)
* [`blanket_clippy_restriction_lints`]: Now lints, if `clippy::restriction` is enabled via the
command line arguments
[#9755](https://github.com/rust-lang/rust-clippy/pull/9755)
* [`mutable_key_type`]: Now has the `ignore-interior-mutability` configuration, to add types which
should be ignored by the lint
[#9692](https://github.com/rust-lang/rust-clippy/pull/9692)
* [`uninlined_format_args`]: Now works for multiline `format!` expressions
[#9945](https://github.com/rust-lang/rust-clippy/pull/9945)
* [`cognitive_complexity`]: Now works for async functions
[#9828](https://github.com/rust-lang/rust-clippy/pull/9828)
[#9836](https://github.com/rust-lang/rust-clippy/pull/9836)
* [`vec_box`]: Now avoids an off-by-one error when using the `vec-box-size-threshold` configuration
[#9848](https://github.com/rust-lang/rust-clippy/pull/9848)
* [`never_loop`]: Now correctly handles breaks in nested labeled blocks
[#9858](https://github.com/rust-lang/rust-clippy/pull/9858)
[#9837](https://github.com/rust-lang/rust-clippy/pull/9837)
* [`disallowed_methods`], [`disallowed_types`], [`disallowed_macros`]: Now correctly resolve
paths, if a crate is used multiple times with different versions
[#9800](https://github.com/rust-lang/rust-clippy/pull/9800)
* [`disallowed_methods`]: Can now be used for local methods
[#9800](https://github.com/rust-lang/rust-clippy/pull/9800)
* [`print_stdout`], [`print_stderr`]: Can now be enabled in test with the `allow-print-in-tests`
config value
[#9797](https://github.com/rust-lang/rust-clippy/pull/9797)
* [`from_raw_with_void_ptr`]: Now works for `Rc`, `Arc`, `alloc::rc::Weak` and
`alloc::sync::Weak` types.
[#9700](https://github.com/rust-lang/rust-clippy/pull/9700)
* [`needless_borrowed_reference`]: Now works for struct and tuple patterns with wildcards
[#9855](https://github.com/rust-lang/rust-clippy/pull/9855)
* [`or_fun_call`]: Now supports `map_or` methods
[#9689](https://github.com/rust-lang/rust-clippy/pull/9689)
* [`unwrap_used`], [`expect_used`]: No longer lints in test code
[#9686](https://github.com/rust-lang/rust-clippy/pull/9686)
* [`fn_params_excessive_bools`]: Is now emitted with the lint level at the linted function
[#9698](https://github.com/rust-lang/rust-clippy/pull/9698)
### False Positive Fixes
* [`new_ret_no_self`]: No longer lints when `impl Trait<Self>` is returned
[#9733](https://github.com/rust-lang/rust-clippy/pull/9733)
* [`unnecessary_lazy_evaluations`]: No longer lints, if the type has a significant drop
[#9750](https://github.com/rust-lang/rust-clippy/pull/9750)
* [`option_if_let_else`]: No longer lints, if any arm has guard
[#9747](https://github.com/rust-lang/rust-clippy/pull/9747)
* [`explicit_auto_deref`]: No longer lints, if the target type is a projection with generic
arguments
[#9813](https://github.com/rust-lang/rust-clippy/pull/9813)
* [`unnecessary_to_owned`]: No longer lints, if the suggestion effects types
[#9796](https://github.com/rust-lang/rust-clippy/pull/9796)
* [`needless_borrow`]: No longer lints, if the suggestion is affected by `Deref`
[#9674](https://github.com/rust-lang/rust-clippy/pull/9674)
* [`unused_unit`]: No longer lints, if lifetimes are bound to the return type
[#9849](https://github.com/rust-lang/rust-clippy/pull/9849)
* [`mut_mut`]: No longer lints cases with unsized mutable references
[#9835](https://github.com/rust-lang/rust-clippy/pull/9835)
* [`bool_to_int_with_if`]: No longer lints in const context
[#9738](https://github.com/rust-lang/rust-clippy/pull/9738)
* [`use_self`]: No longer lints in macros
[#9704](https://github.com/rust-lang/rust-clippy/pull/9704)
* [`unnecessary_operation`]: No longer lints, if multiple macros are involved
[#9981](https://github.com/rust-lang/rust-clippy/pull/9981)
* [`allow_attributes_without_reason`]: No longer lints inside external macros
[#9630](https://github.com/rust-lang/rust-clippy/pull/9630)
* [`question_mark`]: No longer lints for `if let Err()` with an `else` branch
[#9722](https://github.com/rust-lang/rust-clippy/pull/9722)
* [`unnecessary_cast`]: No longer lints if the identifier and cast originate from different macros
[#9980](https://github.com/rust-lang/rust-clippy/pull/9980)
* [`arithmetic_side_effects`]: Now detects operations with associated constants
[#9592](https://github.com/rust-lang/rust-clippy/pull/9592)
* [`explicit_auto_deref`]: No longer lints, if the initial value is not a reference or reference
receiver
[#9997](https://github.com/rust-lang/rust-clippy/pull/9997)
* [`module_name_repetitions`], [`single_component_path_imports`]: Now handle `#[allow]`
attributes correctly
[#9879](https://github.com/rust-lang/rust-clippy/pull/9879)
* [`bool_to_int_with_if`]: No longer lints `if let` statements
[#9714](https://github.com/rust-lang/rust-clippy/pull/9714)
* [`needless_borrow`]: No longer lints, `if`-`else`-statements that require the borrow
[#9791](https://github.com/rust-lang/rust-clippy/pull/9791)
* [`needless_borrow`]: No longer lints borrows, if moves were illegal
[#9711](https://github.com/rust-lang/rust-clippy/pull/9711)
* [`manual_swap`]: No longer lints in const context
[#9871](https://github.com/rust-lang/rust-clippy/pull/9871)
### Suggestion Fixes/Improvements
* [`missing_safety_doc`], [`missing_errors_doc`], [`missing_panics_doc`]: No longer show the
entire item in the lint emission.
[#9772](https://github.com/rust-lang/rust-clippy/pull/9772)
* [`needless_lifetimes`]: Only suggests `'_` when it's applicable
[#9743](https://github.com/rust-lang/rust-clippy/pull/9743)
* [`use_self`]: Now suggests full paths correctly
[#9726](https://github.com/rust-lang/rust-clippy/pull/9726)
* [`redundant_closure_call`]: Now correctly deals with macros during suggestion creation
[#9987](https://github.com/rust-lang/rust-clippy/pull/9987)
* [`unnecessary_cast`]: Suggestions now correctly deal with references
[#9996](https://github.com/rust-lang/rust-clippy/pull/9996)
* [`unnecessary_join`]: Suggestions now correctly use [turbofish] operators
[#9779](https://github.com/rust-lang/rust-clippy/pull/9779)
* [`equatable_if_let`]: Can now suggest `matches!` replacements
[#9368](https://github.com/rust-lang/rust-clippy/pull/9368)
* [`string_extend_chars`]: Suggestions now correctly work for `str` slices
[#9741](https://github.com/rust-lang/rust-clippy/pull/9741)
* [`redundant_closure_for_method_calls`]: Suggestions now include angle brackets and generic
arguments if needed
[#9745](https://github.com/rust-lang/rust-clippy/pull/9745)
* [`manual_let_else`]: Suggestions no longer expand macro calls
[#9943](https://github.com/rust-lang/rust-clippy/pull/9943)
* [`infallible_destructuring_match`]: Suggestions now preserve references
[#9850](https://github.com/rust-lang/rust-clippy/pull/9850)
* [`result_large_err`]: The error now shows the largest enum variant
[#9662](https://github.com/rust-lang/rust-clippy/pull/9662)
* [`needless_return`]: Suggestions are now formatted better
[#9967](https://github.com/rust-lang/rust-clippy/pull/9967)
* [`unused_rounding`]: The suggestion now preserves the original float literal notation
[#9870](https://github.com/rust-lang/rust-clippy/pull/9870)
[turbofish]: https://turbo.fish/::%3CClippy%3E
### ICE Fixes
* [`result_large_err`]: Fixed ICE for empty enums
[#10007](https://github.com/rust-lang/rust-clippy/pull/10007)
* [`redundant_allocation`]: Fixed ICE for types with bounded variables
[#9773](https://github.com/rust-lang/rust-clippy/pull/9773)
* [`unused_rounding`]: Fixed ICE, if `_` was used as a separator
[#10001](https://github.com/rust-lang/rust-clippy/pull/10001)
## Rust 1.66
Current stable, released 2022-12-15
Released 2022-12-15
[b52fb523...4f142aa1](https://github.com/rust-lang/rust-clippy/compare/b52fb523...4f142aa1)
@ -166,6 +359,7 @@ Current stable, released 2022-12-15
* [`unnecessary_to_owned`]: Avoid ICEs in favor of false negatives if information is missing
[#9505](https://github.com/rust-lang/rust-clippy/pull/9505)
[#10027](https://github.com/rust-lang/rust-clippy/pull/10027)
* [`manual_range_contains`]: No longer ICEs on values behind references
[#9627](https://github.com/rust-lang/rust-clippy/pull/9627)
* [`needless_pass_by_value`]: No longer ICEs on unsized `dyn Fn` arguments
@ -4383,6 +4577,7 @@ Released 2018-09-13
[`multi_assignments`]: https://rust-lang.github.io/rust-clippy/master/index.html#multi_assignments
[`multiple_crate_versions`]: https://rust-lang.github.io/rust-clippy/master/index.html#multiple_crate_versions
[`multiple_inherent_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#multiple_inherent_impl
[`multiple_unsafe_ops_per_block`]: https://rust-lang.github.io/rust-clippy/master/index.html#multiple_unsafe_ops_per_block
[`must_use_candidate`]: https://rust-lang.github.io/rust-clippy/master/index.html#must_use_candidate
[`must_use_unit`]: https://rust-lang.github.io/rust-clippy/master/index.html#must_use_unit
[`mut_from_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#mut_from_ref

View file

@ -1,6 +1,6 @@
[package]
name = "clippy"
version = "0.1.68"
version = "0.1.69"
description = "A bunch of helpful lints to avoid common pitfalls in Rust"
repository = "https://github.com/rust-lang/rust-clippy"
readme = "README.md"

View file

@ -194,11 +194,21 @@ value` mapping e.g.
```toml
avoid-breaking-exported-api = false
disallowed-names = ["toto", "tata", "titi"]
cognitive-complexity-threshold = 30
```
See the [list of configurable lints](https://rust-lang.github.io/rust-clippy/master/index.html#Configuration),
the lint descriptions contain the names and meanings of these configuration variables.
The [table of configurations](https://doc.rust-lang.org/nightly/clippy/lint_configuration.html)
contains all config values, their default, and a list of lints they affect.
Each [configurable lint](https://rust-lang.github.io/rust-clippy/master/index.html#Configuration)
, also contains information about these values.
For configurations that are a list type with default values such as
[disallowed-names](https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_names),
you can use the unique value `".."` to extend the default values instead of replacing them.
```toml
# default of disallowed-names is ["foo", "baz", "quux"]
disallowed-names = ["bar", ".."] # -> ["bar", "foo", "baz", "quux"]
```
> **Note**
>

View file

@ -5,6 +5,7 @@
- [Installation](installation.md)
- [Usage](usage.md)
- [Configuration](configuration.md)
- [Lint Configuration](lint_configuration.md)
- [Clippy's Lints](lints.md)
- [Continuous Integration](continuous_integration/README.md)
- [GitHub Actions](continuous_integration/github_actions.md)

View file

@ -8,11 +8,21 @@ basic `variable = value` mapping eg.
```toml
avoid-breaking-exported-api = false
disallowed-names = ["toto", "tata", "titi"]
cognitive-complexity-threshold = 30
```
See the [list of configurable lints](https://rust-lang.github.io/rust-clippy/master/index.html#Configuration),
the lint descriptions contain the names and meanings of these configuration variables.
The [table of configurations](./lint_configuration.md)
contains all config values, their default, and a list of lints they affect.
Each [configurable lint](https://rust-lang.github.io/rust-clippy/master/index.html#Configuration)
, also contains information about these values.
For configurations that are a list type with default values such as
[disallowed-names](https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_names),
you can use the unique value `".."` to extend the default values instead of replacing them.
```toml
# default of disallowed-names is ["foo", "baz", "quux"]
disallowed-names = ["bar", ".."] # -> ["bar", "foo", "baz", "quux"]
```
To deactivate the "for further information visit *lint-link*" message you can define the `CLIPPY_DISABLE_DOCS_LINKS`
environment variable.

View file

@ -146,7 +146,8 @@ For cargo lints, the process of testing differs in that we are interested in the
manifest.
If our new lint is named e.g. `foo_categories`, after running `cargo dev
new_lint` we will find by default two new crates, each with its manifest file:
new_lint --name=foo_categories --type=cargo --category=cargo` we will find by
default two new crates, each with its manifest file:
* `tests/ui-cargo/foo_categories/fail/Cargo.toml`: this file should cause the
new lint to raise an error.
@ -699,6 +700,10 @@ for some users. Adding a configuration is done in the following steps:
`clippy.toml` file with the configuration value and a rust file that
should be linted by Clippy. The test can otherwise be written as usual.
5. Update [Lint Configuration](../lint_configuration.md)
Run `cargo collect-metadata` to generate documentation changes for the book.
[`clippy_lints::utils::conf`]: https://github.com/rust-lang/rust-clippy/blob/master/clippy_lints/src/utils/conf.rs
[`clippy_lints` lib file]: https://github.com/rust-lang/rust-clippy/blob/master/clippy_lints/src/lib.rs
[`tests/ui`]: https://github.com/rust-lang/rust-clippy/blob/master/tests/ui

View file

@ -3,15 +3,15 @@
This document explains how to make additions and changes to the Clippy book, the
guide to Clippy that you're reading right now. The Clippy book is formatted with
[Markdown](https://www.markdownguide.org) and generated by
[mdbook](https://github.com/rust-lang/mdBook).
[mdBook](https://github.com/rust-lang/mdBook).
- [Get mdbook](#get-mdbook)
- [Get mdBook](#get-mdbook)
- [Make changes](#make-changes)
## Get mdbook
## Get mdBook
While not strictly necessary since the book source is simply Markdown text
files, having mdbook locally will allow you to build, test and serve the book
files, having mdBook locally will allow you to build, test and serve the book
locally to view changes before you commit them to the repository. You likely
already have `cargo` installed, so the easiest option is to simply:
@ -19,7 +19,7 @@ already have `cargo` installed, so the easiest option is to simply:
cargo install mdbook
```
See the mdbook [installation](https://github.com/rust-lang/mdBook#installation)
See the mdBook [installation](https://github.com/rust-lang/mdBook#installation)
instructions for other options.
## Make changes
@ -27,7 +27,7 @@ instructions for other options.
The book's
[src](https://github.com/rust-lang/rust-clippy/tree/master/book/src)
directory contains all of the markdown files used to generate the book. If you
want to see your changes in real time, you can use the mdbook `serve` command to
want to see your changes in real time, you can use the mdBook `serve` command to
run a web server locally that will automatically update changes as they are
made. From the top level of your `rust-clippy` directory:
@ -38,5 +38,5 @@ mdbook serve book --open
Then navigate to `http://localhost:3000` to see the generated book. While the
server is running, changes you make will automatically be updated.
For more information, see the mdbook
For more information, see the mdBook
[guide](https://rust-lang.github.io/mdBook/).

View file

@ -95,11 +95,23 @@ As section headers, we use:
Please also be sure to update the Beta/Unreleased sections at the top with the
relevant commit ranges.
If you have the time, it would be appreciated if you double-check, that the
`#[clippy::version]` attributes for the added lints contains the correct version.
#### 3.1 Include `beta-accepted` PRs
Look for the [`beta-accepted`] label and make sure to also include the PRs with
that label in the changelog. If you can, remove the `beta-accepted` labels
**after** the changelog PR was merged.
> _Note:_ Some of those PRs might even got backported to the previous `beta`.
> Those have to be included in the changelog of the _previous_ release.
### 4. Update `clippy::version` attributes
Next, make sure to check that the `#[clippy::version]` attributes for the added
lints contain the correct version.
[changelog]: https://github.com/rust-lang/rust-clippy/blob/master/CHANGELOG.md
[forge]: https://forge.rust-lang.org/
[rust_master_tools]: https://github.com/rust-lang/rust/tree/master/src/tools/clippy
[rust_beta_tools]: https://github.com/rust-lang/rust/tree/beta/src/tools/clippy
[rust_stable_tools]: https://github.com/rust-lang/rust/releases
[`beta-accepted`]: https://github.com/rust-lang/rust-clippy/issues?q=label%3Abeta-accepted+

View file

@ -0,0 +1,523 @@
<!--
This file is generated by `cargo collect-metadata`.
Please use that command to update the file and do not edit it by hand.
-->
## Lint Configuration Options
| <div style="width:290px">Option</div> | Default Value |
|--|--|
| [arithmetic-side-effects-allowed](#arithmetic-side-effects-allowed) | `{}` |
| [arithmetic-side-effects-allowed-binary](#arithmetic-side-effects-allowed-binary) | `[]` |
| [arithmetic-side-effects-allowed-unary](#arithmetic-side-effects-allowed-unary) | `{}` |
| [avoid-breaking-exported-api](#avoid-breaking-exported-api) | `true` |
| [msrv](#msrv) | `None` |
| [cognitive-complexity-threshold](#cognitive-complexity-threshold) | `25` |
| [disallowed-names](#disallowed-names) | `["foo", "baz", "quux"]` |
| [doc-valid-idents](#doc-valid-idents) | `["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "DirectX", "ECMAScript", "GPLv2", "GPLv3", "GitHub", "GitLab", "IPv4", "IPv6", "ClojureScript", "CoffeeScript", "JavaScript", "PureScript", "TypeScript", "NaN", "NaNs", "OAuth", "GraphQL", "OCaml", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenDNS", "WebGL", "TensorFlow", "TrueType", "iOS", "macOS", "FreeBSD", "TeX", "LaTeX", "BibTeX", "BibLaTeX", "MinGW", "CamelCase"]` |
| [too-many-arguments-threshold](#too-many-arguments-threshold) | `7` |
| [type-complexity-threshold](#type-complexity-threshold) | `250` |
| [single-char-binding-names-threshold](#single-char-binding-names-threshold) | `4` |
| [too-large-for-stack](#too-large-for-stack) | `200` |
| [enum-variant-name-threshold](#enum-variant-name-threshold) | `3` |
| [enum-variant-size-threshold](#enum-variant-size-threshold) | `200` |
| [verbose-bit-mask-threshold](#verbose-bit-mask-threshold) | `1` |
| [literal-representation-threshold](#literal-representation-threshold) | `16384` |
| [trivial-copy-size-limit](#trivial-copy-size-limit) | `None` |
| [pass-by-value-size-limit](#pass-by-value-size-limit) | `256` |
| [too-many-lines-threshold](#too-many-lines-threshold) | `100` |
| [array-size-threshold](#array-size-threshold) | `512000` |
| [vec-box-size-threshold](#vec-box-size-threshold) | `4096` |
| [max-trait-bounds](#max-trait-bounds) | `3` |
| [max-struct-bools](#max-struct-bools) | `3` |
| [max-fn-params-bools](#max-fn-params-bools) | `3` |
| [warn-on-all-wildcard-imports](#warn-on-all-wildcard-imports) | `false` |
| [disallowed-macros](#disallowed-macros) | `[]` |
| [disallowed-methods](#disallowed-methods) | `[]` |
| [disallowed-types](#disallowed-types) | `[]` |
| [unreadable-literal-lint-fractions](#unreadable-literal-lint-fractions) | `true` |
| [upper-case-acronyms-aggressive](#upper-case-acronyms-aggressive) | `false` |
| [matches-for-let-else](#matches-for-let-else) | `WellKnownTypes` |
| [cargo-ignore-publish](#cargo-ignore-publish) | `false` |
| [standard-macro-braces](#standard-macro-braces) | `[]` |
| [enforced-import-renames](#enforced-import-renames) | `[]` |
| [allowed-scripts](#allowed-scripts) | `["Latin"]` |
| [enable-raw-pointer-heuristic-for-send](#enable-raw-pointer-heuristic-for-send) | `true` |
| [max-suggested-slice-pattern-length](#max-suggested-slice-pattern-length) | `3` |
| [max-include-file-size](#max-include-file-size) | `1000000` |
| [allow-expect-in-tests](#allow-expect-in-tests) | `false` |
| [allow-unwrap-in-tests](#allow-unwrap-in-tests) | `false` |
| [allow-dbg-in-tests](#allow-dbg-in-tests) | `false` |
| [allow-print-in-tests](#allow-print-in-tests) | `false` |
| [large-error-threshold](#large-error-threshold) | `128` |
| [ignore-interior-mutability](#ignore-interior-mutability) | `["bytes::Bytes"]` |
| [allow-mixed-uninlined-format-args](#allow-mixed-uninlined-format-args) | `true` |
| [suppress-restriction-lint-in-const](#suppress-restriction-lint-in-const) | `false` |
### arithmetic-side-effects-allowed
Suppress checking of the passed type names in all types of operations.
If a specific operation is desired, consider using `arithmetic_side_effects_allowed_binary` or `arithmetic_side_effects_allowed_unary` instead.
#### Example
```toml
arithmetic-side-effects-allowed = ["SomeType", "AnotherType"]
```
#### Noteworthy
A type, say `SomeType`, listed in this configuration has the same behavior of
`["SomeType" , "*"], ["*", "SomeType"]` in `arithmetic_side_effects_allowed_binary`.
**Default Value:** `{}` (`rustc_data_structures::fx::FxHashSet<String>`)
* [arithmetic_side_effects](https://rust-lang.github.io/rust-clippy/master/index.html#arithmetic_side_effects)
### arithmetic-side-effects-allowed-binary
Suppress checking of the passed type pair names in binary operations like addition or
multiplication.
Supports the "*" wildcard to indicate that a certain type won't trigger the lint regardless
of the involved counterpart. For example, `["SomeType", "*"]` or `["*", "AnotherType"]`.
Pairs are asymmetric, which means that `["SomeType", "AnotherType"]` is not the same as
`["AnotherType", "SomeType"]`.
#### Example
```toml
arithmetic-side-effects-allowed-binary = [["SomeType" , "f32"], ["AnotherType", "*"]]
```
**Default Value:** `[]` (`Vec<[String; 2]>`)
* [arithmetic_side_effects](https://rust-lang.github.io/rust-clippy/master/index.html#arithmetic_side_effects)
### arithmetic-side-effects-allowed-unary
Suppress checking of the passed type names in unary operations like "negation" (`-`).
#### Example
```toml
arithmetic-side-effects-allowed-unary = ["SomeType", "AnotherType"]
```
**Default Value:** `{}` (`rustc_data_structures::fx::FxHashSet<String>`)
* [arithmetic_side_effects](https://rust-lang.github.io/rust-clippy/master/index.html#arithmetic_side_effects)
### avoid-breaking-exported-api
Suppress lints whenever the suggested change would cause breakage for other crates.
**Default Value:** `true` (`bool`)
* [enum_variant_names](https://rust-lang.github.io/rust-clippy/master/index.html#enum_variant_names)
* [large_types_passed_by_value](https://rust-lang.github.io/rust-clippy/master/index.html#large_types_passed_by_value)
* [trivially_copy_pass_by_ref](https://rust-lang.github.io/rust-clippy/master/index.html#trivially_copy_pass_by_ref)
* [unnecessary_wraps](https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_wraps)
* [unused_self](https://rust-lang.github.io/rust-clippy/master/index.html#unused_self)
* [upper_case_acronyms](https://rust-lang.github.io/rust-clippy/master/index.html#upper_case_acronyms)
* [wrong_self_convention](https://rust-lang.github.io/rust-clippy/master/index.html#wrong_self_convention)
* [box_collection](https://rust-lang.github.io/rust-clippy/master/index.html#box_collection)
* [redundant_allocation](https://rust-lang.github.io/rust-clippy/master/index.html#redundant_allocation)
* [rc_buffer](https://rust-lang.github.io/rust-clippy/master/index.html#rc_buffer)
* [vec_box](https://rust-lang.github.io/rust-clippy/master/index.html#vec_box)
* [option_option](https://rust-lang.github.io/rust-clippy/master/index.html#option_option)
* [linkedlist](https://rust-lang.github.io/rust-clippy/master/index.html#linkedlist)
* [rc_mutex](https://rust-lang.github.io/rust-clippy/master/index.html#rc_mutex)
### msrv
The minimum rust version that the project supports
**Default Value:** `None` (`Option<String>`)
* [manual_split_once](https://rust-lang.github.io/rust-clippy/master/index.html#manual_split_once)
* [manual_str_repeat](https://rust-lang.github.io/rust-clippy/master/index.html#manual_str_repeat)
* [cloned_instead_of_copied](https://rust-lang.github.io/rust-clippy/master/index.html#cloned_instead_of_copied)
* [redundant_field_names](https://rust-lang.github.io/rust-clippy/master/index.html#redundant_field_names)
* [redundant_static_lifetimes](https://rust-lang.github.io/rust-clippy/master/index.html#redundant_static_lifetimes)
* [filter_map_next](https://rust-lang.github.io/rust-clippy/master/index.html#filter_map_next)
* [checked_conversions](https://rust-lang.github.io/rust-clippy/master/index.html#checked_conversions)
* [manual_range_contains](https://rust-lang.github.io/rust-clippy/master/index.html#manual_range_contains)
* [use_self](https://rust-lang.github.io/rust-clippy/master/index.html#use_self)
* [mem_replace_with_default](https://rust-lang.github.io/rust-clippy/master/index.html#mem_replace_with_default)
* [manual_non_exhaustive](https://rust-lang.github.io/rust-clippy/master/index.html#manual_non_exhaustive)
* [option_as_ref_deref](https://rust-lang.github.io/rust-clippy/master/index.html#option_as_ref_deref)
* [map_unwrap_or](https://rust-lang.github.io/rust-clippy/master/index.html#map_unwrap_or)
* [match_like_matches_macro](https://rust-lang.github.io/rust-clippy/master/index.html#match_like_matches_macro)
* [manual_strip](https://rust-lang.github.io/rust-clippy/master/index.html#manual_strip)
* [missing_const_for_fn](https://rust-lang.github.io/rust-clippy/master/index.html#missing_const_for_fn)
* [unnested_or_patterns](https://rust-lang.github.io/rust-clippy/master/index.html#unnested_or_patterns)
* [from_over_into](https://rust-lang.github.io/rust-clippy/master/index.html#from_over_into)
* [ptr_as_ptr](https://rust-lang.github.io/rust-clippy/master/index.html#ptr_as_ptr)
* [if_then_some_else_none](https://rust-lang.github.io/rust-clippy/master/index.html#if_then_some_else_none)
* [approx_constant](https://rust-lang.github.io/rust-clippy/master/index.html#approx_constant)
* [deprecated_cfg_attr](https://rust-lang.github.io/rust-clippy/master/index.html#deprecated_cfg_attr)
* [index_refutable_slice](https://rust-lang.github.io/rust-clippy/master/index.html#index_refutable_slice)
* [map_clone](https://rust-lang.github.io/rust-clippy/master/index.html#map_clone)
* [borrow_as_ptr](https://rust-lang.github.io/rust-clippy/master/index.html#borrow_as_ptr)
* [manual_bits](https://rust-lang.github.io/rust-clippy/master/index.html#manual_bits)
* [err_expect](https://rust-lang.github.io/rust-clippy/master/index.html#err_expect)
* [cast_abs_to_unsigned](https://rust-lang.github.io/rust-clippy/master/index.html#cast_abs_to_unsigned)
* [uninlined_format_args](https://rust-lang.github.io/rust-clippy/master/index.html#uninlined_format_args)
* [manual_clamp](https://rust-lang.github.io/rust-clippy/master/index.html#manual_clamp)
* [manual_let_else](https://rust-lang.github.io/rust-clippy/master/index.html#manual_let_else)
* [unchecked_duration_subtraction](https://rust-lang.github.io/rust-clippy/master/index.html#unchecked_duration_subtraction)
### cognitive-complexity-threshold
The maximum cognitive complexity a function can have
**Default Value:** `25` (`u64`)
* [cognitive_complexity](https://rust-lang.github.io/rust-clippy/master/index.html#cognitive_complexity)
### disallowed-names
The list of disallowed names to lint about. NB: `bar` is not here since it has legitimate uses. The value
`".."` can be used as part of the list to indicate, that the configured values should be appended to the
default configuration of Clippy. By default any configuration will replace the default value.
**Default Value:** `["foo", "baz", "quux"]` (`Vec<String>`)
* [disallowed_names](https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_names)
### doc-valid-idents
The list of words this lint should not consider as identifiers needing ticks. The value
`".."` can be used as part of the list to indicate, that the configured values should be appended to the
default configuration of Clippy. By default any configuraction will replace the default value. For example:
* `doc-valid-idents = ["ClipPy"]` would replace the default list with `["ClipPy"]`.
* `doc-valid-idents = ["ClipPy", ".."]` would append `ClipPy` to the default list.
Default list:
**Default Value:** `["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "DirectX", "ECMAScript", "GPLv2", "GPLv3", "GitHub", "GitLab", "IPv4", "IPv6", "ClojureScript", "CoffeeScript", "JavaScript", "PureScript", "TypeScript", "NaN", "NaNs", "OAuth", "GraphQL", "OCaml", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenDNS", "WebGL", "TensorFlow", "TrueType", "iOS", "macOS", "FreeBSD", "TeX", "LaTeX", "BibTeX", "BibLaTeX", "MinGW", "CamelCase"]` (`Vec<String>`)
* [doc_markdown](https://rust-lang.github.io/rust-clippy/master/index.html#doc_markdown)
### too-many-arguments-threshold
The maximum number of argument a function or method can have
**Default Value:** `7` (`u64`)
* [too_many_arguments](https://rust-lang.github.io/rust-clippy/master/index.html#too_many_arguments)
### type-complexity-threshold
The maximum complexity a type can have
**Default Value:** `250` (`u64`)
* [type_complexity](https://rust-lang.github.io/rust-clippy/master/index.html#type_complexity)
### single-char-binding-names-threshold
The maximum number of single char bindings a scope may have
**Default Value:** `4` (`u64`)
* [many_single_char_names](https://rust-lang.github.io/rust-clippy/master/index.html#many_single_char_names)
### too-large-for-stack
The maximum size of objects (in bytes) that will be linted. Larger objects are ok on the heap
**Default Value:** `200` (`u64`)
* [boxed_local](https://rust-lang.github.io/rust-clippy/master/index.html#boxed_local)
* [useless_vec](https://rust-lang.github.io/rust-clippy/master/index.html#useless_vec)
### enum-variant-name-threshold
The minimum number of enum variants for the lints about variant names to trigger
**Default Value:** `3` (`u64`)
* [enum_variant_names](https://rust-lang.github.io/rust-clippy/master/index.html#enum_variant_names)
### enum-variant-size-threshold
The maximum size of an enum's variant to avoid box suggestion
**Default Value:** `200` (`u64`)
* [large_enum_variant](https://rust-lang.github.io/rust-clippy/master/index.html#large_enum_variant)
### verbose-bit-mask-threshold
The maximum allowed size of a bit mask before suggesting to use 'trailing_zeros'
**Default Value:** `1` (`u64`)
* [verbose_bit_mask](https://rust-lang.github.io/rust-clippy/master/index.html#verbose_bit_mask)
### literal-representation-threshold
The lower bound for linting decimal literals
**Default Value:** `16384` (`u64`)
* [decimal_literal_representation](https://rust-lang.github.io/rust-clippy/master/index.html#decimal_literal_representation)
### trivial-copy-size-limit
The maximum size (in bytes) to consider a `Copy` type for passing by value instead of by reference.
**Default Value:** `None` (`Option<u64>`)
* [trivially_copy_pass_by_ref](https://rust-lang.github.io/rust-clippy/master/index.html#trivially_copy_pass_by_ref)
### pass-by-value-size-limit
The minimum size (in bytes) to consider a type for passing by reference instead of by value.
**Default Value:** `256` (`u64`)
* [large_type_pass_by_move](https://rust-lang.github.io/rust-clippy/master/index.html#large_type_pass_by_move)
### too-many-lines-threshold
The maximum number of lines a function or method can have
**Default Value:** `100` (`u64`)
* [too_many_lines](https://rust-lang.github.io/rust-clippy/master/index.html#too_many_lines)
### array-size-threshold
The maximum allowed size for arrays on the stack
**Default Value:** `512000` (`u128`)
* [large_stack_arrays](https://rust-lang.github.io/rust-clippy/master/index.html#large_stack_arrays)
* [large_const_arrays](https://rust-lang.github.io/rust-clippy/master/index.html#large_const_arrays)
### vec-box-size-threshold
The size of the boxed type in bytes, where boxing in a `Vec` is allowed
**Default Value:** `4096` (`u64`)
* [vec_box](https://rust-lang.github.io/rust-clippy/master/index.html#vec_box)
### max-trait-bounds
The maximum number of bounds a trait can have to be linted
**Default Value:** `3` (`u64`)
* [type_repetition_in_bounds](https://rust-lang.github.io/rust-clippy/master/index.html#type_repetition_in_bounds)
### max-struct-bools
The maximum number of bool fields a struct can have
**Default Value:** `3` (`u64`)
* [struct_excessive_bools](https://rust-lang.github.io/rust-clippy/master/index.html#struct_excessive_bools)
### max-fn-params-bools
The maximum number of bool parameters a function can have
**Default Value:** `3` (`u64`)
* [fn_params_excessive_bools](https://rust-lang.github.io/rust-clippy/master/index.html#fn_params_excessive_bools)
### warn-on-all-wildcard-imports
Whether to allow certain wildcard imports (prelude, super in tests).
**Default Value:** `false` (`bool`)
* [wildcard_imports](https://rust-lang.github.io/rust-clippy/master/index.html#wildcard_imports)
### disallowed-macros
The list of disallowed macros, written as fully qualified paths.
**Default Value:** `[]` (`Vec<crate::utils::conf::DisallowedPath>`)
* [disallowed_macros](https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_macros)
### disallowed-methods
The list of disallowed methods, written as fully qualified paths.
**Default Value:** `[]` (`Vec<crate::utils::conf::DisallowedPath>`)
* [disallowed_methods](https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_methods)
### disallowed-types
The list of disallowed types, written as fully qualified paths.
**Default Value:** `[]` (`Vec<crate::utils::conf::DisallowedPath>`)
* [disallowed_types](https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_types)
### unreadable-literal-lint-fractions
Should the fraction of a decimal be linted to include separators.
**Default Value:** `true` (`bool`)
* [unreadable_literal](https://rust-lang.github.io/rust-clippy/master/index.html#unreadable_literal)
### upper-case-acronyms-aggressive
Enables verbose mode. Triggers if there is more than one uppercase char next to each other
**Default Value:** `false` (`bool`)
* [upper_case_acronyms](https://rust-lang.github.io/rust-clippy/master/index.html#upper_case_acronyms)
### matches-for-let-else
Whether the matches should be considered by the lint, and whether there should
be filtering for common types.
**Default Value:** `WellKnownTypes` (`crate::manual_let_else::MatchLintBehaviour`)
* [manual_let_else](https://rust-lang.github.io/rust-clippy/master/index.html#manual_let_else)
### cargo-ignore-publish
For internal testing only, ignores the current `publish` settings in the Cargo manifest.
**Default Value:** `false` (`bool`)
* [_cargo_common_metadata](https://rust-lang.github.io/rust-clippy/master/index.html#_cargo_common_metadata)
### standard-macro-braces
Enforce the named macros always use the braces specified.
A `MacroMatcher` can be added like so `{ name = "macro_name", brace = "(" }`. If the macro
is could be used with a full path two `MacroMatcher`s have to be added one with the full path
`crate_name::macro_name` and one with just the macro name.
**Default Value:** `[]` (`Vec<crate::nonstandard_macro_braces::MacroMatcher>`)
* [nonstandard_macro_braces](https://rust-lang.github.io/rust-clippy/master/index.html#nonstandard_macro_braces)
### enforced-import-renames
The list of imports to always rename, a fully qualified path followed by the rename.
**Default Value:** `[]` (`Vec<crate::utils::conf::Rename>`)
* [missing_enforced_import_renames](https://rust-lang.github.io/rust-clippy/master/index.html#missing_enforced_import_renames)
### allowed-scripts
The list of unicode scripts allowed to be used in the scope.
**Default Value:** `["Latin"]` (`Vec<String>`)
* [disallowed_script_idents](https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_script_idents)
### enable-raw-pointer-heuristic-for-send
Whether to apply the raw pointer heuristic to determine if a type is `Send`.
**Default Value:** `true` (`bool`)
* [non_send_fields_in_send_ty](https://rust-lang.github.io/rust-clippy/master/index.html#non_send_fields_in_send_ty)
### max-suggested-slice-pattern-length
When Clippy suggests using a slice pattern, this is the maximum number of elements allowed in
the slice pattern that is suggested. If more elements would be necessary, the lint is suppressed.
For example, `[_, _, _, e, ..]` is a slice pattern with 4 elements.
**Default Value:** `3` (`u64`)
* [index_refutable_slice](https://rust-lang.github.io/rust-clippy/master/index.html#index_refutable_slice)
### max-include-file-size
The maximum size of a file included via `include_bytes!()` or `include_str!()`, in bytes
**Default Value:** `1000000` (`u64`)
* [large_include_file](https://rust-lang.github.io/rust-clippy/master/index.html#large_include_file)
### allow-expect-in-tests
Whether `expect` should be allowed within `#[cfg(test)]`
**Default Value:** `false` (`bool`)
* [expect_used](https://rust-lang.github.io/rust-clippy/master/index.html#expect_used)
### allow-unwrap-in-tests
Whether `unwrap` should be allowed in test cfg
**Default Value:** `false` (`bool`)
* [unwrap_used](https://rust-lang.github.io/rust-clippy/master/index.html#unwrap_used)
### allow-dbg-in-tests
Whether `dbg!` should be allowed in test functions
**Default Value:** `false` (`bool`)
* [dbg_macro](https://rust-lang.github.io/rust-clippy/master/index.html#dbg_macro)
### allow-print-in-tests
Whether print macros (ex. `println!`) should be allowed in test functions
**Default Value:** `false` (`bool`)
* [print_stdout](https://rust-lang.github.io/rust-clippy/master/index.html#print_stdout)
* [print_stderr](https://rust-lang.github.io/rust-clippy/master/index.html#print_stderr)
### large-error-threshold
The maximum size of the `Err`-variant in a `Result` returned from a function
**Default Value:** `128` (`u64`)
* [result_large_err](https://rust-lang.github.io/rust-clippy/master/index.html#result_large_err)
### ignore-interior-mutability
A list of paths to types that should be treated like `Arc`, i.e. ignored but
for the generic parameters for determining interior mutability
**Default Value:** `["bytes::Bytes"]` (`Vec<String>`)
* [mutable_key](https://rust-lang.github.io/rust-clippy/master/index.html#mutable_key)
### allow-mixed-uninlined-format-args
Whether to allow mixed uninlined format args, e.g. `format!("{} {}", a, foo.bar)`
**Default Value:** `true` (`bool`)
* [uninlined_format_args](https://rust-lang.github.io/rust-clippy/master/index.html#uninlined_format_args)
### suppress-restriction-lint-in-const
In same
cases the restructured operation might not be unavoidable, as the
suggested counterparts are unavailable in constant code. This
configuration will cause restriction lints to trigger even
if no suggestion can be made.
**Default Value:** `false` (`bool`)
* [indexing_slicing](https://rust-lang.github.io/rust-clippy/master/index.html#indexing_slicing)

View file

@ -1,6 +1,6 @@
[package]
name = "clippy_lints"
version = "0.1.68"
version = "0.1.69"
description = "A bunch of helpful lints to avoid common pitfalls in Rust"
repository = "https://github.com/rust-lang/rust-clippy"
readme = "README.md"

View file

@ -1,10 +1,11 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::macros::{find_assert_eq_args, root_macro_call_first_node};
use clippy_utils::{diagnostics::span_lint_and_sugg, ty::implements_trait};
use clippy_utils::ty::{implements_trait, is_copy};
use rustc_ast::ast::LitKind;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind, Lit};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::ty::{self, Ty};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::symbol::Ident;
@ -43,9 +44,7 @@ fn is_bool_lit(e: &Expr<'_>) -> bool {
) && !e.span.from_expansion()
}
fn is_impl_not_trait_with_bool_out(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
let ty = cx.typeck_results().expr_ty(e);
fn is_impl_not_trait_with_bool_out<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
cx.tcx
.lang_items()
.not_trait()
@ -77,31 +76,57 @@ impl<'tcx> LateLintPass<'tcx> for BoolAssertComparison {
return;
}
let Some ((a, b, _)) = find_assert_eq_args(cx, expr, macro_call.expn) else { return };
if !(is_bool_lit(a) ^ is_bool_lit(b)) {
let a_span = a.span.source_callsite();
let b_span = b.span.source_callsite();
let (lit_span, non_lit_expr) = match (is_bool_lit(a), is_bool_lit(b)) {
// assert_eq!(true, b)
// ^^^^^^
(true, false) => (a_span.until(b_span), b),
// assert_eq!(a, true)
// ^^^^^^
(false, true) => (b_span.with_lo(a_span.hi()), a),
// If there are two boolean arguments, we definitely don't understand
// what's going on, so better leave things as is...
//
// Or there is simply no boolean and then we can leave things as is!
return;
}
_ => return,
};
if !is_impl_not_trait_with_bool_out(cx, a) || !is_impl_not_trait_with_bool_out(cx, b) {
let non_lit_ty = cx.typeck_results().expr_ty(non_lit_expr);
if !is_impl_not_trait_with_bool_out(cx, non_lit_ty) {
// At this point the expression which is not a boolean
// literal does not implement Not trait with a bool output,
// so we cannot suggest to rewrite our code
return;
}
if !is_copy(cx, non_lit_ty) {
// Only lint with types that are `Copy` because `assert!(x)` takes
// ownership of `x` whereas `assert_eq(x, true)` does not
return;
}
let macro_name = macro_name.as_str();
let non_eq_mac = &macro_name[..macro_name.len() - 3];
span_lint_and_sugg(
span_lint_and_then(
cx,
BOOL_ASSERT_COMPARISON,
macro_call.span,
&format!("used `{macro_name}!` with a literal bool"),
"replace it with",
format!("{non_eq_mac}!(..)"),
Applicability::MaybeIncorrect,
|diag| {
// assert_eq!(...)
// ^^^^^^^^^
let name_span = cx.sess().source_map().span_until_char(macro_call.span, '!');
diag.multipart_suggestion(
format!("replace it with `{non_eq_mac}!(..)`"),
vec![(name_span, non_eq_mac.to_string()), (lit_span, String::new())],
Applicability::MachineApplicable,
);
},
);
}
}

View file

@ -1,11 +1,14 @@
use clippy_utils::consts::{constant, Constant};
use clippy_utils::diagnostics::span_lint;
use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
use clippy_utils::expr_or_init;
use clippy_utils::source::snippet;
use clippy_utils::ty::{get_discriminant_value, is_isize_or_usize};
use rustc_errors::{Applicability, SuggestionStyle};
use rustc_hir::def::{DefKind, Res};
use rustc_hir::{BinOpKind, Expr, ExprKind};
use rustc_lint::LateContext;
use rustc_middle::ty::{self, FloatTy, Ty};
use rustc_span::Span;
use rustc_target::abi::IntegerType;
use super::{utils, CAST_ENUM_TRUNCATION, CAST_POSSIBLE_TRUNCATION};
@ -74,7 +77,14 @@ fn apply_reductions(cx: &LateContext<'_>, nbits: u64, expr: &Expr<'_>, signed: b
}
}
pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) {
pub(super) fn check(
cx: &LateContext<'_>,
expr: &Expr<'_>,
cast_expr: &Expr<'_>,
cast_from: Ty<'_>,
cast_to: Ty<'_>,
cast_to_span: Span,
) {
let msg = match (cast_from.kind(), cast_to.is_integral()) {
(ty::Int(_) | ty::Uint(_), true) => {
let from_nbits = apply_reductions(
@ -139,7 +149,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>,
);
return;
}
format!("casting `{cast_from}` to `{cast_to}` may truncate the value{suffix}",)
format!("casting `{cast_from}` to `{cast_to}` may truncate the value{suffix}")
},
(ty::Float(_), true) => {
@ -153,5 +163,19 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>,
_ => return,
};
span_lint(cx, CAST_POSSIBLE_TRUNCATION, expr.span, &msg);
let name_of_cast_from = snippet(cx, cast_expr.span, "..");
let cast_to_snip = snippet(cx, cast_to_span, "..");
let suggestion = format!("{cast_to_snip}::try_from({name_of_cast_from})");
span_lint_and_then(cx, CAST_POSSIBLE_TRUNCATION, expr.span, &msg, |diag| {
diag.help("if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...");
diag.span_suggestion_with_style(
expr.span,
"... or use `try_from` and handle the error accordingly",
suggestion,
Applicability::Unspecified,
// always show the suggestion in a separate line
SuggestionStyle::ShowAlways,
);
});
}

View file

@ -80,7 +80,8 @@ declare_clippy_lint! {
/// ### What it does
/// Checks for casts between numerical types that may
/// truncate large values. This is expected behavior, so the cast is `Allow` by
/// default.
/// default. It suggests user either explicitly ignore the lint,
/// or use `try_from()` and handle the truncation, default, or panic explicitly.
///
/// ### Why is this bad?
/// In some problem domains, it is good practice to avoid
@ -93,6 +94,21 @@ declare_clippy_lint! {
/// x as u8
/// }
/// ```
/// Use instead:
/// ```
/// fn as_u8(x: u64) -> u8 {
/// if let Ok(x) = u8::try_from(x) {
/// x
/// } else {
/// todo!();
/// }
/// }
/// // Or
/// #[allow(clippy::cast_possible_truncation)]
/// fn as_u16(x: u64) -> u16 {
/// x as u16
/// }
/// ```
#[clippy::version = "pre 1.29.0"]
pub CAST_POSSIBLE_TRUNCATION,
pedantic,
@ -712,7 +728,7 @@ impl<'tcx> LateLintPass<'tcx> for Casts {
fn_to_numeric_cast_with_truncation::check(cx, expr, cast_expr, cast_from, cast_to);
if cast_to.is_numeric() && !in_external_macro(cx.sess(), expr.span) {
cast_possible_truncation::check(cx, expr, cast_expr, cast_from, cast_to);
cast_possible_truncation::check(cx, expr, cast_expr, cast_from, cast_to, cast_to_hir.span);
if cast_from.is_numeric() {
cast_possible_wrap::check(cx, expr, cast_from, cast_to);
cast_precision_loss::check(cx, expr, cast_from, cast_to);

View file

@ -422,6 +422,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
crate::module_style::MOD_MODULE_FILES_INFO,
crate::module_style::SELF_NAMED_MODULE_FILES_INFO,
crate::multi_assignments::MULTI_ASSIGNMENTS_INFO,
crate::multiple_unsafe_ops_per_block::MULTIPLE_UNSAFE_OPS_PER_BLOCK_INFO,
crate::mut_key::MUTABLE_KEY_TYPE_INFO,
crate::mut_mut::MUT_MUT_INFO,
crate::mut_reference::UNNECESSARY_MUT_PASSED_INFO,

View file

@ -251,7 +251,7 @@ declare_clippy_lint! {
/// unimplemented!();
/// }
/// ```
#[clippy::version = "1.66.0"]
#[clippy::version = "1.67.0"]
pub UNNECESSARY_SAFETY_DOC,
restriction,
"`pub fn` or `pub trait` with `# Safety` docs"

View file

@ -277,7 +277,7 @@ impl LateLintPass<'_> for EnumVariantNames {
Some(c) if is_word_beginning(c) => span_lint(
cx,
MODULE_NAME_REPETITIONS,
item.span,
item.ident.span,
"item name starts with its containing module's name",
),
_ => (),
@ -287,7 +287,7 @@ impl LateLintPass<'_> for EnumVariantNames {
span_lint(
cx,
MODULE_NAME_REPETITIONS,
item.span,
item.ident.span,
"item name ends with its containing module's name",
);
}

View file

@ -31,7 +31,7 @@ declare_clippy_lint! {
/// let _ = unsafe { Box::from_raw(ptr as *mut usize) };
/// ```
///
#[clippy::version = "1.66.0"]
#[clippy::version = "1.67.0"]
pub FROM_RAW_WITH_VOID_PTR,
suspicious,
"creating a `Box` from a void raw pointer"

View file

@ -59,7 +59,7 @@ declare_clippy_lint! {
///
/// [`Duration`]: std::time::Duration
/// [`Instant::now()`]: std::time::Instant::now;
#[clippy::version = "1.65.0"]
#[clippy::version = "1.67.0"]
pub UNCHECKED_DURATION_SUBTRACTION,
pedantic,
"finds unchecked subtraction of a 'Duration' from an 'Instant'"

View file

@ -84,7 +84,7 @@ declare_clippy_lint! {
/// let _ = foo().await;
/// # }
/// ```
#[clippy::version = "1.66"]
#[clippy::version = "1.67.0"]
pub LET_UNDERSCORE_FUTURE,
suspicious,
"non-binding `let` on a future"

View file

@ -198,6 +198,7 @@ mod missing_trait_methods;
mod mixed_read_write_in_expression;
mod module_style;
mod multi_assignments;
mod multiple_unsafe_ops_per_block;
mod mut_key;
mod mut_mut;
mod mut_reference;
@ -908,6 +909,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(|_| Box::new(fn_null_check::FnNullCheck));
store.register_late_pass(|_| Box::new(permissions_set_readonly_false::PermissionsSetReadonlyFalse));
store.register_late_pass(|_| Box::new(size_of_ref::SizeOfRef));
store.register_late_pass(|_| Box::new(multiple_unsafe_ops_per_block::MultipleUnsafeOpsPerBlock));
// add lints here, do not remove this comment, it's used in `new_lint`
}

View file

@ -43,7 +43,7 @@ declare_clippy_lint! {
/// 'A'.is_ascii_uppercase();
/// }
/// ```
#[clippy::version = "1.66.0"]
#[clippy::version = "1.67.0"]
pub MANUAL_IS_ASCII_CHECK,
style,
"use dedicated method to check ascii range"

View file

@ -3102,7 +3102,7 @@ declare_clippy_lint! {
/// Ok(())
/// }
/// ```
#[clippy::version = "1.66.0"]
#[clippy::version = "1.67.0"]
pub SEEK_FROM_CURRENT,
complexity,
"use dedicated method for seek from current position"
@ -3133,7 +3133,7 @@ declare_clippy_lint! {
/// t.rewind();
/// }
/// ```
#[clippy::version = "1.66.0"]
#[clippy::version = "1.67.0"]
pub SEEK_TO_START_INSTEAD_OF_REWIND,
complexity,
"jumping to the start of stream using `seek` method"

View file

@ -94,7 +94,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingTraitMethods {
"implement the method",
);
}
})
});
}
}
}

View file

@ -0,0 +1,185 @@
use clippy_utils::{
diagnostics::span_lint_and_then,
visitors::{for_each_expr_with_closures, Descend, Visitable},
};
use core::ops::ControlFlow::Continue;
use hir::{
def::{DefKind, Res},
BlockCheckMode, ExprKind, QPath, UnOp, Unsafety,
};
use rustc_ast::Mutability;
use rustc_hir as hir;
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::Span;
declare_clippy_lint! {
/// ### What it does
/// Checks for `unsafe` blocks that contain more than one unsafe operation.
///
/// ### Why is this bad?
/// Combined with `undocumented_unsafe_blocks`,
/// this lint ensures that each unsafe operation must be independently justified.
/// Combined with `unused_unsafe`, this lint also ensures
/// elimination of unnecessary unsafe blocks through refactoring.
///
/// ### Example
/// ```rust
/// /// Reads a `char` from the given pointer.
/// ///
/// /// # Safety
/// ///
/// /// `ptr` must point to four consecutive, initialized bytes which
/// /// form a valid `char` when interpreted in the native byte order.
/// fn read_char(ptr: *const u8) -> char {
/// // SAFETY: The caller has guaranteed that the value pointed
/// // to by `bytes` is a valid `char`.
/// unsafe { char::from_u32_unchecked(*ptr.cast::<u32>()) }
/// }
/// ```
/// Use instead:
/// ```rust
/// /// Reads a `char` from the given pointer.
/// ///
/// /// # Safety
/// ///
/// /// - `ptr` must be 4-byte aligned, point to four consecutive
/// /// initialized bytes, and be valid for reads of 4 bytes.
/// /// - The bytes pointed to by `ptr` must represent a valid
/// /// `char` when interpreted in the native byte order.
/// fn read_char(ptr: *const u8) -> char {
/// // SAFETY: `ptr` is 4-byte aligned, points to four consecutive
/// // initialized bytes, and is valid for reads of 4 bytes.
/// let int_value = unsafe { *ptr.cast::<u32>() };
///
/// // SAFETY: The caller has guaranteed that the four bytes
/// // pointed to by `bytes` represent a valid `char`.
/// unsafe { char::from_u32_unchecked(int_value) }
/// }
/// ```
#[clippy::version = "1.68.0"]
pub MULTIPLE_UNSAFE_OPS_PER_BLOCK,
restriction,
"more than one unsafe operation per `unsafe` block"
}
declare_lint_pass!(MultipleUnsafeOpsPerBlock => [MULTIPLE_UNSAFE_OPS_PER_BLOCK]);
impl<'tcx> LateLintPass<'tcx> for MultipleUnsafeOpsPerBlock {
fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx hir::Block<'_>) {
if !matches!(block.rules, BlockCheckMode::UnsafeBlock(_)) {
return;
}
let mut unsafe_ops = vec![];
collect_unsafe_exprs(cx, block, &mut unsafe_ops);
if unsafe_ops.len() > 1 {
span_lint_and_then(
cx,
MULTIPLE_UNSAFE_OPS_PER_BLOCK,
block.span,
&format!(
"this `unsafe` block contains {} unsafe operations, expected only one",
unsafe_ops.len()
),
|diag| {
for (msg, span) in unsafe_ops {
diag.span_note(span, msg);
}
},
);
}
}
}
fn collect_unsafe_exprs<'tcx>(
cx: &LateContext<'tcx>,
node: impl Visitable<'tcx>,
unsafe_ops: &mut Vec<(&'static str, Span)>,
) {
for_each_expr_with_closures(cx, node, |expr| {
match expr.kind {
ExprKind::InlineAsm(_) => unsafe_ops.push(("inline assembly used here", expr.span)),
ExprKind::Field(e, _) => {
if cx.typeck_results().expr_ty(e).is_union() {
unsafe_ops.push(("union field access occurs here", expr.span));
}
},
ExprKind::Path(QPath::Resolved(
_,
hir::Path {
res: Res::Def(DefKind::Static(Mutability::Mut), _),
..
},
)) => {
unsafe_ops.push(("access of a mutable static occurs here", expr.span));
},
ExprKind::Unary(UnOp::Deref, e) if cx.typeck_results().expr_ty_adjusted(e).is_unsafe_ptr() => {
unsafe_ops.push(("raw pointer dereference occurs here", expr.span));
},
ExprKind::Call(path_expr, _) => match path_expr.kind {
ExprKind::Path(QPath::Resolved(
_,
hir::Path {
res: Res::Def(kind, def_id),
..
},
)) if kind.is_fn_like() => {
let sig = cx.tcx.fn_sig(*def_id);
if sig.0.unsafety() == Unsafety::Unsafe {
unsafe_ops.push(("unsafe function call occurs here", expr.span));
}
},
ExprKind::Path(QPath::TypeRelative(..)) => {
if let Some(sig) = cx
.typeck_results()
.type_dependent_def_id(path_expr.hir_id)
.map(|def_id| cx.tcx.fn_sig(def_id))
{
if sig.0.unsafety() == Unsafety::Unsafe {
unsafe_ops.push(("unsafe function call occurs here", expr.span));
}
}
},
_ => {},
},
ExprKind::MethodCall(..) => {
if let Some(sig) = cx
.typeck_results()
.type_dependent_def_id(expr.hir_id)
.map(|def_id| cx.tcx.fn_sig(def_id))
{
if sig.0.unsafety() == Unsafety::Unsafe {
unsafe_ops.push(("unsafe method call occurs here", expr.span));
}
}
},
ExprKind::AssignOp(_, lhs, rhs) | ExprKind::Assign(lhs, rhs, _) => {
if matches!(
lhs.kind,
ExprKind::Path(QPath::Resolved(
_,
hir::Path {
res: Res::Def(DefKind::Static(Mutability::Mut), _),
..
}
))
) {
unsafe_ops.push(("modification of a mutable static occurs here", expr.span));
collect_unsafe_exprs(cx, rhs, unsafe_ops);
return Continue(Descend::No);
}
},
_ => {},
};
Continue::<(), _>(Descend::Yes)
});
}

View file

@ -7,7 +7,7 @@ use rustc_hir::def_id::DefId;
use rustc_hir::hir_id::HirIdMap;
use rustc_hir::{Body, Expr, ExprKind, HirId, ImplItem, ImplItemKind, Node, PatKind, TraitItem, TraitItemKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
use rustc_middle::ty::subst::{EarlyBinder, GenericArgKind, SubstsRef};
use rustc_middle::ty::{self, ConstKind};
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::symbol::{kw, Ident};
@ -244,7 +244,7 @@ impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion {
})) => {
#[allow(trivial_casts)]
if let Some(Node::Item(item)) = get_parent_node(cx.tcx, owner_id.into())
&& let Some(trait_ref) = cx.tcx.impl_trait_ref(item.owner_id).map(|t| t.subst_identity())
&& let Some(trait_ref) = cx.tcx.impl_trait_ref(item.owner_id).map(EarlyBinder::subst_identity)
&& let Some(trait_item_id) = cx.tcx.associated_item(owner_id).trait_item_def_id
{
(

View file

@ -1,7 +1,7 @@
use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then};
use clippy_utils::source::{snippet_opt, snippet_with_context};
use clippy_utils::visitors::{for_each_expr, Descend};
use clippy_utils::{fn_def_id, path_to_local_id};
use clippy_utils::{fn_def_id, path_to_local_id, span_find_starting_semi};
use core::ops::ControlFlow;
use if_chain::if_chain;
use rustc_errors::Applicability;
@ -151,7 +151,7 @@ impl<'tcx> LateLintPass<'tcx> for Return {
kind: FnKind<'tcx>,
_: &'tcx FnDecl<'tcx>,
body: &'tcx Body<'tcx>,
_: Span,
sp: Span,
_: HirId,
) {
match kind {
@ -166,14 +166,14 @@ impl<'tcx> LateLintPass<'tcx> for Return {
check_final_expr(cx, body.value, vec![], replacement);
},
FnKind::ItemFn(..) | FnKind::Method(..) => {
check_block_return(cx, &body.value.kind, vec![]);
check_block_return(cx, &body.value.kind, sp, vec![]);
},
}
}
}
// if `expr` is a block, check if there are needless returns in it
fn check_block_return<'tcx>(cx: &LateContext<'tcx>, expr_kind: &ExprKind<'tcx>, semi_spans: Vec<Span>) {
fn check_block_return<'tcx>(cx: &LateContext<'tcx>, expr_kind: &ExprKind<'tcx>, sp: Span, mut semi_spans: Vec<Span>) {
if let ExprKind::Block(block, _) = expr_kind {
if let Some(block_expr) = block.expr {
check_final_expr(cx, block_expr, semi_spans, RetReplacement::Empty);
@ -183,12 +183,14 @@ fn check_block_return<'tcx>(cx: &LateContext<'tcx>, expr_kind: &ExprKind<'tcx>,
check_final_expr(cx, expr, semi_spans, RetReplacement::Empty);
},
StmtKind::Semi(semi_expr) => {
let mut semi_spans_and_this_one = semi_spans;
// we only want the span containing the semicolon so we can remove it later. From `entry.rs:382`
if let Some(semicolon_span) = stmt.span.trim_start(semi_expr.span) {
semi_spans_and_this_one.push(semicolon_span);
check_final_expr(cx, semi_expr, semi_spans_and_this_one, RetReplacement::Empty);
// Remove ending semicolons and any whitespace ' ' in between.
// Without `return`, the suggestion might not compile if the semicolon is retained
if let Some(semi_span) = stmt.span.trim_start(semi_expr.span) {
let semi_span_to_remove =
span_find_starting_semi(cx.sess().source_map(), semi_span.with_hi(sp.hi()));
semi_spans.push(semi_span_to_remove);
}
check_final_expr(cx, semi_expr, semi_spans, RetReplacement::Empty);
},
_ => (),
}
@ -231,9 +233,9 @@ fn check_final_expr<'tcx>(
emit_return_lint(cx, ret_span, semi_spans, inner.as_ref().map(|i| i.span), replacement);
},
ExprKind::If(_, then, else_clause_opt) => {
check_block_return(cx, &then.kind, semi_spans.clone());
check_block_return(cx, &then.kind, peeled_drop_expr.span, semi_spans.clone());
if let Some(else_clause) = else_clause_opt {
check_block_return(cx, &else_clause.kind, semi_spans);
check_block_return(cx, &else_clause.kind, peeled_drop_expr.span, semi_spans);
}
},
// a match expr, check all arms
@ -246,7 +248,7 @@ fn check_final_expr<'tcx>(
}
},
// if it's a whole block, check it
other_expr_kind => check_block_return(cx, other_expr_kind, semi_spans),
other_expr_kind => check_block_return(cx, other_expr_kind, peeled_drop_expr.span, semi_spans),
}
}

View file

@ -9,7 +9,7 @@ declare_clippy_lint! {
/// ### What it does
/// Warns for a Bitwise XOR (`^`) operator being probably confused as a powering. It will not trigger if any of the numbers are not in decimal.
/// ### Why is this bad?
/// It's most probably a typo and may lead to unexpected behaviours.
/// It's most probably a typo and may lead to unexpected behaviours.
/// ### Example
/// ```rust
/// let x = 3_i32 ^ 4_i32;
@ -18,7 +18,7 @@ declare_clippy_lint! {
/// ```rust
/// let x = 3_i32.pow(4);
/// ```
#[clippy::version = "1.66.0"]
#[clippy::version = "1.67.0"]
pub SUSPICIOUS_XOR_USED_AS_POW,
restriction,
"XOR (`^`) operator possibly used as exponentiation operator"

View file

@ -479,7 +479,10 @@ impl<'tcx> LateLintPass<'tcx> for Transmute {
// - char conversions (https://github.com/rust-lang/rust/issues/89259)
let const_context = in_constant(cx, e.hir_id);
let from_ty = cx.typeck_results().expr_ty_adjusted(arg);
let (from_ty, from_ty_adjusted) = match cx.typeck_results().expr_adjustments(arg) {
[] => (cx.typeck_results().expr_ty(arg), false),
[.., a] => (a.target, true),
};
// Adjustments for `to_ty` happen after the call to `transmute`, so don't use them.
let to_ty = cx.typeck_results().expr_ty(e);
@ -506,7 +509,7 @@ impl<'tcx> LateLintPass<'tcx> for Transmute {
);
if !linted {
transmutes_expressible_as_ptr_casts::check(cx, e, from_ty, to_ty, arg);
transmutes_expressible_as_ptr_casts::check(cx, e, from_ty, from_ty_adjusted, to_ty, arg);
}
}
}

View file

@ -1,11 +1,11 @@
use super::utils::can_be_expressed_as_pointer_cast;
use super::utils::check_cast;
use super::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS;
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::sugg;
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::sugg::Sugg;
use rustc_errors::Applicability;
use rustc_hir::Expr;
use rustc_lint::LateContext;
use rustc_middle::ty::Ty;
use rustc_middle::ty::{cast::CastKind, Ty};
/// Checks for `transmutes_expressible_as_ptr_casts` lint.
/// Returns `true` if it's triggered, otherwise returns `false`.
@ -13,24 +13,40 @@ pub(super) fn check<'tcx>(
cx: &LateContext<'tcx>,
e: &'tcx Expr<'_>,
from_ty: Ty<'tcx>,
from_ty_adjusted: bool,
to_ty: Ty<'tcx>,
arg: &'tcx Expr<'_>,
) -> bool {
if can_be_expressed_as_pointer_cast(cx, e, from_ty, to_ty) {
span_lint_and_then(
cx,
TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS,
e.span,
&format!("transmute from `{from_ty}` to `{to_ty}` which could be expressed as a pointer cast instead"),
|diag| {
if let Some(arg) = sugg::Sugg::hir_opt(cx, arg) {
let sugg = arg.as_ty(to_ty.to_string()).to_string();
diag.span_suggestion(e.span, "try", sugg, Applicability::MachineApplicable);
}
},
);
true
} else {
false
}
use CastKind::{AddrPtrCast, ArrayPtrCast, FnPtrAddrCast, FnPtrPtrCast, PtrAddrCast, PtrPtrCast};
let mut app = Applicability::MachineApplicable;
let sugg = match check_cast(cx, e, from_ty, to_ty) {
Some(PtrPtrCast | AddrPtrCast | ArrayPtrCast | FnPtrPtrCast | FnPtrAddrCast) => {
Sugg::hir_with_context(cx, arg, e.span.ctxt(), "..", &mut app)
.as_ty(to_ty.to_string())
.to_string()
},
Some(PtrAddrCast) if !from_ty_adjusted => Sugg::hir_with_context(cx, arg, e.span.ctxt(), "..", &mut app)
.as_ty(to_ty.to_string())
.to_string(),
// The only adjustments here would be ref-to-ptr and unsize coercions. The result of an unsize coercions can't
// be transmuted to a usize. For ref-to-ptr coercions, borrows need to be cast to a pointer before being cast to
// a usize.
Some(PtrAddrCast) => format!(
"{} as {to_ty}",
Sugg::hir_with_context(cx, arg, e.span.ctxt(), "..", &mut app).as_ty(from_ty)
),
_ => return false,
};
span_lint_and_sugg(
cx,
TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS,
e.span,
&format!("transmute from `{from_ty}` to `{to_ty}` which could be expressed as a pointer cast instead"),
"try",
sugg,
app,
);
true
}

View file

@ -20,28 +20,16 @@ pub(super) fn is_layout_incompatible<'tcx>(cx: &LateContext<'tcx>, from: Ty<'tcx
}
}
/// Check if the type conversion can be expressed as a pointer cast, instead of
/// a transmute. In certain cases, including some invalid casts from array
/// references to pointers, this may cause additional errors to be emitted and/or
/// ICE error messages. This function will panic if that occurs.
pub(super) fn can_be_expressed_as_pointer_cast<'tcx>(
cx: &LateContext<'tcx>,
e: &'tcx Expr<'_>,
from_ty: Ty<'tcx>,
to_ty: Ty<'tcx>,
) -> bool {
use CastKind::{AddrPtrCast, ArrayPtrCast, FnPtrAddrCast, FnPtrPtrCast, PtrAddrCast, PtrPtrCast};
matches!(
check_cast(cx, e, from_ty, to_ty),
Some(PtrPtrCast | PtrAddrCast | AddrPtrCast | ArrayPtrCast | FnPtrPtrCast | FnPtrAddrCast)
)
}
/// If a cast from `from_ty` to `to_ty` is valid, returns an Ok containing the kind of
/// the cast. In certain cases, including some invalid casts from array references
/// to pointers, this may cause additional errors to be emitted and/or ICE error
/// messages. This function will panic if that occurs.
fn check_cast<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, from_ty: Ty<'tcx>, to_ty: Ty<'tcx>) -> Option<CastKind> {
pub(super) fn check_cast<'tcx>(
cx: &LateContext<'tcx>,
e: &'tcx Expr<'_>,
from_ty: Ty<'tcx>,
to_ty: Ty<'tcx>,
) -> Option<CastKind> {
let hir_id = e.hir_id;
let local_def_id = hir_id.owner.def_id;

View file

@ -263,6 +263,18 @@ fn expr_has_unnecessary_safety_comment<'tcx>(
expr: &'tcx hir::Expr<'tcx>,
comment_pos: BytePos,
) -> Option<Span> {
if cx.tcx.hir().parent_iter(expr.hir_id).any(|(_, ref node)| {
matches!(
node,
Node::Block(&Block {
rules: BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided),
..
}),
)
}) {
return None;
}
// this should roughly be the reverse of `block_parents_have_safety_comment`
if for_each_expr_with_closures(cx, expr, |expr| match expr.kind {
hir::ExprKind::Block(

View file

@ -219,7 +219,8 @@ define_Conf! {
///
/// #### Noteworthy
///
/// A type, say `SomeType`, listed in this configuration has the same behavior of `["SomeType" , "*"], ["*", "SomeType"]` in `arithmetic_side_effects_allowed_binary`.
/// A type, say `SomeType`, listed in this configuration has the same behavior of
/// `["SomeType" , "*"], ["*", "SomeType"]` in `arithmetic_side_effects_allowed_binary`.
(arithmetic_side_effects_allowed: rustc_data_structures::fx::FxHashSet<String> = <_>::default()),
/// Lint: ARITHMETIC_SIDE_EFFECTS.
///

View file

@ -14,6 +14,7 @@ use clippy_utils::diagnostics::span_lint;
use clippy_utils::ty::{match_type, walk_ptrs_ty_depth};
use clippy_utils::{last_path_segment, match_def_path, match_function_call, match_path, paths};
use if_chain::if_chain;
use itertools::Itertools;
use rustc_ast as ast;
use rustc_data_structures::fx::FxHashMap;
use rustc_hir::{
@ -34,8 +35,10 @@ use std::path::Path;
use std::path::PathBuf;
use std::process::Command;
/// This is the output file of the lint collector.
const OUTPUT_FILE: &str = "../util/gh-pages/lints.json";
/// This is the json output file of the lint collector.
const JSON_OUTPUT_FILE: &str = "../util/gh-pages/lints.json";
/// This is the markdown output file of the lint collector.
const MARKDOWN_OUTPUT_FILE: &str = "../book/src/lint_configuration.md";
/// These lints are excluded from the export.
const BLACK_LISTED_LINTS: &[&str] = &["lint_author", "dump_hir", "internal_metadata_collector"];
/// These groups will be ignored by the lint group matcher. This is useful for collections like
@ -176,6 +179,23 @@ This lint has the following configuration variables:
)
})
}
fn configs_to_markdown(&self, map_fn: fn(&ClippyConfiguration) -> String) -> String {
self.config
.iter()
.filter(|config| config.deprecation_reason.is_none())
.filter(|config| !config.lints.is_empty())
.map(map_fn)
.join("\n")
}
fn get_markdown_docs(&self) -> String {
format!(
"## Lint Configuration Options\n| <div style=\"width:290px\">Option</div> | Default Value |\n|--|--|\n{}\n\n{}\n",
self.configs_to_markdown(ClippyConfiguration::to_markdown_table_entry),
self.configs_to_markdown(ClippyConfiguration::to_markdown_paragraph),
)
}
}
impl Drop for MetadataCollector {
@ -199,12 +219,37 @@ impl Drop for MetadataCollector {
collect_renames(&mut lints);
// Outputting
if Path::new(OUTPUT_FILE).exists() {
fs::remove_file(OUTPUT_FILE).unwrap();
// Outputting json
if Path::new(JSON_OUTPUT_FILE).exists() {
fs::remove_file(JSON_OUTPUT_FILE).unwrap();
}
let mut file = OpenOptions::new().write(true).create(true).open(OUTPUT_FILE).unwrap();
let mut file = OpenOptions::new()
.write(true)
.create(true)
.open(JSON_OUTPUT_FILE)
.unwrap();
writeln!(file, "{}", serde_json::to_string_pretty(&lints).unwrap()).unwrap();
// Outputting markdown
if Path::new(MARKDOWN_OUTPUT_FILE).exists() {
fs::remove_file(MARKDOWN_OUTPUT_FILE).unwrap();
}
let mut file = OpenOptions::new()
.write(true)
.create(true)
.open(MARKDOWN_OUTPUT_FILE)
.unwrap();
writeln!(
file,
"<!--
This file is generated by `cargo collect-metadata`.
Please use that command to update the file and do not edit it by hand.
-->
{}",
self.get_markdown_docs(),
)
.unwrap();
}
}
@ -505,6 +550,28 @@ impl ClippyConfiguration {
deprecation_reason,
}
}
fn to_markdown_paragraph(&self) -> String {
format!(
"### {}\n{}\n\n**Default Value:** `{}` (`{}`)\n\n{}\n\n",
self.name,
self.doc
.lines()
.map(|line| line.strip_prefix(" ").unwrap_or(line))
.join("\n"),
self.default,
self.config_type,
self.lints
.iter()
.map(|name| name.to_string().split_whitespace().next().unwrap().to_string())
.map(|name| format!("* [{name}](https://rust-lang.github.io/rust-clippy/master/index.html#{name})"))
.join("\n"),
)
}
fn to_markdown_table_entry(&self) -> String {
format!("| [{}](#{}) | `{}` |", self.name, self.name, self.default)
}
}
fn collect_configs() -> Vec<ClippyConfiguration> {

View file

@ -1,6 +1,6 @@
[package]
name = "clippy_utils"
version = "0.1.68"
version = "0.1.69"
edition = "2021"
publish = false

View file

@ -2491,6 +2491,10 @@ pub fn span_extract_comment(sm: &SourceMap, span: Span) -> String {
comments_buf.join("\n")
}
pub fn span_find_starting_semi(sm: &SourceMap, span: Span) -> Span {
sm.span_take_while(span, |&ch| ch == ' ' || ch == ';')
}
macro_rules! op_utils {
($($name:ident $assign:ident)*) => {
/// Binary operation traits like `LangItem::Add`

View file

@ -647,9 +647,12 @@ pub fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<ExprFnSig<'t
Some(ExprFnSig::Closure(decl, subs.as_closure().sig()))
},
ty::FnDef(id, subs) => Some(ExprFnSig::Sig(cx.tcx.fn_sig(id).subst(cx.tcx, subs), Some(id))),
ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
sig_from_bounds(cx, ty, cx.tcx.item_bounds(def_id).subst(cx.tcx, substs), cx.tcx.opt_parent(def_id))
},
ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => sig_from_bounds(
cx,
ty,
cx.tcx.item_bounds(def_id).subst(cx.tcx, substs),
cx.tcx.opt_parent(def_id),
),
ty::FnPtr(sig) => Some(ExprFnSig::Sig(sig, None)),
ty::Dynamic(bounds, _, _) => {
let lang_items = cx.tcx.lang_items();

View file

@ -1,6 +1,6 @@
[package]
name = "declare_clippy_lint"
version = "0.1.68"
version = "0.1.69"
edition = "2021"
publish = false

View file

@ -1,3 +1,3 @@
[toolchain]
channel = "nightly-2023-01-12"
channel = "nightly-2023-01-27"
components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]

View file

@ -28,7 +28,7 @@ with:
-D --deny OPT Set lint denied
-F --forbid OPT Set lint forbidden
You can use tool lints to allow or deny lints from your code, eg.:
You can use tool lints to allow or deny lints from your code, e.g.:
#[allow(clippy::needless_lifetimes)]
"#;

View file

@ -7,14 +7,6 @@ LL | const DEREF_TRAIT: [&str; 4] = ["core", "ops", "deref", "Deref"];
= help: convert all references to use `sym::Deref`
= note: `-D clippy::unnecessary-def-path` implied by `-D warnings`
error: hardcoded path to a language item
--> $DIR/unnecessary_def_path_hardcoded_path.rs:11:40
|
LL | const DEREF_MUT_TRAIT: [&str; 4] = ["core", "ops", "deref", "DerefMut"];
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: convert all references to use `LangItem::DerefMut`
error: hardcoded path to a diagnostic item
--> $DIR/unnecessary_def_path_hardcoded_path.rs:12:43
|
@ -23,5 +15,13 @@ LL | const DEREF_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "Deref",
|
= help: convert all references to use `sym::deref_method`
error: hardcoded path to a language item
--> $DIR/unnecessary_def_path_hardcoded_path.rs:11:40
|
LL | const DEREF_MUT_TRAIT: [&str; 4] = ["core", "ops", "deref", "DerefMut"];
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: convert all references to use `LangItem::DerefMut`
error: aborting due to 3 previous errors

View file

@ -0,0 +1,161 @@
// run-rustfix
#![allow(unused, clippy::assertions_on_constants)]
#![warn(clippy::bool_assert_comparison)]
use std::ops::Not;
macro_rules! a {
() => {
true
};
}
macro_rules! b {
() => {
true
};
}
// Implements the Not trait but with an output type
// that's not bool. Should not suggest a rewrite
#[derive(Debug, Clone, Copy)]
enum ImplNotTraitWithoutBool {
VariantX(bool),
VariantY(u32),
}
impl PartialEq<bool> for ImplNotTraitWithoutBool {
fn eq(&self, other: &bool) -> bool {
match *self {
ImplNotTraitWithoutBool::VariantX(b) => b == *other,
_ => false,
}
}
}
impl Not for ImplNotTraitWithoutBool {
type Output = Self;
fn not(self) -> Self::Output {
match self {
ImplNotTraitWithoutBool::VariantX(b) => ImplNotTraitWithoutBool::VariantX(!b),
ImplNotTraitWithoutBool::VariantY(0) => ImplNotTraitWithoutBool::VariantY(1),
ImplNotTraitWithoutBool::VariantY(_) => ImplNotTraitWithoutBool::VariantY(0),
}
}
}
// This type implements the Not trait with an Output of
// type bool. Using assert!(..) must be suggested
#[derive(Debug, Clone, Copy)]
struct ImplNotTraitWithBool;
impl PartialEq<bool> for ImplNotTraitWithBool {
fn eq(&self, other: &bool) -> bool {
false
}
}
impl Not for ImplNotTraitWithBool {
type Output = bool;
fn not(self) -> Self::Output {
true
}
}
#[derive(Debug)]
struct NonCopy;
impl PartialEq<bool> for NonCopy {
fn eq(&self, other: &bool) -> bool {
false
}
}
impl Not for NonCopy {
type Output = bool;
fn not(self) -> Self::Output {
true
}
}
fn main() {
let a = ImplNotTraitWithoutBool::VariantX(true);
let b = ImplNotTraitWithBool;
assert_eq!("a".len(), 1);
assert!("a".is_empty());
assert!("".is_empty());
assert!("".is_empty());
assert_eq!(a!(), b!());
assert_eq!(a!(), "".is_empty());
assert_eq!("".is_empty(), b!());
assert_eq!(a, true);
assert!(b);
assert_ne!("a".len(), 1);
assert!("a".is_empty());
assert!("".is_empty());
assert!("".is_empty());
assert_ne!(a!(), b!());
assert_ne!(a!(), "".is_empty());
assert_ne!("".is_empty(), b!());
assert_ne!(a, true);
assert!(b);
debug_assert_eq!("a".len(), 1);
debug_assert!("a".is_empty());
debug_assert!("".is_empty());
debug_assert!("".is_empty());
debug_assert_eq!(a!(), b!());
debug_assert_eq!(a!(), "".is_empty());
debug_assert_eq!("".is_empty(), b!());
debug_assert_eq!(a, true);
debug_assert!(b);
debug_assert_ne!("a".len(), 1);
debug_assert!("a".is_empty());
debug_assert!("".is_empty());
debug_assert!("".is_empty());
debug_assert_ne!(a!(), b!());
debug_assert_ne!(a!(), "".is_empty());
debug_assert_ne!("".is_empty(), b!());
debug_assert_ne!(a, true);
debug_assert!(b);
// assert with error messages
assert_eq!("a".len(), 1, "tadam {}", 1);
assert_eq!("a".len(), 1, "tadam {}", true);
assert!("a".is_empty(), "tadam {}", 1);
assert!("a".is_empty(), "tadam {}", true);
assert!("a".is_empty(), "tadam {}", true);
assert_eq!(a, true, "tadam {}", false);
debug_assert_eq!("a".len(), 1, "tadam {}", 1);
debug_assert_eq!("a".len(), 1, "tadam {}", true);
debug_assert!("a".is_empty(), "tadam {}", 1);
debug_assert!("a".is_empty(), "tadam {}", true);
debug_assert!("a".is_empty(), "tadam {}", true);
debug_assert_eq!(a, true, "tadam {}", false);
assert!(a!());
assert!(b!());
use debug_assert_eq as renamed;
renamed!(a, true);
debug_assert!(b);
let non_copy = NonCopy;
assert_eq!(non_copy, true);
// changing the above to `assert!(non_copy)` would cause a `borrow of moved value`
println!("{non_copy:?}");
macro_rules! in_macro {
($v:expr) => {{
assert_eq!($v, true);
}};
}
in_macro!(a);
}

View file

@ -1,3 +1,6 @@
// run-rustfix
#![allow(unused, clippy::assertions_on_constants)]
#![warn(clippy::bool_assert_comparison)]
use std::ops::Not;
@ -15,7 +18,7 @@ macro_rules! b {
// Implements the Not trait but with an output type
// that's not bool. Should not suggest a rewrite
#[derive(Debug)]
#[derive(Debug, Clone, Copy)]
enum ImplNotTraitWithoutBool {
VariantX(bool),
VariantY(u32),
@ -44,7 +47,7 @@ impl Not for ImplNotTraitWithoutBool {
// This type implements the Not trait with an Output of
// type bool. Using assert!(..) must be suggested
#[derive(Debug)]
#[derive(Debug, Clone, Copy)]
struct ImplNotTraitWithBool;
impl PartialEq<bool> for ImplNotTraitWithBool {
@ -61,6 +64,23 @@ impl Not for ImplNotTraitWithBool {
}
}
#[derive(Debug)]
struct NonCopy;
impl PartialEq<bool> for NonCopy {
fn eq(&self, other: &bool) -> bool {
false
}
}
impl Not for NonCopy {
type Output = bool;
fn not(self) -> Self::Output {
true
}
}
fn main() {
let a = ImplNotTraitWithoutBool::VariantX(true);
let b = ImplNotTraitWithBool;
@ -119,4 +139,23 @@ fn main() {
debug_assert_eq!("a".is_empty(), false, "tadam {}", true);
debug_assert_eq!(false, "a".is_empty(), "tadam {}", true);
debug_assert_eq!(a, true, "tadam {}", false);
assert_eq!(a!(), true);
assert_eq!(true, b!());
use debug_assert_eq as renamed;
renamed!(a, true);
renamed!(b, true);
let non_copy = NonCopy;
assert_eq!(non_copy, true);
// changing the above to `assert!(non_copy)` would cause a `borrow of moved value`
println!("{non_copy:?}");
macro_rules! in_macro {
($v:expr) => {{
assert_eq!($v, true);
}};
}
in_macro!(a);
}

View file

@ -1,136 +1,303 @@
error: used `assert_eq!` with a literal bool
--> $DIR/bool_assert_comparison.rs:69:5
|
LL | assert_eq!("a".is_empty(), false);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)`
|
= note: `-D clippy::bool-assert-comparison` implied by `-D warnings`
error: used `assert_eq!` with a literal bool
--> $DIR/bool_assert_comparison.rs:70:5
|
LL | assert_eq!("".is_empty(), true);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)`
error: used `assert_eq!` with a literal bool
--> $DIR/bool_assert_comparison.rs:71:5
|
LL | assert_eq!(true, "".is_empty());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)`
error: used `assert_eq!` with a literal bool
--> $DIR/bool_assert_comparison.rs:76:5
|
LL | assert_eq!(b, true);
| ^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)`
error: used `assert_ne!` with a literal bool
--> $DIR/bool_assert_comparison.rs:79:5
|
LL | assert_ne!("a".is_empty(), false);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)`
error: used `assert_ne!` with a literal bool
--> $DIR/bool_assert_comparison.rs:80:5
|
LL | assert_ne!("".is_empty(), true);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)`
error: used `assert_ne!` with a literal bool
--> $DIR/bool_assert_comparison.rs:81:5
|
LL | assert_ne!(true, "".is_empty());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)`
error: used `assert_ne!` with a literal bool
--> $DIR/bool_assert_comparison.rs:86:5
|
LL | assert_ne!(b, true);
| ^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)`
error: used `debug_assert_eq!` with a literal bool
--> $DIR/bool_assert_comparison.rs:89:5
|
LL | debug_assert_eq!("a".is_empty(), false);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `debug_assert!(..)`
LL | assert_eq!("a".is_empty(), false);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `-D clippy::bool-assert-comparison` implied by `-D warnings`
help: replace it with `assert!(..)`
|
LL - assert_eq!("a".is_empty(), false);
LL + assert!("a".is_empty());
|
error: used `debug_assert_eq!` with a literal bool
error: used `assert_eq!` with a literal bool
--> $DIR/bool_assert_comparison.rs:90:5
|
LL | debug_assert_eq!("".is_empty(), true);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `debug_assert!(..)`
LL | assert_eq!("".is_empty(), true);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: replace it with `assert!(..)`
|
LL - assert_eq!("".is_empty(), true);
LL + assert!("".is_empty());
|
error: used `debug_assert_eq!` with a literal bool
error: used `assert_eq!` with a literal bool
--> $DIR/bool_assert_comparison.rs:91:5
|
LL | debug_assert_eq!(true, "".is_empty());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `debug_assert!(..)`
LL | assert_eq!(true, "".is_empty());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: replace it with `assert!(..)`
|
LL - assert_eq!(true, "".is_empty());
LL + assert!("".is_empty());
|
error: used `debug_assert_eq!` with a literal bool
error: used `assert_eq!` with a literal bool
--> $DIR/bool_assert_comparison.rs:96:5
|
LL | debug_assert_eq!(b, true);
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `debug_assert!(..)`
LL | assert_eq!(b, true);
| ^^^^^^^^^^^^^^^^^^^
|
help: replace it with `assert!(..)`
|
LL - assert_eq!(b, true);
LL + assert!(b);
|
error: used `debug_assert_ne!` with a literal bool
error: used `assert_ne!` with a literal bool
--> $DIR/bool_assert_comparison.rs:99:5
|
LL | debug_assert_ne!("a".is_empty(), false);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `debug_assert!(..)`
LL | assert_ne!("a".is_empty(), false);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: replace it with `assert!(..)`
|
LL - assert_ne!("a".is_empty(), false);
LL + assert!("a".is_empty());
|
error: used `debug_assert_ne!` with a literal bool
error: used `assert_ne!` with a literal bool
--> $DIR/bool_assert_comparison.rs:100:5
|
LL | debug_assert_ne!("".is_empty(), true);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `debug_assert!(..)`
LL | assert_ne!("".is_empty(), true);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: replace it with `assert!(..)`
|
LL - assert_ne!("".is_empty(), true);
LL + assert!("".is_empty());
|
error: used `debug_assert_ne!` with a literal bool
error: used `assert_ne!` with a literal bool
--> $DIR/bool_assert_comparison.rs:101:5
|
LL | debug_assert_ne!(true, "".is_empty());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `debug_assert!(..)`
LL | assert_ne!(true, "".is_empty());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: replace it with `assert!(..)`
|
LL - assert_ne!(true, "".is_empty());
LL + assert!("".is_empty());
|
error: used `debug_assert_ne!` with a literal bool
error: used `assert_ne!` with a literal bool
--> $DIR/bool_assert_comparison.rs:106:5
|
LL | debug_assert_ne!(b, true);
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `debug_assert!(..)`
LL | assert_ne!(b, true);
| ^^^^^^^^^^^^^^^^^^^
|
help: replace it with `assert!(..)`
|
LL - assert_ne!(b, true);
LL + assert!(b);
|
error: used `assert_eq!` with a literal bool
error: used `debug_assert_eq!` with a literal bool
--> $DIR/bool_assert_comparison.rs:109:5
|
LL | debug_assert_eq!("a".is_empty(), false);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: replace it with `debug_assert!(..)`
|
LL - debug_assert_eq!("a".is_empty(), false);
LL + debug_assert!("a".is_empty());
|
error: used `debug_assert_eq!` with a literal bool
--> $DIR/bool_assert_comparison.rs:110:5
|
LL | debug_assert_eq!("".is_empty(), true);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: replace it with `debug_assert!(..)`
|
LL - debug_assert_eq!("".is_empty(), true);
LL + debug_assert!("".is_empty());
|
error: used `debug_assert_eq!` with a literal bool
--> $DIR/bool_assert_comparison.rs:111:5
|
LL | assert_eq!("a".is_empty(), false, "tadam {}", 1);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)`
error: used `assert_eq!` with a literal bool
--> $DIR/bool_assert_comparison.rs:112:5
LL | debug_assert_eq!(true, "".is_empty());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
LL | assert_eq!("a".is_empty(), false, "tadam {}", true);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)`
error: used `assert_eq!` with a literal bool
--> $DIR/bool_assert_comparison.rs:113:5
help: replace it with `debug_assert!(..)`
|
LL - debug_assert_eq!(true, "".is_empty());
LL + debug_assert!("".is_empty());
|
LL | assert_eq!(false, "a".is_empty(), "tadam {}", true);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)`
error: used `debug_assert_eq!` with a literal bool
--> $DIR/bool_assert_comparison.rs:118:5
--> $DIR/bool_assert_comparison.rs:116:5
|
LL | debug_assert_eq!(b, true);
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: replace it with `debug_assert!(..)`
|
LL - debug_assert_eq!(b, true);
LL + debug_assert!(b);
|
LL | debug_assert_eq!("a".is_empty(), false, "tadam {}", 1);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `debug_assert!(..)`
error: used `debug_assert_eq!` with a literal bool
error: used `debug_assert_ne!` with a literal bool
--> $DIR/bool_assert_comparison.rs:119:5
|
LL | debug_assert_eq!("a".is_empty(), false, "tadam {}", true);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `debug_assert!(..)`
LL | debug_assert_ne!("a".is_empty(), false);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: replace it with `debug_assert!(..)`
|
LL - debug_assert_ne!("a".is_empty(), false);
LL + debug_assert!("a".is_empty());
|
error: used `debug_assert_eq!` with a literal bool
error: used `debug_assert_ne!` with a literal bool
--> $DIR/bool_assert_comparison.rs:120:5
|
LL | debug_assert_ne!("".is_empty(), true);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: replace it with `debug_assert!(..)`
|
LL - debug_assert_ne!("".is_empty(), true);
LL + debug_assert!("".is_empty());
|
error: used `debug_assert_ne!` with a literal bool
--> $DIR/bool_assert_comparison.rs:121:5
|
LL | debug_assert_ne!(true, "".is_empty());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: replace it with `debug_assert!(..)`
|
LL - debug_assert_ne!(true, "".is_empty());
LL + debug_assert!("".is_empty());
|
error: used `debug_assert_ne!` with a literal bool
--> $DIR/bool_assert_comparison.rs:126:5
|
LL | debug_assert_ne!(b, true);
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: replace it with `debug_assert!(..)`
|
LL - debug_assert_ne!(b, true);
LL + debug_assert!(b);
|
error: used `assert_eq!` with a literal bool
--> $DIR/bool_assert_comparison.rs:131:5
|
LL | assert_eq!("a".is_empty(), false, "tadam {}", 1);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: replace it with `assert!(..)`
|
LL - assert_eq!("a".is_empty(), false, "tadam {}", 1);
LL + assert!("a".is_empty(), "tadam {}", 1);
|
error: used `assert_eq!` with a literal bool
--> $DIR/bool_assert_comparison.rs:132:5
|
LL | assert_eq!("a".is_empty(), false, "tadam {}", true);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: replace it with `assert!(..)`
|
LL - assert_eq!("a".is_empty(), false, "tadam {}", true);
LL + assert!("a".is_empty(), "tadam {}", true);
|
error: used `assert_eq!` with a literal bool
--> $DIR/bool_assert_comparison.rs:133:5
|
LL | assert_eq!(false, "a".is_empty(), "tadam {}", true);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: replace it with `assert!(..)`
|
LL - assert_eq!(false, "a".is_empty(), "tadam {}", true);
LL + assert!("a".is_empty(), "tadam {}", true);
|
error: used `debug_assert_eq!` with a literal bool
--> $DIR/bool_assert_comparison.rs:138:5
|
LL | debug_assert_eq!("a".is_empty(), false, "tadam {}", 1);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: replace it with `debug_assert!(..)`
|
LL - debug_assert_eq!("a".is_empty(), false, "tadam {}", 1);
LL + debug_assert!("a".is_empty(), "tadam {}", 1);
|
error: used `debug_assert_eq!` with a literal bool
--> $DIR/bool_assert_comparison.rs:139:5
|
LL | debug_assert_eq!("a".is_empty(), false, "tadam {}", true);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: replace it with `debug_assert!(..)`
|
LL - debug_assert_eq!("a".is_empty(), false, "tadam {}", true);
LL + debug_assert!("a".is_empty(), "tadam {}", true);
|
error: used `debug_assert_eq!` with a literal bool
--> $DIR/bool_assert_comparison.rs:140:5
|
LL | debug_assert_eq!(false, "a".is_empty(), "tadam {}", true);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `debug_assert!(..)`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: replace it with `debug_assert!(..)`
|
LL - debug_assert_eq!(false, "a".is_empty(), "tadam {}", true);
LL + debug_assert!("a".is_empty(), "tadam {}", true);
|
error: aborting due to 22 previous errors
error: used `assert_eq!` with a literal bool
--> $DIR/bool_assert_comparison.rs:143:5
|
LL | assert_eq!(a!(), true);
| ^^^^^^^^^^^^^^^^^^^^^^
|
help: replace it with `assert!(..)`
|
LL - assert_eq!(a!(), true);
LL + assert!(a!());
|
error: used `assert_eq!` with a literal bool
--> $DIR/bool_assert_comparison.rs:144:5
|
LL | assert_eq!(true, b!());
| ^^^^^^^^^^^^^^^^^^^^^^
|
help: replace it with `assert!(..)`
|
LL - assert_eq!(true, b!());
LL + assert!(b!());
|
error: used `debug_assert_eq!` with a literal bool
--> $DIR/bool_assert_comparison.rs:148:5
|
LL | renamed!(b, true);
| ^^^^^^^^^^^^^^^^^
|
help: replace it with `debug_assert!(..)`
|
LL - renamed!(b, true);
LL + debug_assert!(b);
|
error: aborting due to 25 previous errors

View file

@ -28,6 +28,7 @@ fn main() {
1i32 as u8;
1f64 as isize;
1f64 as usize;
1f32 as u32 as u16;
// Test clippy::cast_possible_wrap
1u8 as i8;
1u16 as i16;

View file

@ -42,13 +42,24 @@ error: casting `f32` to `i32` may truncate the value
LL | 1f32 as i32;
| ^^^^^^^^^^^
|
= help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
= note: `-D clippy::cast-possible-truncation` implied by `-D warnings`
help: ... or use `try_from` and handle the error accordingly
|
LL | i32::try_from(1f32);
| ~~~~~~~~~~~~~~~~~~~
error: casting `f32` to `u32` may truncate the value
--> $DIR/cast.rs:25:5
|
LL | 1f32 as u32;
| ^^^^^^^^^^^
|
= help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
help: ... or use `try_from` and handle the error accordingly
|
LL | u32::try_from(1f32);
| ~~~~~~~~~~~~~~~~~~~
error: casting `f32` to `u32` may lose the sign of the value
--> $DIR/cast.rs:25:5
@ -63,30 +74,60 @@ error: casting `f64` to `f32` may truncate the value
|
LL | 1f64 as f32;
| ^^^^^^^^^^^
|
= help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
help: ... or use `try_from` and handle the error accordingly
|
LL | f32::try_from(1f64);
| ~~~~~~~~~~~~~~~~~~~
error: casting `i32` to `i8` may truncate the value
--> $DIR/cast.rs:27:5
|
LL | 1i32 as i8;
| ^^^^^^^^^^
|
= help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
help: ... or use `try_from` and handle the error accordingly
|
LL | i8::try_from(1i32);
| ~~~~~~~~~~~~~~~~~~
error: casting `i32` to `u8` may truncate the value
--> $DIR/cast.rs:28:5
|
LL | 1i32 as u8;
| ^^^^^^^^^^
|
= help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
help: ... or use `try_from` and handle the error accordingly
|
LL | u8::try_from(1i32);
| ~~~~~~~~~~~~~~~~~~
error: casting `f64` to `isize` may truncate the value
--> $DIR/cast.rs:29:5
|
LL | 1f64 as isize;
| ^^^^^^^^^^^^^
|
= help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
help: ... or use `try_from` and handle the error accordingly
|
LL | isize::try_from(1f64);
| ~~~~~~~~~~~~~~~~~~~~~
error: casting `f64` to `usize` may truncate the value
--> $DIR/cast.rs:30:5
|
LL | 1f64 as usize;
| ^^^^^^^^^^^^^
|
= help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
help: ... or use `try_from` and handle the error accordingly
|
LL | usize::try_from(1f64);
| ~~~~~~~~~~~~~~~~~~~~~
error: casting `f64` to `usize` may lose the sign of the value
--> $DIR/cast.rs:30:5
@ -94,8 +135,38 @@ error: casting `f64` to `usize` may lose the sign of the value
LL | 1f64 as usize;
| ^^^^^^^^^^^^^
error: casting `u32` to `u16` may truncate the value
--> $DIR/cast.rs:31:5
|
LL | 1f32 as u32 as u16;
| ^^^^^^^^^^^^^^^^^^
|
= help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
help: ... or use `try_from` and handle the error accordingly
|
LL | u16::try_from(1f32 as u32);
| ~~~~~~~~~~~~~~~~~~~~~~~~~~
error: casting `f32` to `u32` may truncate the value
--> $DIR/cast.rs:31:5
|
LL | 1f32 as u32 as u16;
| ^^^^^^^^^^^
|
= help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
help: ... or use `try_from` and handle the error accordingly
|
LL | u32::try_from(1f32) as u16;
| ~~~~~~~~~~~~~~~~~~~
error: casting `f32` to `u32` may lose the sign of the value
--> $DIR/cast.rs:31:5
|
LL | 1f32 as u32 as u16;
| ^^^^^^^^^^^
error: casting `u8` to `i8` may wrap around the value
--> $DIR/cast.rs:32:5
--> $DIR/cast.rs:33:5
|
LL | 1u8 as i8;
| ^^^^^^^^^
@ -103,61 +174,79 @@ LL | 1u8 as i8;
= note: `-D clippy::cast-possible-wrap` implied by `-D warnings`
error: casting `u16` to `i16` may wrap around the value
--> $DIR/cast.rs:33:5
--> $DIR/cast.rs:34:5
|
LL | 1u16 as i16;
| ^^^^^^^^^^^
error: casting `u32` to `i32` may wrap around the value
--> $DIR/cast.rs:34:5
--> $DIR/cast.rs:35:5
|
LL | 1u32 as i32;
| ^^^^^^^^^^^
error: casting `u64` to `i64` may wrap around the value
--> $DIR/cast.rs:35:5
--> $DIR/cast.rs:36:5
|
LL | 1u64 as i64;
| ^^^^^^^^^^^
error: casting `usize` to `isize` may wrap around the value
--> $DIR/cast.rs:36:5
--> $DIR/cast.rs:37:5
|
LL | 1usize as isize;
| ^^^^^^^^^^^^^^^
error: casting `i32` to `u32` may lose the sign of the value
--> $DIR/cast.rs:39:5
--> $DIR/cast.rs:40:5
|
LL | -1i32 as u32;
| ^^^^^^^^^^^^
error: casting `isize` to `usize` may lose the sign of the value
--> $DIR/cast.rs:41:5
--> $DIR/cast.rs:42:5
|
LL | -1isize as usize;
| ^^^^^^^^^^^^^^^^
error: casting `i64` to `i8` may truncate the value
--> $DIR/cast.rs:108:5
--> $DIR/cast.rs:109:5
|
LL | (-99999999999i64).min(1) as i8; // should be linted because signed
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
help: ... or use `try_from` and handle the error accordingly
|
LL | i8::try_from((-99999999999i64).min(1)); // should be linted because signed
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: casting `u64` to `u8` may truncate the value
--> $DIR/cast.rs:120:5
--> $DIR/cast.rs:121:5
|
LL | 999999u64.clamp(0, 256) as u8; // should still be linted
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
help: ... or use `try_from` and handle the error accordingly
|
LL | u8::try_from(999999u64.clamp(0, 256)); // should still be linted
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: casting `main::E2` to `u8` may truncate the value
--> $DIR/cast.rs:141:21
--> $DIR/cast.rs:142:21
|
LL | let _ = self as u8;
| ^^^^^^^^^^
|
= help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
help: ... or use `try_from` and handle the error accordingly
|
LL | let _ = u8::try_from(self);
| ~~~~~~~~~~~~~~~~~~
error: casting `main::E2::B` to `u8` will truncate the value
--> $DIR/cast.rs:142:21
--> $DIR/cast.rs:143:21
|
LL | let _ = Self::B as u8;
| ^^^^^^^^^^^^^
@ -165,46 +254,82 @@ LL | let _ = Self::B as u8;
= note: `-D clippy::cast-enum-truncation` implied by `-D warnings`
error: casting `main::E5` to `i8` may truncate the value
--> $DIR/cast.rs:178:21
--> $DIR/cast.rs:179:21
|
LL | let _ = self as i8;
| ^^^^^^^^^^
|
= help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
help: ... or use `try_from` and handle the error accordingly
|
LL | let _ = i8::try_from(self);
| ~~~~~~~~~~~~~~~~~~
error: casting `main::E5::A` to `i8` will truncate the value
--> $DIR/cast.rs:179:21
--> $DIR/cast.rs:180:21
|
LL | let _ = Self::A as i8;
| ^^^^^^^^^^^^^
error: casting `main::E6` to `i16` may truncate the value
--> $DIR/cast.rs:193:21
--> $DIR/cast.rs:194:21
|
LL | let _ = self as i16;
| ^^^^^^^^^^^
|
= help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
help: ... or use `try_from` and handle the error accordingly
|
LL | let _ = i16::try_from(self);
| ~~~~~~~~~~~~~~~~~~~
error: casting `main::E7` to `usize` may truncate the value on targets with 32-bit wide pointers
--> $DIR/cast.rs:208:21
--> $DIR/cast.rs:209:21
|
LL | let _ = self as usize;
| ^^^^^^^^^^^^^
|
= help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
help: ... or use `try_from` and handle the error accordingly
|
LL | let _ = usize::try_from(self);
| ~~~~~~~~~~~~~~~~~~~~~
error: casting `main::E10` to `u16` may truncate the value
--> $DIR/cast.rs:249:21
--> $DIR/cast.rs:250:21
|
LL | let _ = self as u16;
| ^^^^^^^^^^^
|
= help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
help: ... or use `try_from` and handle the error accordingly
|
LL | let _ = u16::try_from(self);
| ~~~~~~~~~~~~~~~~~~~
error: casting `u32` to `u8` may truncate the value
--> $DIR/cast.rs:257:13
--> $DIR/cast.rs:258:13
|
LL | let c = (q >> 16) as u8;
| ^^^^^^^^^^^^^^^
|
= help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
help: ... or use `try_from` and handle the error accordingly
|
LL | let c = u8::try_from((q >> 16));
| ~~~~~~~~~~~~~~~~~~~~~~~
error: casting `u32` to `u8` may truncate the value
--> $DIR/cast.rs:260:13
--> $DIR/cast.rs:261:13
|
LL | let c = (q / 1000) as u8;
| ^^^^^^^^^^^^^^^^
|
= help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
help: ... or use `try_from` and handle the error accordingly
|
LL | let c = u8::try_from((q / 1000));
| ~~~~~~~~~~~~~~~~~~~~~~~~
error: aborting due to 33 previous errors
error: aborting due to 36 previous errors

View file

@ -4,7 +4,12 @@ error: casting `isize` to `i8` may truncate the value
LL | 1isize as i8;
| ^^^^^^^^^^^^
|
= help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
= note: `-D clippy::cast-possible-truncation` implied by `-D warnings`
help: ... or use `try_from` and handle the error accordingly
|
LL | i8::try_from(1isize);
| ~~~~~~~~~~~~~~~~~~~~
error: casting `isize` to `f64` causes a loss of precision on targets with 64-bit wide pointers (`isize` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)
--> $DIR/cast_size.rs:15:5
@ -37,24 +42,48 @@ error: casting `isize` to `i32` may truncate the value on targets with 64-bit wi
|
LL | 1isize as i32;
| ^^^^^^^^^^^^^
|
= help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
help: ... or use `try_from` and handle the error accordingly
|
LL | i32::try_from(1isize);
| ~~~~~~~~~~~~~~~~~~~~~
error: casting `isize` to `u32` may truncate the value on targets with 64-bit wide pointers
--> $DIR/cast_size.rs:20:5
|
LL | 1isize as u32;
| ^^^^^^^^^^^^^
|
= help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
help: ... or use `try_from` and handle the error accordingly
|
LL | u32::try_from(1isize);
| ~~~~~~~~~~~~~~~~~~~~~
error: casting `usize` to `u32` may truncate the value on targets with 64-bit wide pointers
--> $DIR/cast_size.rs:21:5
|
LL | 1usize as u32;
| ^^^^^^^^^^^^^
|
= help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
help: ... or use `try_from` and handle the error accordingly
|
LL | u32::try_from(1usize);
| ~~~~~~~~~~~~~~~~~~~~~
error: casting `usize` to `i32` may truncate the value on targets with 64-bit wide pointers
--> $DIR/cast_size.rs:22:5
|
LL | 1usize as i32;
| ^^^^^^^^^^^^^
|
= help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
help: ... or use `try_from` and handle the error accordingly
|
LL | i32::try_from(1usize);
| ~~~~~~~~~~~~~~~~~~~~~
error: casting `usize` to `i32` may wrap around the value on targets with 32-bit wide pointers
--> $DIR/cast_size.rs:22:5
@ -69,18 +98,36 @@ error: casting `i64` to `isize` may truncate the value on targets with 32-bit wi
|
LL | 1i64 as isize;
| ^^^^^^^^^^^^^
|
= help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
help: ... or use `try_from` and handle the error accordingly
|
LL | isize::try_from(1i64);
| ~~~~~~~~~~~~~~~~~~~~~
error: casting `i64` to `usize` may truncate the value on targets with 32-bit wide pointers
--> $DIR/cast_size.rs:25:5
|
LL | 1i64 as usize;
| ^^^^^^^^^^^^^
|
= help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
help: ... or use `try_from` and handle the error accordingly
|
LL | usize::try_from(1i64);
| ~~~~~~~~~~~~~~~~~~~~~
error: casting `u64` to `isize` may truncate the value on targets with 32-bit wide pointers
--> $DIR/cast_size.rs:26:5
|
LL | 1u64 as isize;
| ^^^^^^^^^^^^^
|
= help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
help: ... or use `try_from` and handle the error accordingly
|
LL | isize::try_from(1u64);
| ~~~~~~~~~~~~~~~~~~~~~
error: casting `u64` to `isize` may wrap around the value on targets with 64-bit wide pointers
--> $DIR/cast_size.rs:26:5
@ -93,6 +140,12 @@ error: casting `u64` to `usize` may truncate the value on targets with 32-bit wi
|
LL | 1u64 as usize;
| ^^^^^^^^^^^^^
|
= help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
help: ... or use `try_from` and handle the error accordingly
|
LL | usize::try_from(1u64);
| ~~~~~~~~~~~~~~~~~~~~~
error: casting `u32` to `isize` may wrap around the value on targets with 32-bit wide pointers
--> $DIR/cast_size.rs:28:5

View file

@ -1,34 +1,34 @@
error: item name starts with its containing module's name
--> $DIR/module_name_repetitions.rs:8:5
--> $DIR/module_name_repetitions.rs:8:12
|
LL | pub fn foo_bar() {}
| ^^^^^^^^^^^^^^^^^^^
| ^^^^^^^
|
= note: `-D clippy::module-name-repetitions` implied by `-D warnings`
error: item name ends with its containing module's name
--> $DIR/module_name_repetitions.rs:9:5
--> $DIR/module_name_repetitions.rs:9:12
|
LL | pub fn bar_foo() {}
| ^^^^^^^^^^^^^^^^^^^
| ^^^^^^^
error: item name starts with its containing module's name
--> $DIR/module_name_repetitions.rs:10:5
--> $DIR/module_name_repetitions.rs:10:16
|
LL | pub struct FooCake;
| ^^^^^^^^^^^^^^^^^^^
| ^^^^^^^
error: item name ends with its containing module's name
--> $DIR/module_name_repetitions.rs:11:5
--> $DIR/module_name_repetitions.rs:11:14
|
LL | pub enum CakeFoo {}
| ^^^^^^^^^^^^^^^^^^^
| ^^^^^^^
error: item name starts with its containing module's name
--> $DIR/module_name_repetitions.rs:12:5
--> $DIR/module_name_repetitions.rs:12:16
|
LL | pub struct Foo7Bar;
| ^^^^^^^^^^^^^^^^^^^
| ^^^^^^^
error: aborting due to 5 previous errors

View file

@ -0,0 +1,110 @@
#![allow(unused)]
#![allow(deref_nullptr)]
#![allow(clippy::unnecessary_operation)]
#![allow(clippy::drop_copy)]
#![warn(clippy::multiple_unsafe_ops_per_block)]
use core::arch::asm;
fn raw_ptr() -> *const () {
core::ptr::null()
}
unsafe fn not_very_safe() {}
struct Sample;
impl Sample {
unsafe fn not_very_safe(&self) {}
}
#[allow(non_upper_case_globals)]
const sample: Sample = Sample;
union U {
i: i32,
u: u32,
}
static mut STATIC: i32 = 0;
fn test1() {
unsafe {
STATIC += 1;
not_very_safe();
}
}
fn test2() {
let u = U { i: 0 };
unsafe {
drop(u.u);
*raw_ptr();
}
}
fn test3() {
unsafe {
asm!("nop");
sample.not_very_safe();
STATIC = 0;
}
}
fn test_all() {
let u = U { i: 0 };
unsafe {
drop(u.u);
drop(STATIC);
sample.not_very_safe();
not_very_safe();
*raw_ptr();
asm!("nop");
}
}
// no lint
fn correct1() {
unsafe {
STATIC += 1;
}
}
// no lint
fn correct2() {
unsafe {
STATIC += 1;
}
unsafe {
*raw_ptr();
}
}
// no lint
fn correct3() {
let u = U { u: 0 };
unsafe {
not_very_safe();
}
unsafe {
drop(u.i);
}
}
// tests from the issue (https://github.com/rust-lang/rust-clippy/issues/10064)
unsafe fn read_char_bad(ptr: *const u8) -> char {
unsafe { char::from_u32_unchecked(*ptr.cast::<u32>()) }
}
// no lint
unsafe fn read_char_good(ptr: *const u8) -> char {
let int_value = unsafe { *ptr.cast::<u32>() };
unsafe { core::char::from_u32_unchecked(int_value) }
}
fn main() {}

View file

@ -0,0 +1,129 @@
error: this `unsafe` block contains 2 unsafe operations, expected only one
--> $DIR/multiple_unsafe_ops_per_block.rs:32:5
|
LL | / unsafe {
LL | | STATIC += 1;
LL | | not_very_safe();
LL | | }
| |_____^
|
note: modification of a mutable static occurs here
--> $DIR/multiple_unsafe_ops_per_block.rs:33:9
|
LL | STATIC += 1;
| ^^^^^^^^^^^
note: unsafe function call occurs here
--> $DIR/multiple_unsafe_ops_per_block.rs:34:9
|
LL | not_very_safe();
| ^^^^^^^^^^^^^^^
= note: `-D clippy::multiple-unsafe-ops-per-block` implied by `-D warnings`
error: this `unsafe` block contains 2 unsafe operations, expected only one
--> $DIR/multiple_unsafe_ops_per_block.rs:41:5
|
LL | / unsafe {
LL | | drop(u.u);
LL | | *raw_ptr();
LL | | }
| |_____^
|
note: union field access occurs here
--> $DIR/multiple_unsafe_ops_per_block.rs:42:14
|
LL | drop(u.u);
| ^^^
note: raw pointer dereference occurs here
--> $DIR/multiple_unsafe_ops_per_block.rs:43:9
|
LL | *raw_ptr();
| ^^^^^^^^^^
error: this `unsafe` block contains 3 unsafe operations, expected only one
--> $DIR/multiple_unsafe_ops_per_block.rs:48:5
|
LL | / unsafe {
LL | | asm!("nop");
LL | | sample.not_very_safe();
LL | | STATIC = 0;
LL | | }
| |_____^
|
note: inline assembly used here
--> $DIR/multiple_unsafe_ops_per_block.rs:49:9
|
LL | asm!("nop");
| ^^^^^^^^^^^
note: unsafe method call occurs here
--> $DIR/multiple_unsafe_ops_per_block.rs:50:9
|
LL | sample.not_very_safe();
| ^^^^^^^^^^^^^^^^^^^^^^
note: modification of a mutable static occurs here
--> $DIR/multiple_unsafe_ops_per_block.rs:51:9
|
LL | STATIC = 0;
| ^^^^^^^^^^
error: this `unsafe` block contains 6 unsafe operations, expected only one
--> $DIR/multiple_unsafe_ops_per_block.rs:57:5
|
LL | / unsafe {
LL | | drop(u.u);
LL | | drop(STATIC);
LL | | sample.not_very_safe();
... |
LL | | asm!("nop");
LL | | }
| |_____^
|
note: union field access occurs here
--> $DIR/multiple_unsafe_ops_per_block.rs:58:14
|
LL | drop(u.u);
| ^^^
note: access of a mutable static occurs here
--> $DIR/multiple_unsafe_ops_per_block.rs:59:14
|
LL | drop(STATIC);
| ^^^^^^
note: unsafe method call occurs here
--> $DIR/multiple_unsafe_ops_per_block.rs:60:9
|
LL | sample.not_very_safe();
| ^^^^^^^^^^^^^^^^^^^^^^
note: unsafe function call occurs here
--> $DIR/multiple_unsafe_ops_per_block.rs:61:9
|
LL | not_very_safe();
| ^^^^^^^^^^^^^^^
note: raw pointer dereference occurs here
--> $DIR/multiple_unsafe_ops_per_block.rs:62:9
|
LL | *raw_ptr();
| ^^^^^^^^^^
note: inline assembly used here
--> $DIR/multiple_unsafe_ops_per_block.rs:63:9
|
LL | asm!("nop");
| ^^^^^^^^^^^
error: this `unsafe` block contains 2 unsafe operations, expected only one
--> $DIR/multiple_unsafe_ops_per_block.rs:101:5
|
LL | unsafe { char::from_u32_unchecked(*ptr.cast::<u32>()) }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: unsafe function call occurs here
--> $DIR/multiple_unsafe_ops_per_block.rs:101:14
|
LL | unsafe { char::from_u32_unchecked(*ptr.cast::<u32>()) }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: raw pointer dereference occurs here
--> $DIR/multiple_unsafe_ops_per_block.rs:101:39
|
LL | unsafe { char::from_u32_unchecked(*ptr.cast::<u32>()) }
| ^^^^^^^^^^^^^^^^^^
error: aborting due to 5 previous errors

View file

@ -31,6 +31,16 @@ fn test_no_semicolon() -> bool {
true
}
#[rustfmt::skip]
fn test_multiple_semicolon() -> bool {
true
}
#[rustfmt::skip]
fn test_multiple_semicolon_with_spaces() -> bool {
true
}
fn test_if_block() -> bool {
if true {
true

View file

@ -31,6 +31,16 @@ fn test_no_semicolon() -> bool {
return true;
}
#[rustfmt::skip]
fn test_multiple_semicolon() -> bool {
return true;;;
}
#[rustfmt::skip]
fn test_multiple_semicolon_with_spaces() -> bool {
return true;; ; ;
}
fn test_if_block() -> bool {
if true {
return true;

View file

@ -16,7 +16,23 @@ LL | return true;
= help: remove `return`
error: unneeded `return` statement
--> $DIR/needless_return.rs:36:9
--> $DIR/needless_return.rs:36:5
|
LL | return true;;;
| ^^^^^^^^^^^
|
= help: remove `return`
error: unneeded `return` statement
--> $DIR/needless_return.rs:41:5
|
LL | return true;; ; ;
| ^^^^^^^^^^^
|
= help: remove `return`
error: unneeded `return` statement
--> $DIR/needless_return.rs:46:9
|
LL | return true;
| ^^^^^^^^^^^
@ -24,7 +40,7 @@ LL | return true;
= help: remove `return`
error: unneeded `return` statement
--> $DIR/needless_return.rs:38:9
--> $DIR/needless_return.rs:48:9
|
LL | return false;
| ^^^^^^^^^^^^
@ -32,7 +48,7 @@ LL | return false;
= help: remove `return`
error: unneeded `return` statement
--> $DIR/needless_return.rs:44:17
--> $DIR/needless_return.rs:54:17
|
LL | true => return false,
| ^^^^^^^^^^^^
@ -40,7 +56,7 @@ LL | true => return false,
= help: remove `return`
error: unneeded `return` statement
--> $DIR/needless_return.rs:46:13
--> $DIR/needless_return.rs:56:13
|
LL | return true;
| ^^^^^^^^^^^
@ -48,7 +64,7 @@ LL | return true;
= help: remove `return`
error: unneeded `return` statement
--> $DIR/needless_return.rs:53:9
--> $DIR/needless_return.rs:63:9
|
LL | return true;
| ^^^^^^^^^^^
@ -56,7 +72,7 @@ LL | return true;
= help: remove `return`
error: unneeded `return` statement
--> $DIR/needless_return.rs:55:16
--> $DIR/needless_return.rs:65:16
|
LL | let _ = || return true;
| ^^^^^^^^^^^
@ -64,7 +80,7 @@ LL | let _ = || return true;
= help: remove `return`
error: unneeded `return` statement
--> $DIR/needless_return.rs:59:5
--> $DIR/needless_return.rs:69:5
|
LL | return the_answer!();
| ^^^^^^^^^^^^^^^^^^^^
@ -72,7 +88,7 @@ LL | return the_answer!();
= help: remove `return`
error: unneeded `return` statement
--> $DIR/needless_return.rs:62:21
--> $DIR/needless_return.rs:72:21
|
LL | fn test_void_fun() {
| _____________________^
@ -82,7 +98,7 @@ LL | | return;
= help: remove `return`
error: unneeded `return` statement
--> $DIR/needless_return.rs:67:11
--> $DIR/needless_return.rs:77:11
|
LL | if b {
| ___________^
@ -92,7 +108,7 @@ LL | | return;
= help: remove `return`
error: unneeded `return` statement
--> $DIR/needless_return.rs:69:13
--> $DIR/needless_return.rs:79:13
|
LL | } else {
| _____________^
@ -102,7 +118,7 @@ LL | | return;
= help: remove `return`
error: unneeded `return` statement
--> $DIR/needless_return.rs:77:14
--> $DIR/needless_return.rs:87:14
|
LL | _ => return,
| ^^^^^^
@ -110,7 +126,7 @@ LL | _ => return,
= help: replace `return` with a unit value
error: unneeded `return` statement
--> $DIR/needless_return.rs:85:24
--> $DIR/needless_return.rs:95:24
|
LL | let _ = 42;
| ________________________^
@ -120,7 +136,7 @@ LL | | return;
= help: remove `return`
error: unneeded `return` statement
--> $DIR/needless_return.rs:88:14
--> $DIR/needless_return.rs:98:14
|
LL | _ => return,
| ^^^^^^
@ -128,7 +144,7 @@ LL | _ => return,
= help: replace `return` with a unit value
error: unneeded `return` statement
--> $DIR/needless_return.rs:101:9
--> $DIR/needless_return.rs:111:9
|
LL | return String::from("test");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -136,7 +152,7 @@ LL | return String::from("test");
= help: remove `return`
error: unneeded `return` statement
--> $DIR/needless_return.rs:103:9
--> $DIR/needless_return.rs:113:9
|
LL | return String::new();
| ^^^^^^^^^^^^^^^^^^^^
@ -144,7 +160,7 @@ LL | return String::new();
= help: remove `return`
error: unneeded `return` statement
--> $DIR/needless_return.rs:125:32
--> $DIR/needless_return.rs:135:32
|
LL | bar.unwrap_or_else(|_| return)
| ^^^^^^
@ -152,7 +168,7 @@ LL | bar.unwrap_or_else(|_| return)
= help: replace `return` with an empty block
error: unneeded `return` statement
--> $DIR/needless_return.rs:129:21
--> $DIR/needless_return.rs:139:21
|
LL | let _ = || {
| _____________________^
@ -162,7 +178,7 @@ LL | | return;
= help: remove `return`
error: unneeded `return` statement
--> $DIR/needless_return.rs:132:20
--> $DIR/needless_return.rs:142:20
|
LL | let _ = || return;
| ^^^^^^
@ -170,7 +186,7 @@ LL | let _ = || return;
= help: replace `return` with an empty block
error: unneeded `return` statement
--> $DIR/needless_return.rs:138:32
--> $DIR/needless_return.rs:148:32
|
LL | res.unwrap_or_else(|_| return Foo)
| ^^^^^^^^^^
@ -178,7 +194,7 @@ LL | res.unwrap_or_else(|_| return Foo)
= help: remove `return`
error: unneeded `return` statement
--> $DIR/needless_return.rs:147:5
--> $DIR/needless_return.rs:157:5
|
LL | return true;
| ^^^^^^^^^^^
@ -186,7 +202,7 @@ LL | return true;
= help: remove `return`
error: unneeded `return` statement
--> $DIR/needless_return.rs:151:5
--> $DIR/needless_return.rs:161:5
|
LL | return true;
| ^^^^^^^^^^^
@ -194,7 +210,7 @@ LL | return true;
= help: remove `return`
error: unneeded `return` statement
--> $DIR/needless_return.rs:156:9
--> $DIR/needless_return.rs:166:9
|
LL | return true;
| ^^^^^^^^^^^
@ -202,7 +218,7 @@ LL | return true;
= help: remove `return`
error: unneeded `return` statement
--> $DIR/needless_return.rs:158:9
--> $DIR/needless_return.rs:168:9
|
LL | return false;
| ^^^^^^^^^^^^
@ -210,7 +226,7 @@ LL | return false;
= help: remove `return`
error: unneeded `return` statement
--> $DIR/needless_return.rs:164:17
--> $DIR/needless_return.rs:174:17
|
LL | true => return false,
| ^^^^^^^^^^^^
@ -218,7 +234,7 @@ LL | true => return false,
= help: remove `return`
error: unneeded `return` statement
--> $DIR/needless_return.rs:166:13
--> $DIR/needless_return.rs:176:13
|
LL | return true;
| ^^^^^^^^^^^
@ -226,7 +242,7 @@ LL | return true;
= help: remove `return`
error: unneeded `return` statement
--> $DIR/needless_return.rs:173:9
--> $DIR/needless_return.rs:183:9
|
LL | return true;
| ^^^^^^^^^^^
@ -234,7 +250,7 @@ LL | return true;
= help: remove `return`
error: unneeded `return` statement
--> $DIR/needless_return.rs:175:16
--> $DIR/needless_return.rs:185:16
|
LL | let _ = || return true;
| ^^^^^^^^^^^
@ -242,7 +258,7 @@ LL | let _ = || return true;
= help: remove `return`
error: unneeded `return` statement
--> $DIR/needless_return.rs:179:5
--> $DIR/needless_return.rs:189:5
|
LL | return the_answer!();
| ^^^^^^^^^^^^^^^^^^^^
@ -250,7 +266,7 @@ LL | return the_answer!();
= help: remove `return`
error: unneeded `return` statement
--> $DIR/needless_return.rs:182:33
--> $DIR/needless_return.rs:192:33
|
LL | async fn async_test_void_fun() {
| _________________________________^
@ -260,7 +276,7 @@ LL | | return;
= help: remove `return`
error: unneeded `return` statement
--> $DIR/needless_return.rs:187:11
--> $DIR/needless_return.rs:197:11
|
LL | if b {
| ___________^
@ -270,7 +286,7 @@ LL | | return;
= help: remove `return`
error: unneeded `return` statement
--> $DIR/needless_return.rs:189:13
--> $DIR/needless_return.rs:199:13
|
LL | } else {
| _____________^
@ -280,7 +296,7 @@ LL | | return;
= help: remove `return`
error: unneeded `return` statement
--> $DIR/needless_return.rs:197:14
--> $DIR/needless_return.rs:207:14
|
LL | _ => return,
| ^^^^^^
@ -288,7 +304,7 @@ LL | _ => return,
= help: replace `return` with a unit value
error: unneeded `return` statement
--> $DIR/needless_return.rs:210:9
--> $DIR/needless_return.rs:220:9
|
LL | return String::from("test");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -296,7 +312,7 @@ LL | return String::from("test");
= help: remove `return`
error: unneeded `return` statement
--> $DIR/needless_return.rs:212:9
--> $DIR/needless_return.rs:222:9
|
LL | return String::new();
| ^^^^^^^^^^^^^^^^^^^^
@ -304,7 +320,7 @@ LL | return String::new();
= help: remove `return`
error: unneeded `return` statement
--> $DIR/needless_return.rs:228:5
--> $DIR/needless_return.rs:238:5
|
LL | return format!("Hello {}", "world!");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -312,7 +328,7 @@ LL | return format!("Hello {}", "world!");
= help: remove `return`
error: unneeded `return` statement
--> $DIR/needless_return.rs:239:9
--> $DIR/needless_return.rs:249:9
|
LL | return true;
| ^^^^^^^^^^^
@ -320,7 +336,7 @@ LL | return true;
= help: remove `return`
error: unneeded `return` statement
--> $DIR/needless_return.rs:241:9
--> $DIR/needless_return.rs:251:9
|
LL | return false;
| ^^^^^^^^^^^^
@ -328,7 +344,7 @@ LL | return false;
= help: remove `return`
error: unneeded `return` statement
--> $DIR/needless_return.rs:248:13
--> $DIR/needless_return.rs:258:13
|
LL | return 10;
| ^^^^^^^^^
@ -336,7 +352,7 @@ LL | return 10;
= help: remove `return`
error: unneeded `return` statement
--> $DIR/needless_return.rs:251:13
--> $DIR/needless_return.rs:261:13
|
LL | return 100;
| ^^^^^^^^^^
@ -344,7 +360,7 @@ LL | return 100;
= help: remove `return`
error: unneeded `return` statement
--> $DIR/needless_return.rs:259:9
--> $DIR/needless_return.rs:269:9
|
LL | return 0;
| ^^^^^^^^
@ -352,7 +368,7 @@ LL | return 0;
= help: remove `return`
error: unneeded `return` statement
--> $DIR/needless_return.rs:266:13
--> $DIR/needless_return.rs:276:13
|
LL | return *(x as *const isize);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -360,7 +376,7 @@ LL | return *(x as *const isize);
= help: remove `return`
error: unneeded `return` statement
--> $DIR/needless_return.rs:268:13
--> $DIR/needless_return.rs:278:13
|
LL | return !*(x as *const isize);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -368,7 +384,7 @@ LL | return !*(x as *const isize);
= help: remove `return`
error: unneeded `return` statement
--> $DIR/needless_return.rs:275:20
--> $DIR/needless_return.rs:285:20
|
LL | let _ = 42;
| ____________________^
@ -379,7 +395,7 @@ LL | | return;
= help: remove `return`
error: unneeded `return` statement
--> $DIR/needless_return.rs:282:20
--> $DIR/needless_return.rs:292:20
|
LL | let _ = 42; return;
| ^^^^^^^
@ -387,7 +403,7 @@ LL | let _ = 42; return;
= help: remove `return`
error: unneeded `return` statement
--> $DIR/needless_return.rs:294:9
--> $DIR/needless_return.rs:304:9
|
LL | return Ok(format!("ok!"));
| ^^^^^^^^^^^^^^^^^^^^^^^^^
@ -395,12 +411,12 @@ LL | return Ok(format!("ok!"));
= help: remove `return`
error: unneeded `return` statement
--> $DIR/needless_return.rs:296:9
--> $DIR/needless_return.rs:306:9
|
LL | return Err(format!("err!"));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: remove `return`
error: aborting due to 48 previous errors
error: aborting due to 50 previous errors

View file

@ -51,6 +51,8 @@ fn main() {
// e is a function pointer type and U is an integer; fptr-addr-cast
let _usize_from_fn_ptr_transmute = unsafe { foo as usize };
let _usize_from_fn_ptr = foo as *const usize;
let _usize_from_ref = unsafe { &1u32 as *const u32 as usize };
}
// If a ref-to-ptr cast of this form where the pointer type points to a type other

View file

@ -51,6 +51,8 @@ fn main() {
// e is a function pointer type and U is an integer; fptr-addr-cast
let _usize_from_fn_ptr_transmute = unsafe { transmute::<fn(usize) -> u8, usize>(foo) };
let _usize_from_fn_ptr = foo as *const usize;
let _usize_from_ref = unsafe { transmute::<*const u32, usize>(&1u32) };
}
// If a ref-to-ptr cast of this form where the pointer type points to a type other

View file

@ -46,11 +46,17 @@ error: transmute from `fn(usize) -> u8` to `usize` which could be expressed as a
LL | let _usize_from_fn_ptr_transmute = unsafe { transmute::<fn(usize) -> u8, usize>(foo) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `foo as usize`
error: transmute from `*const u32` to `usize` which could be expressed as a pointer cast instead
--> $DIR/transmutes_expressible_as_ptr_casts.rs:55:36
|
LL | let _usize_from_ref = unsafe { transmute::<*const u32, usize>(&1u32) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&1u32 as *const u32 as usize`
error: transmute from a reference to a pointer
--> $DIR/transmutes_expressible_as_ptr_casts.rs:64:14
--> $DIR/transmutes_expressible_as_ptr_casts.rs:66:14
|
LL | unsafe { transmute::<&[i32; 1], *const u8>(in_param) }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `in_param as *const [i32; 1] as *const u8`
error: aborting due to 8 previous errors
error: aborting due to 9 previous errors

View file

@ -48,4 +48,21 @@ fn unnecessary_on_stmt_and_expr() -> u32 {
24
}
mod issue_10084 {
unsafe fn bar() -> i32 {
42
}
macro_rules! foo {
() => {
// SAFETY: This is necessary
unsafe { bar() }
};
}
fn main() {
foo!();
}
}
fn main() {}